@atlaskit/editor-plugin-table 7.18.1 → 7.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/cjs/commands/index.js +6 -0
- package/dist/cjs/commands/misc.js +15 -1
- package/dist/cjs/plugin.js +7 -4
- package/dist/cjs/pm-plugins/keymap.js +3 -0
- package/dist/cjs/reducer.js +1 -0
- package/dist/cjs/ui/FloatingContextualButton/index.js +18 -2
- package/dist/cjs/ui/FloatingContextualMenu/ContextualMenu.js +170 -35
- package/dist/cjs/ui/FloatingContextualMenu/index.js +4 -2
- package/dist/es2019/commands/index.js +1 -1
- package/dist/es2019/commands/misc.js +9 -1
- package/dist/es2019/plugin.js +7 -4
- package/dist/es2019/pm-plugins/keymap.js +5 -2
- package/dist/es2019/reducer.js +1 -0
- package/dist/es2019/ui/FloatingContextualButton/index.js +17 -2
- package/dist/es2019/ui/FloatingContextualMenu/ContextualMenu.js +159 -24
- package/dist/es2019/ui/FloatingContextualMenu/index.js +4 -2
- package/dist/esm/commands/index.js +1 -1
- package/dist/esm/commands/misc.js +14 -0
- package/dist/esm/plugin.js +7 -4
- package/dist/esm/pm-plugins/keymap.js +5 -2
- package/dist/esm/reducer.js +1 -0
- package/dist/esm/ui/FloatingContextualButton/index.js +15 -2
- package/dist/esm/ui/FloatingContextualMenu/ContextualMenu.js +171 -40
- package/dist/esm/ui/FloatingContextualMenu/index.js +4 -2
- package/dist/types/commands/index.d.ts +1 -1
- package/dist/types/commands/misc.d.ts +1 -0
- package/dist/types/types.d.ts +6 -0
- package/dist/types/ui/FloatingContextualButton/index.d.ts +1 -0
- package/dist/types/ui/FloatingContextualMenu/ContextualMenu.d.ts +7 -3
- package/dist/types/ui/FloatingContextualMenu/index.d.ts +2 -1
- package/dist/types-ts4.5/commands/index.d.ts +1 -1
- package/dist/types-ts4.5/commands/misc.d.ts +1 -0
- package/dist/types-ts4.5/types.d.ts +6 -0
- package/dist/types-ts4.5/ui/FloatingContextualButton/index.d.ts +1 -0
- package/dist/types-ts4.5/ui/FloatingContextualMenu/ContextualMenu.d.ts +7 -3
- package/dist/types-ts4.5/ui/FloatingContextualMenu/index.d.ts +2 -1
- package/package.json +6 -3
- package/src/commands/index.ts +1 -0
- package/src/commands/misc.ts +13 -0
- package/src/plugin.tsx +6 -1
- package/src/pm-plugins/keymap.ts +6 -1
- package/src/reducer.ts +1 -0
- package/src/types.ts +27 -20
- package/src/ui/FloatingContextualButton/index.tsx +19 -1
- package/src/ui/FloatingContextualMenu/ContextualMenu.tsx +209 -30
- package/src/ui/FloatingContextualMenu/index.tsx +3 -0
package/src/plugin.tsx
CHANGED
|
@@ -514,6 +514,7 @@ const tablesPlugin: TablePlugin = ({ config: options, api }) => {
|
|
|
514
514
|
isHeaderRowEnabled,
|
|
515
515
|
isDragAndDropEnabled,
|
|
516
516
|
tableWrapperTarget,
|
|
517
|
+
isCellMenuOpenByKeyboard,
|
|
517
518
|
} = tablePluginState!;
|
|
518
519
|
|
|
519
520
|
const { allowControls } = pluginConfig;
|
|
@@ -525,7 +526,9 @@ const tablesPlugin: TablePlugin = ({ config: options, api }) => {
|
|
|
525
526
|
return (
|
|
526
527
|
<>
|
|
527
528
|
{targetCellPosition &&
|
|
528
|
-
tableRef
|
|
529
|
+
(tableRef ||
|
|
530
|
+
(getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') &&
|
|
531
|
+
isCellMenuOpenByKeyboard)) &&
|
|
529
532
|
!isResizing &&
|
|
530
533
|
options &&
|
|
531
534
|
options.allowContextualMenu && (
|
|
@@ -540,6 +543,7 @@ const tablesPlugin: TablePlugin = ({ config: options, api }) => {
|
|
|
540
543
|
isContextualMenuOpen={isContextualMenuOpen}
|
|
541
544
|
stickyHeader={stickyHeader}
|
|
542
545
|
tableWrapper={tableWrapperTarget}
|
|
546
|
+
isCellMenuOpenByKeyboard={isCellMenuOpenByKeyboard}
|
|
543
547
|
/>
|
|
544
548
|
)}
|
|
545
549
|
{allowControls && (
|
|
@@ -578,6 +582,7 @@ const tablesPlugin: TablePlugin = ({ config: options, api }) => {
|
|
|
578
582
|
getEditorFeatureFlags={
|
|
579
583
|
options?.getEditorFeatureFlags || defaultGetEditorFeatureFlags
|
|
580
584
|
}
|
|
585
|
+
isCellMenuOpenByKeyboard={isCellMenuOpenByKeyboard}
|
|
581
586
|
/>
|
|
582
587
|
)}
|
|
583
588
|
{isDragAndDropEnabled && (
|
package/src/pm-plugins/keymap.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
deleteColumn,
|
|
18
18
|
deleteRow,
|
|
19
19
|
escape,
|
|
20
|
+
focusToContextMenuTrigger,
|
|
20
21
|
increaseMediaSize,
|
|
21
22
|
moveColumnLeft,
|
|
22
23
|
moveColumnRight,
|
|
@@ -35,7 +36,7 @@ import { chainCommands } from '@atlaskit/editor-prosemirror/commands';
|
|
|
35
36
|
import { keymap } from '@atlaskit/editor-prosemirror/keymap';
|
|
36
37
|
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
37
38
|
|
|
38
|
-
import { goToNextCell, moveCursorBackward } from '../commands';
|
|
39
|
+
import { goToNextCell, moveCursorBackward, setFocusToCellMenu } from '../commands';
|
|
39
40
|
import {
|
|
40
41
|
addRowAroundSelection,
|
|
41
42
|
changeColumnWidthByStepWithAnalytics,
|
|
@@ -298,6 +299,10 @@ export function keymapPlugin(
|
|
|
298
299
|
);
|
|
299
300
|
}
|
|
300
301
|
|
|
302
|
+
if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
|
|
303
|
+
bindKeymapWithCommand(focusToContextMenuTrigger.common!, setFocusToCellMenu(), list);
|
|
304
|
+
}
|
|
305
|
+
|
|
301
306
|
return keymap(list) as SafePlugin;
|
|
302
307
|
}
|
|
303
308
|
|
package/src/reducer.ts
CHANGED
|
@@ -135,6 +135,7 @@ export default (pluginState: TablePluginState, action: TablePluginAction): Table
|
|
|
135
135
|
case 'HOVER_CELL':
|
|
136
136
|
case 'SHOW_RESIZE_HANDLE_LINE':
|
|
137
137
|
case 'SET_EDITOR_FOCUS':
|
|
138
|
+
case 'SET_CELL_MENU_OPEN':
|
|
138
139
|
return { ...pluginState, ...action.data };
|
|
139
140
|
|
|
140
141
|
default:
|
package/src/types.ts
CHANGED
|
@@ -178,6 +178,7 @@ export interface TablePluginState {
|
|
|
178
178
|
// use options.isTableScalingEnabled and avoid using pluginState.isTableScalingEnabled or
|
|
179
179
|
// const { isTableScalingEnabled } = getPluginState(state) for that purpose.
|
|
180
180
|
isTableScalingEnabled?: boolean;
|
|
181
|
+
isCellMenuOpenByKeyboard?: boolean;
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
export type TablePluginAction =
|
|
@@ -194,7 +195,7 @@ export type TablePluginAction =
|
|
|
194
195
|
isHeaderRowEnabled: boolean;
|
|
195
196
|
isHeaderColumnEnabled: boolean;
|
|
196
197
|
};
|
|
197
|
-
|
|
198
|
+
}
|
|
198
199
|
| {
|
|
199
200
|
type: 'HOVER_ROWS';
|
|
200
201
|
data: {
|
|
@@ -202,13 +203,13 @@ export type TablePluginAction =
|
|
|
202
203
|
hoveredRows: number[];
|
|
203
204
|
isInDanger?: boolean;
|
|
204
205
|
};
|
|
205
|
-
|
|
206
|
+
}
|
|
206
207
|
| {
|
|
207
208
|
type: 'HOVER_MERGED_CELLS';
|
|
208
209
|
data: {
|
|
209
210
|
decorationSet: DecorationSet;
|
|
210
211
|
};
|
|
211
|
-
|
|
212
|
+
}
|
|
212
213
|
| {
|
|
213
214
|
type: 'HOVER_COLUMNS';
|
|
214
215
|
data: {
|
|
@@ -216,7 +217,7 @@ export type TablePluginAction =
|
|
|
216
217
|
hoveredColumns: number[];
|
|
217
218
|
isInDanger?: boolean;
|
|
218
219
|
};
|
|
219
|
-
|
|
220
|
+
}
|
|
220
221
|
| {
|
|
221
222
|
type: 'HOVER_TABLE';
|
|
222
223
|
data: {
|
|
@@ -225,7 +226,7 @@ export type TablePluginAction =
|
|
|
225
226
|
hoveredColumns: number[];
|
|
226
227
|
isInDanger?: boolean;
|
|
227
228
|
};
|
|
228
|
-
|
|
229
|
+
}
|
|
229
230
|
| {
|
|
230
231
|
type: 'START_KEYBOARD_COLUMN_RESIZE';
|
|
231
232
|
data: {
|
|
@@ -235,7 +236,7 @@ export type TablePluginAction =
|
|
|
235
236
|
resizeHandleIncludeTooltip: boolean;
|
|
236
237
|
isKeyboardResize?: boolean;
|
|
237
238
|
};
|
|
238
|
-
|
|
239
|
+
}
|
|
239
240
|
| {
|
|
240
241
|
type: 'ADD_RESIZE_HANDLE_DECORATIONS';
|
|
241
242
|
data: {
|
|
@@ -245,7 +246,7 @@ export type TablePluginAction =
|
|
|
245
246
|
resizeHandleIncludeTooltip: boolean;
|
|
246
247
|
isKeyboardResize?: boolean;
|
|
247
248
|
};
|
|
248
|
-
|
|
249
|
+
}
|
|
249
250
|
| {
|
|
250
251
|
type: 'UPDATE_RESIZE_HANDLE_DECORATIONS';
|
|
251
252
|
data: {
|
|
@@ -254,21 +255,21 @@ export type TablePluginAction =
|
|
|
254
255
|
resizeHandleColumnIndex: number | undefined;
|
|
255
256
|
resizeHandleIncludeTooltip: boolean | undefined;
|
|
256
257
|
};
|
|
257
|
-
|
|
258
|
+
}
|
|
258
259
|
| {
|
|
259
260
|
type: 'UPDATE_TABLE_WIDTH_TO_WIDEST';
|
|
260
261
|
data: {
|
|
261
262
|
widthToWidest: WidthToWidest | undefined;
|
|
262
263
|
};
|
|
263
|
-
|
|
264
|
+
}
|
|
264
265
|
| {
|
|
265
266
|
type: 'REMOVE_RESIZE_HANDLE_DECORATIONS';
|
|
266
267
|
data: { decorationSet: DecorationSet };
|
|
267
|
-
|
|
268
|
+
}
|
|
268
269
|
| {
|
|
269
270
|
type: 'STOP_KEYBOARD_COLUMN_RESIZE';
|
|
270
271
|
data: { decorationSet: DecorationSet };
|
|
271
|
-
|
|
272
|
+
}
|
|
272
273
|
| { type: 'CLEAR_HOVER_SELECTION'; data: { decorationSet: DecorationSet } }
|
|
273
274
|
| { type: 'SHOW_RESIZE_HANDLE_LINE'; data: { decorationSet: DecorationSet } }
|
|
274
275
|
| { type: 'HIDE_RESIZE_HANDLE_LINE'; data: { decorationSet: DecorationSet } }
|
|
@@ -277,42 +278,48 @@ export type TablePluginAction =
|
|
|
277
278
|
data: {
|
|
278
279
|
hoveredCell: CellHoverMeta;
|
|
279
280
|
};
|
|
280
|
-
|
|
281
|
+
}
|
|
281
282
|
| {
|
|
282
283
|
type: 'TABLE_HOVERED';
|
|
283
284
|
data: {
|
|
284
285
|
isTableHovered: boolean;
|
|
285
286
|
};
|
|
286
|
-
|
|
287
|
+
}
|
|
287
288
|
| { type: 'SET_TARGET_CELL_POSITION'; data: { targetCellPosition?: number } }
|
|
288
289
|
| {
|
|
289
290
|
type: 'SELECT_COLUMN';
|
|
290
291
|
data: { targetCellPosition: number; decorationSet: DecorationSet };
|
|
291
|
-
|
|
292
|
+
}
|
|
292
293
|
| { type: 'SHOW_INSERT_ROW_BUTTON'; data: { insertRowButtonIndex: number } }
|
|
293
294
|
| {
|
|
294
295
|
type: 'SHOW_INSERT_COLUMN_BUTTON';
|
|
295
296
|
data: { insertColumnButtonIndex: number };
|
|
296
|
-
|
|
297
|
+
}
|
|
297
298
|
| {
|
|
298
299
|
type: 'HIDE_INSERT_COLUMN_OR_ROW_BUTTON';
|
|
299
|
-
|
|
300
|
-
| { type: 'TOGGLE_CONTEXTUAL_MENU' }
|
|
300
|
+
}
|
|
301
|
+
| { type: 'TOGGLE_CONTEXTUAL_MENU' }
|
|
302
|
+
| {
|
|
303
|
+
type: 'SET_CELL_MENU_OPEN';
|
|
304
|
+
data: {
|
|
305
|
+
isCellMenuOpenByKeyboard: boolean;
|
|
306
|
+
};
|
|
307
|
+
};
|
|
301
308
|
|
|
302
309
|
export type ColumnResizingPluginAction =
|
|
303
310
|
| {
|
|
304
311
|
type: 'SET_RESIZE_HANDLE_POSITION';
|
|
305
312
|
data: { resizeHandlePos: number | null };
|
|
306
|
-
|
|
313
|
+
}
|
|
307
314
|
| { type: 'STOP_RESIZING' }
|
|
308
315
|
| {
|
|
309
316
|
type: 'SET_DRAGGING';
|
|
310
317
|
data: { dragging: { startX: number; startWidth: number } | null };
|
|
311
|
-
|
|
318
|
+
}
|
|
312
319
|
| {
|
|
313
320
|
type: 'SET_LAST_CLICK';
|
|
314
321
|
data: { lastClick: { x: number; y: number; time: number } | null };
|
|
315
|
-
|
|
322
|
+
};
|
|
316
323
|
|
|
317
324
|
export enum TableDecorations {
|
|
318
325
|
/** Classic controls */
|
|
@@ -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';
|
|
@@ -17,6 +17,7 @@ import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
|
|
|
17
17
|
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
18
18
|
import { akEditorSmallZIndex } from '@atlaskit/editor-shared-styles';
|
|
19
19
|
import ExpandIcon from '@atlaskit/icon/glyph/chevron-down';
|
|
20
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
20
21
|
|
|
21
22
|
import { toggleContextualMenu } from '../../commands';
|
|
22
23
|
import type { RowStickyState } from '../../pm-plugins/sticky-headers';
|
|
@@ -37,6 +38,7 @@ export interface Props {
|
|
|
37
38
|
isNumberColumnEnabled?: boolean;
|
|
38
39
|
stickyHeader?: RowStickyState;
|
|
39
40
|
dispatchAnalyticsEvent?: DispatchAnalyticsEvent;
|
|
41
|
+
isCellMenuOpenByKeyboard?: boolean;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
const BUTTON_OFFSET = 3;
|
|
@@ -50,6 +52,7 @@ const FloatingContextualButtonInner = React.memo((props: Props & WrappedComponen
|
|
|
50
52
|
stickyHeader,
|
|
51
53
|
tableWrapper,
|
|
52
54
|
targetCellPosition,
|
|
55
|
+
isCellMenuOpenByKeyboard,
|
|
53
56
|
intl: { formatMessage },
|
|
54
57
|
} = props; // : Props & WrappedComponentProps
|
|
55
58
|
|
|
@@ -69,6 +72,16 @@ const FloatingContextualButtonInner = React.memo((props: Props & WrappedComponen
|
|
|
69
72
|
let targetCellRef: Node | undefined;
|
|
70
73
|
targetCellRef = findDomRefAtPos(targetCellPosition, domAtPos);
|
|
71
74
|
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
|
|
77
|
+
if (isCellMenuOpenByKeyboard && !isContextualMenuOpen) {
|
|
78
|
+
const { state, dispatch } = editorView;
|
|
79
|
+
// open the menu when the keyboard shortcut is pressed
|
|
80
|
+
toggleContextualMenu()(state, dispatch);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}, [isCellMenuOpenByKeyboard, isContextualMenuOpen, editorView]);
|
|
84
|
+
|
|
72
85
|
if (!targetCellRef || !(targetCellRef instanceof HTMLElement)) {
|
|
73
86
|
return null;
|
|
74
87
|
}
|
|
@@ -92,6 +105,11 @@ const FloatingContextualButtonInner = React.memo((props: Props & WrappedComponen
|
|
|
92
105
|
onClick={handleClick}
|
|
93
106
|
iconBefore={<ExpandIcon label="" />}
|
|
94
107
|
aria-label={labelCellOptions}
|
|
108
|
+
aria-expanded={
|
|
109
|
+
getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')
|
|
110
|
+
? isContextualMenuOpen
|
|
111
|
+
: undefined
|
|
112
|
+
}
|
|
95
113
|
/>
|
|
96
114
|
</div>
|
|
97
115
|
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @atlaskit/design-system/prefer-primitives */
|
|
2
2
|
/** @jsx jsx */
|
|
3
|
-
import { Component } from 'react';
|
|
3
|
+
import React, { Component } from 'react';
|
|
4
|
+
import type { PointerEvent } from 'react';
|
|
4
5
|
|
|
5
6
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
6
7
|
import { jsx } from '@emotion/react';
|
|
@@ -24,9 +25,14 @@ import {
|
|
|
24
25
|
backgroundPaletteTooltipMessages,
|
|
25
26
|
cellBackgroundColorPalette,
|
|
26
27
|
ColorPalette,
|
|
28
|
+
getSelectedRowAndColumnFromPalette,
|
|
27
29
|
} from '@atlaskit/editor-common/ui-color';
|
|
28
30
|
import type { MenuItem } from '@atlaskit/editor-common/ui-menu';
|
|
29
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
ArrowKeyNavigationProvider,
|
|
33
|
+
ArrowKeyNavigationType,
|
|
34
|
+
DropdownMenu,
|
|
35
|
+
} from '@atlaskit/editor-common/ui-menu';
|
|
30
36
|
import { closestElement } from '@atlaskit/editor-common/utils';
|
|
31
37
|
import { hexToEditorBackgroundPaletteColor } from '@atlaskit/editor-palette';
|
|
32
38
|
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
@@ -43,6 +49,7 @@ import {
|
|
|
43
49
|
hoverColumns,
|
|
44
50
|
hoverMergedCells,
|
|
45
51
|
hoverRows,
|
|
52
|
+
setFocusToCellMenu,
|
|
46
53
|
toggleContextualMenu,
|
|
47
54
|
} from '../../commands';
|
|
48
55
|
import {
|
|
@@ -58,6 +65,7 @@ import {
|
|
|
58
65
|
splitCellWithAnalytics,
|
|
59
66
|
} from '../../commands-with-analytics';
|
|
60
67
|
import { getPluginState } from '../../pm-plugins/plugin-factory';
|
|
68
|
+
import { pluginKey as tablePluginKey } from '../../pm-plugins/plugin-key';
|
|
61
69
|
import { getNewResizeStateFromSelectedColumns } from '../../pm-plugins/table-resizing/utils/resize-state';
|
|
62
70
|
import { canMergeCells } from '../../transforms';
|
|
63
71
|
import { TableCssClassName as ClassName } from '../../types';
|
|
@@ -66,7 +74,11 @@ import {
|
|
|
66
74
|
getSelectedColumnIndexes,
|
|
67
75
|
getSelectedRowIndexes,
|
|
68
76
|
} from '../../utils';
|
|
69
|
-
import {
|
|
77
|
+
import {
|
|
78
|
+
colorPalletteColumns,
|
|
79
|
+
contextualMenuDropdownWidth,
|
|
80
|
+
contextualMenuDropdownWidthDnD,
|
|
81
|
+
} from '../consts';
|
|
70
82
|
import { AddColRightIcon, AddRowBelowIcon, MergeCellsIcon, SplitCellIcon } from '../icons';
|
|
71
83
|
|
|
72
84
|
import { cellColourPreviewStyles, elementBeforeIconStyles } from './styles';
|
|
@@ -85,40 +97,78 @@ export interface Props {
|
|
|
85
97
|
editorAnalyticsAPI?: EditorAnalyticsAPI;
|
|
86
98
|
getEditorContainerWidth: GetEditorContainerWidth;
|
|
87
99
|
getEditorFeatureFlags?: GetEditorFeatureFlags;
|
|
100
|
+
isCellMenuOpenByKeyboard?: boolean;
|
|
88
101
|
}
|
|
89
102
|
|
|
90
103
|
export interface State {
|
|
91
104
|
isSubmenuOpen: boolean;
|
|
105
|
+
isOpenAllowed: boolean;
|
|
92
106
|
}
|
|
93
|
-
|
|
107
|
+
const arrowsList = new Set(['ArrowRight', 'ArrowLeft']);
|
|
94
108
|
export class ContextualMenu extends Component<Props & WrappedComponentProps, State> {
|
|
95
109
|
state: State = {
|
|
96
110
|
isSubmenuOpen: false,
|
|
111
|
+
isOpenAllowed: false,
|
|
97
112
|
};
|
|
98
113
|
|
|
99
114
|
static defaultProps = {
|
|
100
115
|
boundariesElement: typeof document !== 'undefined' ? document.body : undefined,
|
|
101
116
|
};
|
|
117
|
+
private dropdownMenuRef = React.createRef<HTMLDivElement>();
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
componentDidMount() {
|
|
121
|
+
if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
|
|
122
|
+
// ArrowKeyNavigationProvider in DropdownMenu expects that menu handle will stay focused
|
|
123
|
+
// until user pressed ArrowDown.
|
|
124
|
+
// Behavior above fails the A11Y requirement about first item in menu should be focused immediately.
|
|
125
|
+
// so here is triggering componentDidUpdate inside dropdown to set focus on first element
|
|
126
|
+
const { isCellMenuOpenByKeyboard } = this.props;
|
|
127
|
+
if (isCellMenuOpenByKeyboard) {
|
|
128
|
+
this.setState({
|
|
129
|
+
...this.state,
|
|
130
|
+
isOpenAllowed: isCellMenuOpenByKeyboard
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
102
135
|
|
|
103
136
|
render() {
|
|
104
|
-
const { isOpen, mountPoint, offset, boundariesElement, editorView } =
|
|
137
|
+
const { isOpen, mountPoint, offset, boundariesElement, editorView, isCellMenuOpenByKeyboard } =
|
|
138
|
+
this.props;
|
|
105
139
|
const { isDragAndDropEnabled } = getPluginState(editorView.state);
|
|
106
140
|
const items = isDragAndDropEnabled
|
|
107
141
|
? this.createNewContextMenuItems()
|
|
108
142
|
: this.createOriginalContextMenuItems();
|
|
143
|
+
let isOpenAllowed = false;
|
|
144
|
+
|
|
145
|
+
if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
|
|
146
|
+
isOpenAllowed = isCellMenuOpenByKeyboard ? this.state.isOpenAllowed : isOpen;
|
|
147
|
+
} else {
|
|
148
|
+
isOpenAllowed = isOpen;
|
|
149
|
+
}
|
|
109
150
|
|
|
110
151
|
return (
|
|
111
|
-
<div
|
|
152
|
+
<div
|
|
153
|
+
data-testid="table-cell-contextual-menu"
|
|
154
|
+
onMouseLeave={this.closeSubmenu}
|
|
155
|
+
ref={this.dropdownMenuRef}
|
|
156
|
+
>
|
|
112
157
|
<DropdownMenu
|
|
113
158
|
mountTo={mountPoint}
|
|
114
159
|
//This needs be removed when the a11y is completely handled
|
|
115
160
|
//Disabling key navigation now as it works only partially
|
|
116
161
|
arrowKeyNavigationProviderOptions={{
|
|
117
162
|
type: ArrowKeyNavigationType.MENU,
|
|
118
|
-
disableArrowKeyNavigation:
|
|
163
|
+
disableArrowKeyNavigation:
|
|
164
|
+
getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') &&
|
|
165
|
+
isCellMenuOpenByKeyboard &&
|
|
166
|
+
!this.state.isSubmenuOpen
|
|
167
|
+
? false
|
|
168
|
+
: true,
|
|
119
169
|
}}
|
|
120
170
|
items={items}
|
|
121
|
-
isOpen={
|
|
171
|
+
isOpen={isOpenAllowed}
|
|
122
172
|
onOpenChange={this.handleOpenChange}
|
|
123
173
|
onItemActivated={this.onMenuItemActivated}
|
|
124
174
|
onMouseEnter={this.handleItemMouseEnter}
|
|
@@ -127,9 +177,22 @@ export class ContextualMenu extends Component<Props & WrappedComponentProps, Sta
|
|
|
127
177
|
fitWidth={
|
|
128
178
|
isDragAndDropEnabled ? contextualMenuDropdownWidthDnD : contextualMenuDropdownWidth
|
|
129
179
|
}
|
|
180
|
+
shouldFocusFirstItem={
|
|
181
|
+
getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')
|
|
182
|
+
?
|
|
183
|
+
() => {
|
|
184
|
+
return Boolean(isCellMenuOpenByKeyboard);
|
|
185
|
+
}
|
|
186
|
+
: undefined
|
|
187
|
+
}
|
|
130
188
|
boundariesElement={boundariesElement}
|
|
131
189
|
offset={offset}
|
|
132
190
|
section={isDragAndDropEnabled ? { hasSeparator: true } : undefined}
|
|
191
|
+
isAllowEnterDefaultBehavior={
|
|
192
|
+
getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')
|
|
193
|
+
? this.state.isSubmenuOpen
|
|
194
|
+
: false
|
|
195
|
+
}
|
|
133
196
|
/>
|
|
134
197
|
</div>
|
|
135
198
|
);
|
|
@@ -157,6 +220,7 @@ export class ContextualMenu extends Component<Props & WrappedComponentProps, Sta
|
|
|
157
220
|
isOpen,
|
|
158
221
|
intl: { formatMessage },
|
|
159
222
|
editorView,
|
|
223
|
+
isCellMenuOpenByKeyboard,
|
|
160
224
|
} = this.props;
|
|
161
225
|
const { isSubmenuOpen } = this.state;
|
|
162
226
|
const { targetCellPosition, isDragAndDropEnabled } = getPluginState(editorView.state);
|
|
@@ -164,6 +228,18 @@ export class ContextualMenu extends Component<Props & WrappedComponentProps, Sta
|
|
|
164
228
|
if (allowBackgroundColor) {
|
|
165
229
|
const node = isOpen && targetCellPosition ? state.doc.nodeAt(targetCellPosition) : null;
|
|
166
230
|
const background = hexToEditorBackgroundPaletteColor(node?.attrs?.background || '#ffffff');
|
|
231
|
+
let selectedRowIndex;
|
|
232
|
+
let selectedColumnIndex;
|
|
233
|
+
|
|
234
|
+
if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
|
|
235
|
+
const selectedRowAndColumnFromPalette = getSelectedRowAndColumnFromPalette(
|
|
236
|
+
cellBackgroundColorPalette,
|
|
237
|
+
background!,
|
|
238
|
+
colorPalletteColumns,
|
|
239
|
+
);
|
|
240
|
+
selectedRowIndex = selectedRowAndColumnFromPalette.selectedRowIndex;
|
|
241
|
+
selectedColumnIndex = selectedRowAndColumnFromPalette.selectedColumnIndex;
|
|
242
|
+
}
|
|
167
243
|
return {
|
|
168
244
|
content: isDragAndDropEnabled
|
|
169
245
|
? formatMessage(messages.backgroundColor)
|
|
@@ -191,26 +267,64 @@ export class ContextualMenu extends Component<Props & WrappedComponentProps, Sta
|
|
|
191
267
|
: ClassName.CONTEXTUAL_MENU_ICON
|
|
192
268
|
}
|
|
193
269
|
/>
|
|
194
|
-
{
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
270
|
+
{getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')
|
|
271
|
+
? isSubmenuOpen && (
|
|
272
|
+
<div
|
|
273
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
274
|
+
className={ClassName.CONTEXTUAL_SUBMENU}
|
|
275
|
+
ref={this.handleSubMenuRef}
|
|
276
|
+
>
|
|
277
|
+
<ArrowKeyNavigationProvider
|
|
278
|
+
type={ArrowKeyNavigationType.COLOR}
|
|
279
|
+
selectedRowIndex={selectedRowIndex || 0}
|
|
280
|
+
selectedColumnIndex={selectedColumnIndex || 0}
|
|
281
|
+
handleClose={() => {
|
|
282
|
+
this.setState({ isSubmenuOpen: false });
|
|
283
|
+
if (this.dropdownMenuRef && this.dropdownMenuRef.current) {
|
|
284
|
+
const focusableItems = this.dropdownMenuRef.current.querySelectorAll(
|
|
285
|
+
'div[tabindex="-1"]:not([disabled])',
|
|
286
|
+
) as NodeListOf<HTMLElement>;
|
|
287
|
+
if (focusableItems && focusableItems.length) {
|
|
288
|
+
focusableItems[0].focus();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}}
|
|
292
|
+
isPopupPositioned={true}
|
|
293
|
+
isOpenedByKeyboard={isCellMenuOpenByKeyboard!}
|
|
294
|
+
>
|
|
295
|
+
<ColorPalette
|
|
296
|
+
cols={7}
|
|
297
|
+
onClick={this.setColor}
|
|
298
|
+
selectedColor={node?.attrs?.background || '#ffffff'}
|
|
299
|
+
paletteOptions={{
|
|
300
|
+
palette: cellBackgroundColorPalette,
|
|
301
|
+
paletteColorTooltipMessages: backgroundPaletteTooltipMessages,
|
|
302
|
+
hexToPaletteColor: hexToEditorBackgroundPaletteColor,
|
|
303
|
+
}}
|
|
304
|
+
/>
|
|
305
|
+
</ArrowKeyNavigationProvider>
|
|
306
|
+
</div>
|
|
307
|
+
)
|
|
308
|
+
: isSubmenuOpen && (
|
|
309
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
310
|
+
<div className={ClassName.CONTEXTUAL_SUBMENU} ref={this.handleSubMenuRef}>
|
|
311
|
+
<ColorPalette
|
|
312
|
+
cols={7}
|
|
313
|
+
onClick={this.setColor}
|
|
314
|
+
selectedColor={node?.attrs?.background || '#ffffff'}
|
|
315
|
+
paletteOptions={{
|
|
316
|
+
palette: cellBackgroundColorPalette,
|
|
317
|
+
paletteColorTooltipMessages: backgroundPaletteTooltipMessages,
|
|
318
|
+
hexToPaletteColor: hexToEditorBackgroundPaletteColor,
|
|
319
|
+
}}
|
|
320
|
+
/>
|
|
321
|
+
</div>
|
|
322
|
+
)}
|
|
212
323
|
</div>
|
|
213
324
|
),
|
|
325
|
+
'aria-expanded': getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')
|
|
326
|
+
? isSubmenuOpen
|
|
327
|
+
: undefined,
|
|
214
328
|
} as MenuItem;
|
|
215
329
|
}
|
|
216
330
|
};
|
|
@@ -526,6 +640,7 @@ export class ContextualMenu extends Component<Props & WrappedComponentProps, Sta
|
|
|
526
640
|
editorAnalyticsAPI,
|
|
527
641
|
getEditorContainerWidth,
|
|
528
642
|
getEditorFeatureFlags,
|
|
643
|
+
isCellMenuOpenByKeyboard,
|
|
529
644
|
} = this.props;
|
|
530
645
|
// TargetCellPosition could be outdated: https://product-fabric.atlassian.net/browse/ED-8129
|
|
531
646
|
const { state, dispatch } = editorView;
|
|
@@ -533,6 +648,24 @@ export class ContextualMenu extends Component<Props & WrappedComponentProps, Sta
|
|
|
533
648
|
|
|
534
649
|
const { tableDuplicateCellColouring = false, tableWithFixedColumnWidthsOption = false } =
|
|
535
650
|
getEditorFeatureFlags ? getEditorFeatureFlags() : {};
|
|
651
|
+
// context menu opened by keyboard and any item except 'background' activated
|
|
652
|
+
// or color has been chosen from color palette
|
|
653
|
+
if (
|
|
654
|
+
getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') &&
|
|
655
|
+
isCellMenuOpenByKeyboard &&
|
|
656
|
+
(item.value.name !== 'background' ||
|
|
657
|
+
(item.value.name === 'background' && this.state.isSubmenuOpen))
|
|
658
|
+
) {
|
|
659
|
+
const { tr } = state;
|
|
660
|
+
tr.setMeta(tablePluginKey, {
|
|
661
|
+
type: 'SET_CELL_MENU_OPEN',
|
|
662
|
+
data: {
|
|
663
|
+
isCellMenuOpenByKeyboard: false,
|
|
664
|
+
},
|
|
665
|
+
});
|
|
666
|
+
dispatch(tr);
|
|
667
|
+
editorView.dom.focus(); // otherwise cursor disappears from cell
|
|
668
|
+
}
|
|
536
669
|
|
|
537
670
|
const shouldUseIncreasedScalingPercent =
|
|
538
671
|
isTableScalingEnabled &&
|
|
@@ -630,6 +763,20 @@ export class ContextualMenu extends Component<Props & WrappedComponentProps, Sta
|
|
|
630
763
|
)(state, dispatch);
|
|
631
764
|
this.toggleOpen();
|
|
632
765
|
break;
|
|
766
|
+
case 'background': {
|
|
767
|
+
// This is called twice.
|
|
768
|
+
// 1st time when user chooses the background color item.
|
|
769
|
+
// 2nd when color has been chosen from color palette.
|
|
770
|
+
// here we are handling the 1st call relying on the isSubmenuOpen state value
|
|
771
|
+
if (
|
|
772
|
+
getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c') &&
|
|
773
|
+
isCellMenuOpenByKeyboard &&
|
|
774
|
+
!this.state.isSubmenuOpen
|
|
775
|
+
) {
|
|
776
|
+
this.setState({ isSubmenuOpen: true });
|
|
777
|
+
}
|
|
778
|
+
break;
|
|
779
|
+
}
|
|
633
780
|
}
|
|
634
781
|
};
|
|
635
782
|
|
|
@@ -646,12 +793,44 @@ export class ContextualMenu extends Component<Props & WrappedComponentProps, Sta
|
|
|
646
793
|
}
|
|
647
794
|
};
|
|
648
795
|
|
|
649
|
-
private handleOpenChange = (
|
|
796
|
+
private handleOpenChange = (payload?: {
|
|
797
|
+
event: PointerEvent | KeyboardEvent;
|
|
798
|
+
isOpen: boolean;
|
|
799
|
+
}) => {
|
|
650
800
|
const {
|
|
651
|
-
editorView: { state, dispatch },
|
|
801
|
+
editorView: { state, dispatch, dom },
|
|
802
|
+
isCellMenuOpenByKeyboard,
|
|
652
803
|
} = this.props;
|
|
653
|
-
|
|
654
|
-
|
|
804
|
+
|
|
805
|
+
if (getBooleanFF('platform.editor.a11y-table-context-menu_y4c9c')) {
|
|
806
|
+
if (payload) {
|
|
807
|
+
const { event } = payload;
|
|
808
|
+
if (event && event instanceof KeyboardEvent) {
|
|
809
|
+
if (!this.state.isSubmenuOpen) {
|
|
810
|
+
if (arrowsList.has(event.key)) {
|
|
811
|
+
// preventing default behavior for avoiding cursor jump to next/previous table column
|
|
812
|
+
// when left/right arrow pressed.
|
|
813
|
+
event.preventDefault();
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
toggleContextualMenu()(state, dispatch);
|
|
817
|
+
this.setState({ isSubmenuOpen: false });
|
|
818
|
+
setFocusToCellMenu(false)(state, dispatch);
|
|
819
|
+
dom.focus();
|
|
820
|
+
}
|
|
821
|
+
} else {
|
|
822
|
+
// mouse click outside
|
|
823
|
+
toggleContextualMenu()(state, dispatch);
|
|
824
|
+
this.setState({ isSubmenuOpen: false });
|
|
825
|
+
if (isCellMenuOpenByKeyboard) {
|
|
826
|
+
setFocusToCellMenu(false)(state, dispatch);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
} else {
|
|
831
|
+
toggleContextualMenu()(state, dispatch);
|
|
832
|
+
this.setState({ isSubmenuOpen: false });
|
|
833
|
+
}
|
|
655
834
|
};
|
|
656
835
|
|
|
657
836
|
private handleItemMouseEnter = ({ item }: { item: any }) => {
|
|
@@ -40,6 +40,7 @@ export interface Props {
|
|
|
40
40
|
scrollableElement?: HTMLElement;
|
|
41
41
|
pluginConfig?: PluginConfig;
|
|
42
42
|
editorAnalyticsAPI?: EditorAnalyticsAPI;
|
|
43
|
+
isCellMenuOpenByKeyboard?: boolean;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
const FloatingContextualMenu = ({
|
|
@@ -52,6 +53,7 @@ const FloatingContextualMenu = ({
|
|
|
52
53
|
editorAnalyticsAPI,
|
|
53
54
|
getEditorContainerWidth,
|
|
54
55
|
getEditorFeatureFlags,
|
|
56
|
+
isCellMenuOpenByKeyboard,
|
|
55
57
|
}: Props) => {
|
|
56
58
|
// TargetCellPosition could be outdated: https://product-fabric.atlassian.net/browse/ED-8129
|
|
57
59
|
const { targetCellPosition, isDragAndDropEnabled } = getPluginState(editorView.state);
|
|
@@ -108,6 +110,7 @@ const FloatingContextualMenu = ({
|
|
|
108
110
|
editorAnalyticsAPI={editorAnalyticsAPI}
|
|
109
111
|
getEditorContainerWidth={getEditorContainerWidth}
|
|
110
112
|
getEditorFeatureFlags={getEditorFeatureFlags}
|
|
113
|
+
isCellMenuOpenByKeyboard={isCellMenuOpenByKeyboard}
|
|
111
114
|
/>
|
|
112
115
|
</div>
|
|
113
116
|
</Popup>
|