@atlaskit/editor-plugin-table 7.3.0 → 7.3.2

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 (98) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/afm-cc/tsconfig.json +3 -0
  3. package/dist/cjs/commands/misc.js +4 -2
  4. package/dist/cjs/commands/selection.js +4 -2
  5. package/dist/cjs/pm-plugins/drag-and-drop/commands.js +3 -1
  6. package/dist/cjs/pm-plugins/drag-and-drop/plugin.js +33 -1
  7. package/dist/cjs/pm-plugins/drag-and-drop/reducer.js +2 -1
  8. package/dist/cjs/pm-plugins/table-selection-keymap.js +2 -2
  9. package/dist/cjs/ui/DragHandle/HandleIconComponent.js +1 -3
  10. package/dist/cjs/ui/DragHandle/index.js +24 -10
  11. package/dist/cjs/ui/FloatingDragMenu/DragMenu.js +75 -33
  12. package/dist/cjs/ui/FloatingDragMenu/DropdownMenu.js +123 -0
  13. package/dist/cjs/ui/FloatingDragMenu/index.js +2 -2
  14. package/dist/cjs/ui/TableFloatingColumnControls/ColumnControls/index.js +24 -35
  15. package/dist/cjs/ui/TableFloatingColumnControls/index.js +1 -2
  16. package/dist/cjs/ui/TableFloatingControls/CornerControls/DragCornerControls.js +4 -0
  17. package/dist/cjs/ui/TableFloatingControls/RowControls/DragControls.js +26 -33
  18. package/dist/cjs/ui/common-styles.js +1 -1
  19. package/dist/cjs/ui/consts.js +3 -2
  20. package/dist/es2019/commands/misc.js +4 -4
  21. package/dist/es2019/commands/selection.js +4 -4
  22. package/dist/es2019/pm-plugins/drag-and-drop/commands.js +3 -3
  23. package/dist/es2019/pm-plugins/drag-and-drop/plugin.js +34 -1
  24. package/dist/es2019/pm-plugins/drag-and-drop/reducer.js +2 -1
  25. package/dist/es2019/pm-plugins/table-selection-keymap.js +2 -2
  26. package/dist/es2019/ui/DragHandle/HandleIconComponent.js +1 -3
  27. package/dist/es2019/ui/DragHandle/index.js +27 -10
  28. package/dist/es2019/ui/FloatingDragMenu/DragMenu.js +72 -32
  29. package/dist/es2019/ui/FloatingDragMenu/DropdownMenu.js +109 -0
  30. package/dist/es2019/ui/FloatingDragMenu/index.js +2 -2
  31. package/dist/es2019/ui/TableFloatingColumnControls/ColumnControls/index.js +24 -35
  32. package/dist/es2019/ui/TableFloatingColumnControls/index.js +1 -2
  33. package/dist/es2019/ui/TableFloatingControls/CornerControls/DragCornerControls.js +4 -0
  34. package/dist/es2019/ui/TableFloatingControls/RowControls/DragControls.js +26 -33
  35. package/dist/es2019/ui/common-styles.js +11 -1
  36. package/dist/es2019/ui/consts.js +2 -1
  37. package/dist/esm/commands/misc.js +4 -2
  38. package/dist/esm/commands/selection.js +4 -2
  39. package/dist/esm/pm-plugins/drag-and-drop/commands.js +3 -2
  40. package/dist/esm/pm-plugins/drag-and-drop/plugin.js +33 -1
  41. package/dist/esm/pm-plugins/drag-and-drop/reducer.js +2 -1
  42. package/dist/esm/pm-plugins/table-selection-keymap.js +2 -2
  43. package/dist/esm/ui/DragHandle/HandleIconComponent.js +1 -3
  44. package/dist/esm/ui/DragHandle/index.js +23 -9
  45. package/dist/esm/ui/FloatingDragMenu/DragMenu.js +74 -35
  46. package/dist/esm/ui/FloatingDragMenu/DropdownMenu.js +116 -0
  47. package/dist/esm/ui/FloatingDragMenu/index.js +2 -2
  48. package/dist/esm/ui/TableFloatingColumnControls/ColumnControls/index.js +24 -35
  49. package/dist/esm/ui/TableFloatingColumnControls/index.js +1 -2
  50. package/dist/esm/ui/TableFloatingControls/CornerControls/DragCornerControls.js +4 -0
  51. package/dist/esm/ui/TableFloatingControls/RowControls/DragControls.js +26 -33
  52. package/dist/esm/ui/common-styles.js +1 -1
  53. package/dist/esm/ui/consts.js +2 -1
  54. package/dist/types/commands/misc.d.ts +2 -2
  55. package/dist/types/commands/selection.d.ts +2 -2
  56. package/dist/types/pm-plugins/drag-and-drop/actions.d.ts +1 -0
  57. package/dist/types/pm-plugins/drag-and-drop/commands.d.ts +2 -1
  58. package/dist/types/pm-plugins/drag-and-drop/types.d.ts +2 -0
  59. package/dist/types/ui/DragHandle/HandleIconComponent.d.ts +1 -2
  60. package/dist/types/ui/DragHandle/index.d.ts +3 -2
  61. package/dist/types/ui/FloatingDragMenu/DragMenu.d.ts +7 -8
  62. package/dist/types/ui/FloatingDragMenu/DropdownMenu.d.ts +30 -0
  63. package/dist/types/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +1 -2
  64. package/dist/types/ui/TableFloatingControls/RowControls/DragControls.d.ts +1 -1
  65. package/dist/types/ui/consts.d.ts +1 -0
  66. package/dist/types-ts4.5/commands/misc.d.ts +2 -2
  67. package/dist/types-ts4.5/commands/selection.d.ts +2 -2
  68. package/dist/types-ts4.5/pm-plugins/drag-and-drop/actions.d.ts +1 -0
  69. package/dist/types-ts4.5/pm-plugins/drag-and-drop/commands.d.ts +2 -1
  70. package/dist/types-ts4.5/pm-plugins/drag-and-drop/types.d.ts +2 -0
  71. package/dist/types-ts4.5/ui/DragHandle/HandleIconComponent.d.ts +1 -2
  72. package/dist/types-ts4.5/ui/DragHandle/index.d.ts +3 -2
  73. package/dist/types-ts4.5/ui/FloatingDragMenu/DragMenu.d.ts +7 -8
  74. package/dist/types-ts4.5/ui/FloatingDragMenu/DropdownMenu.d.ts +30 -0
  75. package/dist/types-ts4.5/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +1 -2
  76. package/dist/types-ts4.5/ui/TableFloatingControls/RowControls/DragControls.d.ts +1 -1
  77. package/dist/types-ts4.5/ui/consts.d.ts +1 -0
  78. package/package.json +3 -2
  79. package/src/commands/misc.ts +17 -4
  80. package/src/commands/selection.ts +12 -4
  81. package/src/pm-plugins/drag-and-drop/actions.ts +1 -0
  82. package/src/pm-plugins/drag-and-drop/commands.ts +3 -0
  83. package/src/pm-plugins/drag-and-drop/plugin.ts +47 -0
  84. package/src/pm-plugins/drag-and-drop/reducer.ts +1 -0
  85. package/src/pm-plugins/drag-and-drop/types.ts +3 -0
  86. package/src/pm-plugins/table-selection-keymap.ts +2 -2
  87. package/src/ui/DragHandle/HandleIconComponent.tsx +2 -9
  88. package/src/ui/DragHandle/index.tsx +39 -16
  89. package/src/ui/FloatingDragMenu/DragMenu.tsx +362 -310
  90. package/src/ui/FloatingDragMenu/DropdownMenu.tsx +150 -0
  91. package/src/ui/FloatingDragMenu/index.tsx +3 -3
  92. package/src/ui/TableFloatingColumnControls/ColumnControls/index.tsx +72 -91
  93. package/src/ui/TableFloatingColumnControls/index.tsx +1 -2
  94. package/src/ui/TableFloatingControls/CornerControls/DragCornerControls.tsx +5 -0
  95. package/src/ui/TableFloatingControls/RowControls/DragControls.tsx +89 -104
  96. package/src/ui/common-styles.ts +11 -1
  97. package/src/ui/consts.ts +1 -0
  98. package/tsconfig.app.json +3 -0
@@ -334,7 +334,7 @@ export const setMultipleCellAttrs = (attrs, targetCellPosition) => (state, dispa
334
334
  }
335
335
  return false;
336
336
  };
337
- export const selectColumn = (column, expand) => createCommand(state => {
337
+ export const selectColumn = (column, expand, triggeredByKeyboard = false) => createCommand(state => {
338
338
  const cells = getCellsInColumn(column)(state.tr.selection);
339
339
  if (!cells || !cells.length || typeof cells[0].pos !== 'number') {
340
340
  return false;
@@ -349,7 +349,7 @@ export const selectColumn = (column, expand) => createCommand(state => {
349
349
  decorationSet
350
350
  }
351
351
  };
352
- }, tr => selectColumnTransform(column, expand)(tr).setMeta('addToHistory', false));
352
+ }, tr => selectColumnTransform(column, expand)(tr).setMeta('addToHistory', false).setMeta('selectedColumnViaKeyboard', triggeredByKeyboard));
353
353
  export const selectColumns = columnIndexes => createCommand(state => {
354
354
  if (!columnIndexes) {
355
355
  return false;
@@ -375,7 +375,7 @@ export const selectColumns = columnIndexes => createCommand(state => {
375
375
  }, tr => {
376
376
  return selectColumnsTransform(columnIndexes)(tr).setMeta('addToHistory', false);
377
377
  });
378
- export const selectRow = (row, expand) => createCommand(state => {
378
+ export const selectRow = (row, expand, triggeredByKeyboard = false) => createCommand(state => {
379
379
  let targetCellPosition;
380
380
  const cells = getCellsInRow(row)(state.tr.selection);
381
381
  if (cells && cells.length) {
@@ -387,7 +387,7 @@ export const selectRow = (row, expand) => createCommand(state => {
387
387
  targetCellPosition
388
388
  }
389
389
  };
390
- }, tr => selectRowTransform(row, expand)(tr).setMeta('addToHistory', false));
390
+ }, tr => selectRowTransform(row, expand)(tr).setMeta('addToHistory', false).setMeta('selectedRowViaKeyboard', triggeredByKeyboard));
391
391
  export const selectRows = rowIndexes => createCommand(state => {
392
392
  if (rowIndexes.length === 0) {
393
393
  return false;
@@ -69,7 +69,7 @@ const arrowRightFromCellSelection = editorSelectionAPI => selection => (state, d
69
69
  }
70
70
  return false;
71
71
  };
72
- export const selectColumns = editorSelectionAPI => () => (state, dispatch) => {
72
+ export const selectColumns = editorSelectionAPI => (triggeredByKeyboard = false) => (state, dispatch) => {
73
73
  const {
74
74
  selection
75
75
  } = state;
@@ -83,11 +83,11 @@ export const selectColumns = editorSelectionAPI => () => (state, dispatch) => {
83
83
  })(state, dispatch);
84
84
  }
85
85
  if (table && rect) {
86
- return selectColumn(rect.left)(state, dispatch);
86
+ return selectColumn(rect.left, undefined, triggeredByKeyboard)(state, dispatch);
87
87
  }
88
88
  return false;
89
89
  };
90
- export const selectRows = editorSelectionAPI => () => (state, dispatch) => {
90
+ export const selectRows = editorSelectionAPI => (triggeredByKeyboard = false) => (state, dispatch) => {
91
91
  const {
92
92
  selection
93
93
  } = state;
@@ -101,7 +101,7 @@ export const selectRows = editorSelectionAPI => () => (state, dispatch) => {
101
101
  })(state, dispatch);
102
102
  }
103
103
  if (table && rect) {
104
- return selectRow(rect.top)(state, dispatch);
104
+ return selectRow(rect.top, undefined, triggeredByKeyboard)(state, dispatch);
105
105
  }
106
106
  return false;
107
107
  };
@@ -6,7 +6,6 @@ import { DragAndDropActionType } from './actions';
6
6
  import { DropTargetType } from './consts';
7
7
  import { createCommand, getPluginState } from './plugin-factory';
8
8
  import { pluginKey } from './plugin-key';
9
-
10
9
  // TODO: This command is a placeholder example. Please replace this if required.
11
10
  export const getDecorations = state => {
12
11
  var _pluginKey$getState;
@@ -68,7 +67,7 @@ export const moveSource = (sourceType, sourceIndexes, targetIndex, tr) => create
68
67
  selectAfterMove: true
69
68
  })(nextTr);
70
69
  });
71
- export const toggleDragMenu = (isDragMenuOpen, direction, index) => createCommand(state => {
70
+ export const toggleDragMenu = (isDragMenuOpen, direction, index, trigger = 'mouse') => createCommand(state => {
72
71
  let {
73
72
  isDragMenuOpen: previousOpenState,
74
73
  dragMenuDirection: previousDragMenuDirection,
@@ -95,7 +94,8 @@ export const toggleDragMenu = (isDragMenuOpen, direction, index) => createComman
95
94
  data: {
96
95
  isDragMenuOpen: updatedMenuOpenState,
97
96
  direction: direction !== null && direction !== void 0 ? direction : previousDragMenuDirection,
98
- index: index !== null && index !== void 0 ? index : previousDragMenuIndex
97
+ index: index !== null && index !== void 0 ? index : previousDragMenuIndex,
98
+ isKeyboardModeActive: updatedMenuOpenState && trigger === 'keyboard'
99
99
  }
100
100
  };
101
101
  }, tr => {
@@ -177,7 +177,8 @@ export const createPlugin = (dispatch, eventDispatcher, editorAnalyticsAPI) => {
177
177
  dropTargetIndex: 0,
178
178
  isDragMenuOpen: false,
179
179
  dragMenuIndex: 0,
180
- isDragging: false
180
+ isDragging: false,
181
+ isKeyboardModeActive: false
181
182
  })),
182
183
  key: pluginKey,
183
184
  appendTransaction: (transactions, oldState, newState) => {
@@ -191,6 +192,20 @@ export const createPlugin = (dispatch, eventDispatcher, editorAnalyticsAPI) => {
191
192
  isDragMenuOpen,
192
193
  dragMenuIndex
193
194
  } = getPluginState(newState);
195
+ transactions.forEach(transaction => {
196
+ if (transaction.getMeta('selectedRowViaKeyboard')) {
197
+ const button = document.querySelector('#drag-handle-button-row');
198
+ if (button) {
199
+ button.focus();
200
+ }
201
+ }
202
+ if (transaction.getMeta('selectedColumnViaKeyboard')) {
203
+ const button = document.querySelector('#drag-handle-button-column');
204
+ if (button) {
205
+ button.focus();
206
+ }
207
+ }
208
+ });
194
209
 
195
210
  // What's happening here? you asked... In a nutshell;
196
211
  // If the target cell position changes while the drag menu is open then we want to close the drag menu if it has been opened.
@@ -232,6 +247,24 @@ export const createPlugin = (dispatch, eventDispatcher, editorAnalyticsAPI) => {
232
247
  decorationSet
233
248
  } = getPluginState(state);
234
249
  return decorationSet;
250
+ },
251
+ handleKeyDown: (view, event) => {
252
+ var _ref;
253
+ const isDragHandleFocused = ['drag-handle-button-row', 'drag-handle-button-column'].includes((_ref = event.target || null) === null || _ref === void 0 ? void 0 : _ref.id);
254
+ const keysToTrap = ['Enter', ' '];
255
+ const keysToTrapWhen = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
256
+ const {
257
+ isDragMenuOpen
258
+ } = getPluginState(view.state);
259
+
260
+ // drag handle is focused, and user presses any key return them back to editing
261
+ if (isDragHandleFocused && !isDragMenuOpen && !keysToTrap.includes(event.key)) {
262
+ view.dom.focus();
263
+ return true;
264
+ }
265
+ if (isDragHandleFocused && keysToTrap.includes(event.key) || isDragMenuOpen && keysToTrapWhen.includes(event.key)) {
266
+ return true;
267
+ }
235
268
  }
236
269
  }
237
270
  });
@@ -23,7 +23,8 @@ export default ((pluginState, action) => {
23
23
  ...pluginState,
24
24
  isDragMenuOpen: action.data.isDragMenuOpen,
25
25
  dragMenuDirection: action.data.direction,
26
- dragMenuIndex: action.data.index
26
+ dragMenuIndex: action.data.index,
27
+ isKeyboardModeActive: action.data.isKeyboardModeActive
27
28
  };
28
29
  default:
29
30
  return pluginState;
@@ -7,8 +7,8 @@ export function tableSelectionKeymapPlugin(editorSelectionAPI) {
7
7
  bindKeymapWithCommand(moveRight.common, arrowRightFromTable(editorSelectionAPI)(), list);
8
8
  bindKeymapWithCommand(moveLeft.common, arrowLeftFromTable(editorSelectionAPI)(), list);
9
9
  if (getBooleanFF('platform.editor.a11y.table-selection_9uv33')) {
10
- bindKeymapArrayWithCommand(selectColumn, selectColumns(editorSelectionAPI)(), list);
11
- bindKeymapArrayWithCommand(selectRow, selectRows(editorSelectionAPI)(), list);
10
+ bindKeymapArrayWithCommand(selectColumn, selectColumns(editorSelectionAPI)(true), list);
11
+ bindKeymapArrayWithCommand(selectRow, selectRows(editorSelectionAPI)(true), list);
12
12
  }
13
13
  if (getBooleanFF('platform.editor.table.shift-arrowup-fix')) {
14
14
  bindKeymapWithCommand(shiftArrowUp.common, shiftArrowUpFromTable(editorSelectionAPI)(), list);
@@ -3,11 +3,9 @@ import { DragHandleDisabledIcon, DragHandleIcon, MinimisedHandleIcon } from '../
3
3
  export const HandleIconComponent = props => {
4
4
  const {
5
5
  forceDefaultHandle,
6
- isRowHandleHovered,
7
- isColumnHandleHovered,
6
+ isHandleHovered,
8
7
  hasMergedCells
9
8
  } = props;
10
- const isHandleHovered = isRowHandleHovered || isColumnHandleHovered;
11
9
  if (isHandleHovered || forceDefaultHandle) {
12
10
  return hasMergedCells ? /*#__PURE__*/React.createElement(DragHandleDisabledIcon, null) : /*#__PURE__*/React.createElement(DragHandleIcon, null);
13
11
  }
@@ -6,6 +6,7 @@ import { tableMessages as messages } from '@atlaskit/editor-common/messages';
6
6
  import { browser } from '@atlaskit/editor-common/utils';
7
7
  import { draggable } from '@atlaskit/pragmatic-drag-and-drop/adapter/element';
8
8
  import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/util/set-custom-native-drag-preview';
9
+ import { getPluginState as getDnDPluginState } from '../../pm-plugins/drag-and-drop/plugin-factory';
9
10
  import { getPluginState } from '../../pm-plugins/plugin-factory';
10
11
  import { TableCssClassName as ClassName } from '../../types';
11
12
  import { hasMergedCellsInColumn, hasMergedCellsInRow } from '../../utils';
@@ -23,7 +24,7 @@ const DragHandleComponent = ({
23
24
  previewHeight,
24
25
  onMouseOver,
25
26
  onMouseOut,
26
- onMouseUp,
27
+ toggleDragMenu,
27
28
  onClick,
28
29
  editorView,
29
30
  intl: {
@@ -32,13 +33,19 @@ const DragHandleComponent = ({
32
33
  }) => {
33
34
  const dragHandleDivRef = useRef(null);
34
35
  const [previewContainer, setPreviewContainer] = useState(null);
36
+ const {
37
+ state,
38
+ state: {
39
+ selection
40
+ }
41
+ } = editorView;
35
42
  const {
36
43
  hoveredColumns,
37
44
  hoveredRows
38
- } = getPluginState(editorView.state);
45
+ } = getPluginState(state);
39
46
  const {
40
- selection
41
- } = editorView.state;
47
+ isDragMenuOpen
48
+ } = getDnDPluginState(state);
42
49
  const isRow = direction === 'row';
43
50
  const isColumn = direction === 'column';
44
51
  const isRowHandleHovered = isRow && hoveredRows.length > 0;
@@ -46,8 +53,7 @@ const DragHandleComponent = ({
46
53
  const hasMergedCells = useMemo(() => isRow ? hasMergedCellsInRow(indexes[0])(selection) : hasMergedCellsInColumn(indexes[0])(selection), [indexes, isRow, selection]);
47
54
  const handleIconProps = {
48
55
  forceDefaultHandle,
49
- isColumnHandleHovered,
50
- isRowHandleHovered,
56
+ isHandleHovered: isColumnHandleHovered || isRowHandleHovered,
51
57
  hasMergedCells
52
58
  };
53
59
  useEffect(() => {
@@ -108,6 +114,7 @@ const DragHandleComponent = ({
108
114
  }, [tableLocalId, direction, indexes, isRow, editorView.state.selection, hasMergedCells]);
109
115
  const showDragMenuAnchorId = isRow ? 'drag-handle-button-row' : 'drag-handle-button-column';
110
116
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("button", {
117
+ type: "button",
111
118
  className: ClassName.DRAG_HANDLE_BUTTON_CLICKABLE_ZONE,
112
119
  "data-testid": "table-drag-handle-clickable-zone-button",
113
120
  style: {
@@ -122,6 +129,7 @@ const DragHandleComponent = ({
122
129
  },
123
130
  onClick: onClick
124
131
  }), /*#__PURE__*/React.createElement("button", {
132
+ type: "button",
125
133
  id: isDragMenuTarget ? showDragMenuAnchorId : undefined,
126
134
  className: classnames(ClassName.DRAG_HANDLE_BUTTON_CONTAINER, appearance, {
127
135
  [ClassName.DRAG_HANDLE_DISABLED]: hasMergedCells
@@ -133,20 +141,29 @@ const DragHandleComponent = ({
133
141
  },
134
142
  "data-testid": "table-drag-handle-button",
135
143
  "aria-label": formatMessage(isRow ? messages.rowDragHandle : messages.columnDragHandle),
144
+ "aria-expanded": isDragMenuOpen && isDragMenuTarget ? 'true' : 'false',
145
+ "aria-haspopup": "menu",
136
146
  onMouseOver: onMouseOver,
137
147
  onMouseOut: onMouseOut,
138
148
  onMouseUp: e => {
139
149
  // return focus to editor so copying table selections whilst still works, i cannot call e.preventDefault in a mousemove event as this stops dragstart events from firing
140
150
  // -> this is bad for a11y but is the current standard new copy/paste keyboard shortcuts should be introduced instead
141
151
  editorView.focus();
142
- onMouseUp && onMouseUp(e);
152
+ toggleDragMenu && toggleDragMenu('mouse', e);
143
153
  },
144
- onClick: onClick
145
- }, browser.gecko ? /*#__PURE__*/React.createElement(HandleIconComponent, handleIconProps) : /*#__PURE__*/React.createElement("span", {
154
+ onClick: onClick,
155
+ onKeyDown: e => {
156
+ if (e.key === 'Enter' || e.key === ' ') {
157
+ toggleDragMenu && toggleDragMenu('keyboard');
158
+ }
159
+ }
160
+ }, appearance !== 'placeholder' ?
161
+ // cannot block pointer events in Firefox as it breaks Dragging functionality
162
+ browser.gecko ? /*#__PURE__*/React.createElement(HandleIconComponent, handleIconProps) : /*#__PURE__*/React.createElement("span", {
146
163
  style: {
147
164
  pointerEvents: 'none'
148
165
  }
149
- }, /*#__PURE__*/React.createElement(HandleIconComponent, handleIconProps))), previewContainer && previewWidth !== undefined && previewHeight !== undefined && /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(DragPreview, {
166
+ }, /*#__PURE__*/React.createElement(HandleIconComponent, handleIconProps)) : null), previewContainer && previewWidth !== undefined && previewHeight !== undefined && /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(DragPreview, {
150
167
  direction: direction,
151
168
  width: previewWidth,
152
169
  height: previewHeight
@@ -1,13 +1,15 @@
1
1
  /* eslint-disable @atlaskit/design-system/prefer-primitives */
2
2
  /** @jsx jsx */
3
- import { useState } from 'react';
3
+ /** @jsxFrag */
4
+ import React, { useEffect, useState } from 'react';
4
5
  import { jsx } from '@emotion/react';
5
6
  import { injectIntl } from 'react-intl-next';
6
7
  import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
7
8
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
8
9
  import { DropdownMenuSharedCssClassName } from '@atlaskit/editor-common/styles';
9
- import { backgroundPaletteTooltipMessages, cellBackgroundColorPalette, ColorPalette } from '@atlaskit/editor-common/ui-color';
10
- import { ArrowKeyNavigationType, DropdownMenu } from '@atlaskit/editor-common/ui-menu';
10
+ import { withOuterListeners } from '@atlaskit/editor-common/ui';
11
+ import { backgroundPaletteTooltipMessages, cellBackgroundColorPalette, ColorPalette, getSelectedRowAndColumnFromPalette } from '@atlaskit/editor-common/ui-color';
12
+ import { ArrowKeyNavigationProvider, ArrowKeyNavigationType } from '@atlaskit/editor-common/ui-menu';
11
13
  import { closestElement } from '@atlaskit/editor-common/utils';
12
14
  import { hexToEditorBackgroundPaletteColor } from '@atlaskit/editor-palette';
13
15
  import { shortcutStyle } from '@atlaskit/editor-shared-styles/shortcut';
@@ -24,7 +26,8 @@ import { getPluginState as getTablePluginState } from '../../pm-plugins/plugin-f
24
26
  import { TableCssClassName as ClassName } from '../../types';
25
27
  import { checkIfHeaderColumnEnabled, checkIfHeaderRowEnabled, checkIfNumberColumnEnabled, getMergedCellsPositions, getSelectedColumnIndexes, getSelectedRowIndexes, hasMergedCellsInColumn, hasMergedCellsInRow } from '../../utils';
26
28
  import { getDragMenuConfig } from '../../utils/drag-menu';
27
- import { dragMenuDropdownWidth } from '../consts';
29
+ import { colorPalletteColumns } from '../consts';
30
+ import { DropdownMenu } from './DropdownMenu';
28
31
  import { cellColourPreviewStyles, dragMenuBackgroundColorStyles, elementBeforeIconStyles, toggleStyles } from './styles';
29
32
  const MapDragMenuOptionIdToMessage = {
30
33
  add_row_above: {
@@ -153,15 +156,14 @@ const convertToDropdownItems = (dragMenuConfig, formatMessage, selectionRect) =>
153
156
  menuCallback
154
157
  };
155
158
  };
156
- export const DragMenu = ({
159
+ const ColorPaletteWithListeners = withOuterListeners(ColorPalette);
160
+ export const DragMenu = /*#__PURE__*/React.memo(({
157
161
  direction = 'row',
158
162
  index,
163
+ target,
159
164
  isOpen,
160
165
  editorView,
161
166
  tableNode,
162
- mountPoint,
163
- boundariesElement,
164
- scrollableElement,
165
167
  targetCellPosition,
166
168
  getEditorContainerWidth,
167
169
  editorAnalyticsAPI,
@@ -180,6 +182,9 @@ export const DragMenu = ({
180
182
  } = state;
181
183
  const tableMap = tableNode ? TableMap.get(tableNode) : undefined;
182
184
  const [isSubmenuOpen, setIsSubmenuOpen] = useState(false);
185
+ const {
186
+ isKeyboardModeActive
187
+ } = getPluginState(state);
183
188
  const selectionRect = isSelectionType(selection, 'cell') ? getSelectionRect(selection) : findCellRectClosestToPos(selection.$from);
184
189
  const hasMergedCells = direction === 'row' ? hasMergedCellsInRow : hasMergedCellsInColumn;
185
190
  const shouldMoveDisabled = index !== undefined && hasMergedCells(index)(selection);
@@ -220,7 +225,12 @@ export const DragMenu = ({
220
225
  } = getTablePluginState(editorView.state);
221
226
  const node = targetCellPosition ? state.doc.nodeAt(targetCellPosition) : null;
222
227
  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');
228
+ const {
229
+ selectedRowIndex,
230
+ selectedColumnIndex
231
+ } = getSelectedRowAndColumnFromPalette(cellBackgroundColorPalette, background, colorPalletteColumns);
223
232
  return {
233
+ key: 'background',
224
234
  content: formatMessage(messages.backgroundColor),
225
235
  value: {
226
236
  name: 'background'
@@ -240,16 +250,33 @@ export const DragMenu = ({
240
250
  }), isSubmenuOpen && jsx("div", {
241
251
  className: ClassName.DRAG_SUBMENU,
242
252
  ref: handleSubMenuRef
243
- }, jsx(ColorPalette, {
244
- cols: 7,
245
- onClick: setColor,
253
+ }, jsx(ArrowKeyNavigationProvider, {
254
+ type: ArrowKeyNavigationType.COLOR,
255
+ selectedRowIndex: selectedRowIndex,
256
+ selectedColumnIndex: selectedColumnIndex,
257
+ handleClose: () => {
258
+ const keyboardEvent = new KeyboardEvent('keydown', {
259
+ key: 'ArrowDown',
260
+ bubbles: true
261
+ });
262
+ setIsSubmenuOpen(false);
263
+ target === null || target === void 0 ? void 0 : target.focus();
264
+ target === null || target === void 0 ? void 0 : target.dispatchEvent(keyboardEvent);
265
+ },
266
+ isPopupPositioned: true,
267
+ isOpenedByKeyboard: isKeyboardModeActive
268
+ }, jsx(ColorPaletteWithListeners, {
269
+ cols: colorPalletteColumns,
270
+ onClick: color => {
271
+ setColor(color);
272
+ },
246
273
  selectedColor: background,
247
274
  paletteOptions: {
248
275
  palette: cellBackgroundColorPalette,
249
276
  paletteColorTooltipMessages: backgroundPaletteTooltipMessages,
250
277
  hexToPaletteColor: hexToEditorBackgroundPaletteColor
251
278
  }
252
- })))
279
+ }))))
253
280
  };
254
281
  };
255
282
  const toggleHeaderColumn = () => {
@@ -261,8 +288,9 @@ export const DragMenu = ({
261
288
  const toggleRowNumbers = () => {
262
289
  toggleNumberColumnWithAnalytics(editorAnalyticsAPI)(state, dispatch);
263
290
  };
264
- const createhHeaderRowColumnMenuItem = direction => {
291
+ const createHeaderRowColumnMenuItem = direction => {
265
292
  return direction === 'column' ? {
293
+ key: 'header_column',
266
294
  content: formatMessage(messages.headerColumn),
267
295
  value: {
268
296
  name: 'header_column'
@@ -275,6 +303,7 @@ export const DragMenu = ({
275
303
  isChecked: checkIfHeaderColumnEnabled(selection)
276
304
  }))
277
305
  } : {
306
+ key: 'header_row',
278
307
  content: formatMessage(messages.headerRow),
279
308
  value: {
280
309
  name: 'header_row'
@@ -290,6 +319,7 @@ export const DragMenu = ({
290
319
  };
291
320
  const createRowNumbersMenuItem = () => {
292
321
  return {
322
+ key: 'row_numbers',
293
323
  content: formatMessage(messages.rowNumbers),
294
324
  value: {
295
325
  name: 'row_numbers'
@@ -326,12 +356,17 @@ export const DragMenu = ({
326
356
  return true;
327
357
  }
328
358
  };
329
- const closeMenu = () => {
359
+ const closeMenu = (focusTarget = 'handle') => {
330
360
  const {
331
361
  state,
332
362
  dispatch
333
363
  } = editorView;
334
364
  if (shouldCloseMenu(state)) {
365
+ if (target && focusTarget === 'handle') {
366
+ target === null || target === void 0 ? void 0 : target.focus();
367
+ } else {
368
+ editorView.dom.focus();
369
+ }
335
370
  toggleDragMenu(false, direction, index)(state, dispatch);
336
371
  }
337
372
  };
@@ -341,6 +376,9 @@ export const DragMenu = ({
341
376
  var _menuCallback$item$va;
342
377
  (_menuCallback$item$va = menuCallback[item.value.name]) === null || _menuCallback$item$va === void 0 ? void 0 : _menuCallback$item$va.call(menuCallback, state, dispatch);
343
378
  switch (item.value.name) {
379
+ case 'background':
380
+ setIsSubmenuOpen(!isSubmenuOpen);
381
+ break;
344
382
  case 'header_column':
345
383
  toggleHeaderColumn();
346
384
  break;
@@ -354,7 +392,7 @@ export const DragMenu = ({
354
392
  break;
355
393
  }
356
394
  if (['header_column', 'header_row', 'row_numbers', 'background'].indexOf(item.value.name) <= -1) {
357
- closeMenu();
395
+ closeMenu('editor');
358
396
  }
359
397
  };
360
398
  const handleItemMouseEnter = ({
@@ -382,6 +420,17 @@ export const DragMenu = ({
382
420
  clearHoverSelection()(state, dispatch);
383
421
  }
384
422
  };
423
+ useEffect(() => {
424
+ // focus on first menu item automatically when menu renders
425
+ // and user is using keyboard
426
+ if (isOpen && target && isKeyboardModeActive) {
427
+ const keyboardEvent = new KeyboardEvent('keydown', {
428
+ key: 'ArrowDown',
429
+ bubbles: true
430
+ });
431
+ target.dispatchEvent(keyboardEvent);
432
+ }
433
+ }, [isOpen, target, isKeyboardModeActive]);
385
434
  if (!menuItems) {
386
435
  return null;
387
436
  }
@@ -389,11 +438,11 @@ export const DragMenu = ({
389
438
  menuItems[0].items.unshift(createBackgroundColorMenuItem());
390
439
  }
391
440
 
392
- // If first row, add toggle for Hearder row, default is true
441
+ // If first row, add toggle for Header row, default is true
393
442
  // If first column, add toggle for Header column, default is false
394
443
  if (getBooleanFF('platform.editor.table.new-cell-context-menu-styling') && index === 0) {
395
444
  menuItems.push({
396
- items: [createhHeaderRowColumnMenuItem(direction)]
445
+ items: [createHeaderRowColumnMenuItem(direction)]
397
446
  });
398
447
  }
399
448
 
@@ -404,25 +453,16 @@ export const DragMenu = ({
404
453
  });
405
454
  }
406
455
  return jsx(DropdownMenu, {
407
- mountTo: mountPoint
408
- //This needs be removed when the a11y is completely handled
409
- //Disabling key navigation now as it works only partially
410
- ,
411
- arrowKeyNavigationProviderOptions: {
412
- type: ArrowKeyNavigationType.MENU,
413
- disableArrowKeyNavigation: true
456
+ disableKeyboardHandling: isSubmenuOpen,
457
+ section: {
458
+ hasSeparator: true
414
459
  },
460
+ target: target,
415
461
  items: menuItems,
416
- isOpen: isOpen,
417
- onOpenChange: closeMenu,
418
462
  onItemActivated: handleMenuItemActivated,
419
463
  onMouseEnter: handleItemMouseEnter,
420
464
  onMouseLeave: handleItemMouseLeave,
421
- fitWidth: dragMenuDropdownWidth,
422
- boundariesElement: boundariesElement,
423
- section: {
424
- hasSeparator: true
425
- }
465
+ handleClose: closeMenu
426
466
  });
427
- };
467
+ });
428
468
  export default injectIntl(DragMenu);
@@ -0,0 +1,109 @@
1
+ import React from 'react';
2
+ import { DropList } from '@atlaskit/editor-common/ui';
3
+ import { ArrowKeyNavigationProvider, ArrowKeyNavigationType, DropdownMenuItem } from '@atlaskit/editor-common/ui-menu';
4
+ import { withReactEditorViewOuterListeners } from '@atlaskit/editor-common/ui-react';
5
+ import { MenuGroup, Section } from '@atlaskit/menu';
6
+ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
7
+ import { dragMenuDropdownWidth } from '../consts';
8
+ const DropListWithOutsideListeners = withReactEditorViewOuterListeners(DropList);
9
+ export const DropdownMenu = ({
10
+ target,
11
+ items,
12
+ section,
13
+ disableKeyboardHandling,
14
+ onItemActivated,
15
+ handleClose,
16
+ onMouseEnter,
17
+ onMouseLeave
18
+ }) => {
19
+ const innerMenu = () => {
20
+ return /*#__PURE__*/React.createElement(DropListWithOutsideListeners, {
21
+ isOpen: true,
22
+ shouldFitContainer: true,
23
+ position: ['bottom', 'left'].join(' '),
24
+ handleClickOutside: () => handleClose('editor'),
25
+ handleEscapeKeydown: () => {
26
+ if (!disableKeyboardHandling) {
27
+ handleClose('handle');
28
+ }
29
+ },
30
+ handleEnterKeydown: e => {
31
+ if (!disableKeyboardHandling) {
32
+ e.preventDefault();
33
+ e.stopPropagation();
34
+ }
35
+ },
36
+ targetRef: target
37
+ }, /*#__PURE__*/React.createElement("div", {
38
+ style: {
39
+ height: 0,
40
+ minWidth: dragMenuDropdownWidth
41
+ }
42
+ }), /*#__PURE__*/React.createElement(MenuGroup, {
43
+ role: "menu"
44
+ }, items.map((group, index) => /*#__PURE__*/React.createElement(Section, {
45
+ hasSeparator: (section === null || section === void 0 ? void 0 : section.hasSeparator) && index > 0,
46
+ title: section === null || section === void 0 ? void 0 : section.title,
47
+ key: index
48
+ }, group.items.map(item => {
49
+ var _item$key;
50
+ return /*#__PURE__*/React.createElement(DropdownMenuItem, {
51
+ shouldUseDefaultRole: false,
52
+ key: (_item$key = item.key) !== null && _item$key !== void 0 ? _item$key : String(item.content),
53
+ item: item,
54
+ onItemActivated: onItemActivated,
55
+ onMouseEnter: onMouseEnter,
56
+ onMouseLeave: onMouseLeave
57
+ });
58
+ })))));
59
+ };
60
+ if (disableKeyboardHandling) {
61
+ return innerMenu();
62
+ }
63
+ return /*#__PURE__*/React.createElement(ArrowKeyNavigationProvider, {
64
+ closeOnTab: true,
65
+ type: ArrowKeyNavigationType.MENU,
66
+ onSelection: index => {
67
+ const results = items.flatMap(item => 'items' in item ? item.items : item);
68
+
69
+ // onSelection is called when any focusable element is 'activated'
70
+ // this is an issue as some menu items have toggles, which cause the index value
71
+ // in the callback to be outside of array length.
72
+ // The logic below normalises the index value based on the number
73
+ // of menu items with 2 focusable elements, and adjusts the index to ensure
74
+ // the correct menu item is sent in onItemActivated callback
75
+ if (getBooleanFF('platform.editor.table.new-cell-context-menu-styling')) {
76
+ const keys = ['row_numbers', 'header_row', 'header_column'];
77
+ let doubleItemCount = 0;
78
+ const firstIndex = results.findIndex(value => keys.includes(value.key));
79
+ if (firstIndex === -1 || index <= firstIndex) {
80
+ onItemActivated && onItemActivated({
81
+ item: results[index]
82
+ });
83
+ return;
84
+ }
85
+ for (let i = firstIndex; i < results.length; i += 1) {
86
+ if (keys.includes(results[i].key)) {
87
+ doubleItemCount += 1;
88
+ }
89
+ if (firstIndex % 2 === 0 && index - doubleItemCount === i) {
90
+ onItemActivated && onItemActivated({
91
+ item: results[i]
92
+ });
93
+ return;
94
+ }
95
+ if (firstIndex % 2 === 1 && index - doubleItemCount === i) {
96
+ onItemActivated && onItemActivated({
97
+ item: results[i]
98
+ });
99
+ return;
100
+ }
101
+ }
102
+ } else {
103
+ onItemActivated && onItemActivated({
104
+ item: results[index]
105
+ });
106
+ }
107
+ }
108
+ }, innerMenu());
109
+ };
@@ -24,10 +24,10 @@ const FloatingDragMenu = ({
24
24
  }
25
25
  const inStickyMode = stickyHeaders === null || stickyHeaders === void 0 ? void 0 : stickyHeaders.sticky;
26
26
  const targetHandleRef = direction === 'row' ? document.querySelector('#drag-handle-button-row') : document.querySelector('#drag-handle-button-column');
27
+ const offset = direction === 'row' ? [-9, 6] : [0, -7];
27
28
  if (!targetHandleRef || !(editorView.state.selection instanceof CellSelection)) {
28
29
  return null;
29
30
  }
30
- const offset = direction === 'row' ? [-9, 6] : [0, -7];
31
31
 
32
32
  // TODO: we will need to adjust the alignment and offset values depending on whether this is a row or column menu.
33
33
  return /*#__PURE__*/React.createElement(Popup, {
@@ -49,10 +49,10 @@ const FloatingDragMenu = ({
49
49
  }, /*#__PURE__*/React.createElement(DragMenu, {
50
50
  editorView: editorView,
51
51
  isOpen: isOpen,
52
- boundariesElement: boundariesElement,
53
52
  tableNode: tableNode,
54
53
  direction: direction,
55
54
  index: index,
55
+ target: targetHandleRef || undefined,
56
56
  targetCellPosition: targetCellPosition,
57
57
  getEditorContainerWidth: getEditorContainerWidth,
58
58
  editorAnalyticsAPI: editorAnalyticsAPI,