@atlaskit/editor-plugin-table 7.2.3 → 7.3.1

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 (135) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/afm-cc/tsconfig.json +3 -0
  3. package/dist/cjs/commands/column-resize.js +115 -45
  4. package/dist/cjs/commands/go-to-next-cell.js +7 -11
  5. package/dist/cjs/commands/misc.js +7 -4
  6. package/dist/cjs/commands/selection.js +7 -5
  7. package/dist/cjs/event-handlers.js +38 -25
  8. package/dist/cjs/pm-plugins/drag-and-drop/commands.js +3 -1
  9. package/dist/cjs/pm-plugins/drag-and-drop/plugin.js +33 -1
  10. package/dist/cjs/pm-plugins/drag-and-drop/reducer.js +2 -1
  11. package/dist/cjs/pm-plugins/keymap.js +1 -0
  12. package/dist/cjs/pm-plugins/main.js +43 -9
  13. package/dist/cjs/pm-plugins/table-resizing/event-handlers.js +37 -7
  14. package/dist/cjs/pm-plugins/table-resizing/plugin.js +20 -6
  15. package/dist/cjs/pm-plugins/table-selection-keymap.js +2 -2
  16. package/dist/cjs/reducer.js +5 -2
  17. package/dist/cjs/ui/DragHandle/HandleIconComponent.js +1 -3
  18. package/dist/cjs/ui/DragHandle/index.js +22 -10
  19. package/dist/cjs/ui/FloatingDragMenu/DragMenu.js +75 -33
  20. package/dist/cjs/ui/FloatingDragMenu/DropdownMenu.js +123 -0
  21. package/dist/cjs/ui/FloatingDragMenu/index.js +2 -2
  22. package/dist/cjs/ui/TableFloatingColumnControls/ColumnControls/index.js +24 -35
  23. package/dist/cjs/ui/TableFloatingColumnControls/index.js +1 -2
  24. package/dist/cjs/ui/TableFloatingControls/CornerControls/DragCornerControls.js +4 -0
  25. package/dist/cjs/ui/TableFloatingControls/RowControls/DragControls.js +26 -33
  26. package/dist/cjs/ui/common-styles.js +1 -1
  27. package/dist/cjs/ui/consts.js +3 -2
  28. package/dist/es2019/commands/column-resize.js +100 -35
  29. package/dist/es2019/commands/go-to-next-cell.js +7 -9
  30. package/dist/es2019/commands/misc.js +7 -6
  31. package/dist/es2019/commands/selection.js +9 -9
  32. package/dist/es2019/event-handlers.js +17 -3
  33. package/dist/es2019/pm-plugins/drag-and-drop/commands.js +3 -3
  34. package/dist/es2019/pm-plugins/drag-and-drop/plugin.js +34 -1
  35. package/dist/es2019/pm-plugins/drag-and-drop/reducer.js +2 -1
  36. package/dist/es2019/pm-plugins/keymap.js +3 -2
  37. package/dist/es2019/pm-plugins/main.js +41 -5
  38. package/dist/es2019/pm-plugins/table-resizing/event-handlers.js +37 -4
  39. package/dist/es2019/pm-plugins/table-resizing/plugin.js +16 -1
  40. package/dist/es2019/pm-plugins/table-selection-keymap.js +2 -2
  41. package/dist/es2019/reducer.js +5 -2
  42. package/dist/es2019/ui/DragHandle/HandleIconComponent.js +1 -3
  43. package/dist/es2019/ui/DragHandle/index.js +25 -10
  44. package/dist/es2019/ui/FloatingDragMenu/DragMenu.js +72 -32
  45. package/dist/es2019/ui/FloatingDragMenu/DropdownMenu.js +109 -0
  46. package/dist/es2019/ui/FloatingDragMenu/index.js +2 -2
  47. package/dist/es2019/ui/TableFloatingColumnControls/ColumnControls/index.js +24 -35
  48. package/dist/es2019/ui/TableFloatingColumnControls/index.js +1 -2
  49. package/dist/es2019/ui/TableFloatingControls/CornerControls/DragCornerControls.js +4 -0
  50. package/dist/es2019/ui/TableFloatingControls/RowControls/DragControls.js +26 -33
  51. package/dist/es2019/ui/common-styles.js +11 -1
  52. package/dist/es2019/ui/consts.js +2 -1
  53. package/dist/esm/commands/column-resize.js +105 -35
  54. package/dist/esm/commands/go-to-next-cell.js +7 -11
  55. package/dist/esm/commands/misc.js +7 -4
  56. package/dist/esm/commands/selection.js +9 -7
  57. package/dist/esm/event-handlers.js +38 -25
  58. package/dist/esm/pm-plugins/drag-and-drop/commands.js +3 -2
  59. package/dist/esm/pm-plugins/drag-and-drop/plugin.js +33 -1
  60. package/dist/esm/pm-plugins/drag-and-drop/reducer.js +2 -1
  61. package/dist/esm/pm-plugins/keymap.js +3 -2
  62. package/dist/esm/pm-plugins/main.js +38 -4
  63. package/dist/esm/pm-plugins/table-resizing/event-handlers.js +34 -4
  64. package/dist/esm/pm-plugins/table-resizing/plugin.js +15 -1
  65. package/dist/esm/pm-plugins/table-selection-keymap.js +2 -2
  66. package/dist/esm/reducer.js +5 -2
  67. package/dist/esm/ui/DragHandle/HandleIconComponent.js +1 -3
  68. package/dist/esm/ui/DragHandle/index.js +21 -9
  69. package/dist/esm/ui/FloatingDragMenu/DragMenu.js +74 -35
  70. package/dist/esm/ui/FloatingDragMenu/DropdownMenu.js +116 -0
  71. package/dist/esm/ui/FloatingDragMenu/index.js +2 -2
  72. package/dist/esm/ui/TableFloatingColumnControls/ColumnControls/index.js +24 -35
  73. package/dist/esm/ui/TableFloatingColumnControls/index.js +1 -2
  74. package/dist/esm/ui/TableFloatingControls/CornerControls/DragCornerControls.js +4 -0
  75. package/dist/esm/ui/TableFloatingControls/RowControls/DragControls.js +26 -33
  76. package/dist/esm/ui/common-styles.js +1 -1
  77. package/dist/esm/ui/consts.js +2 -1
  78. package/dist/types/commands/column-resize.d.ts +2 -0
  79. package/dist/types/commands/misc.d.ts +3 -3
  80. package/dist/types/commands/selection.d.ts +2 -2
  81. package/dist/types/pm-plugins/drag-and-drop/actions.d.ts +1 -0
  82. package/dist/types/pm-plugins/drag-and-drop/commands.d.ts +2 -1
  83. package/dist/types/pm-plugins/drag-and-drop/types.d.ts +2 -0
  84. package/dist/types/types.d.ts +16 -0
  85. package/dist/types/ui/DragHandle/HandleIconComponent.d.ts +1 -2
  86. package/dist/types/ui/DragHandle/index.d.ts +3 -2
  87. package/dist/types/ui/FloatingDragMenu/DragMenu.d.ts +7 -8
  88. package/dist/types/ui/FloatingDragMenu/DropdownMenu.d.ts +30 -0
  89. package/dist/types/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +1 -2
  90. package/dist/types/ui/TableFloatingControls/RowControls/DragControls.d.ts +1 -1
  91. package/dist/types/ui/consts.d.ts +1 -0
  92. package/dist/types-ts4.5/commands/column-resize.d.ts +2 -0
  93. package/dist/types-ts4.5/commands/misc.d.ts +3 -3
  94. package/dist/types-ts4.5/commands/selection.d.ts +2 -2
  95. package/dist/types-ts4.5/pm-plugins/drag-and-drop/actions.d.ts +1 -0
  96. package/dist/types-ts4.5/pm-plugins/drag-and-drop/commands.d.ts +2 -1
  97. package/dist/types-ts4.5/pm-plugins/drag-and-drop/types.d.ts +2 -0
  98. package/dist/types-ts4.5/types.d.ts +16 -0
  99. package/dist/types-ts4.5/ui/DragHandle/HandleIconComponent.d.ts +1 -2
  100. package/dist/types-ts4.5/ui/DragHandle/index.d.ts +3 -2
  101. package/dist/types-ts4.5/ui/FloatingDragMenu/DragMenu.d.ts +7 -8
  102. package/dist/types-ts4.5/ui/FloatingDragMenu/DropdownMenu.d.ts +30 -0
  103. package/dist/types-ts4.5/ui/TableFloatingColumnControls/ColumnControls/index.d.ts +1 -2
  104. package/dist/types-ts4.5/ui/TableFloatingControls/RowControls/DragControls.d.ts +1 -1
  105. package/dist/types-ts4.5/ui/consts.d.ts +1 -0
  106. package/package.json +4 -3
  107. package/src/commands/column-resize.ts +155 -40
  108. package/src/commands/go-to-next-cell.ts +6 -15
  109. package/src/commands/misc.ts +19 -4
  110. package/src/commands/selection.ts +17 -9
  111. package/src/event-handlers.ts +21 -4
  112. package/src/pm-plugins/drag-and-drop/actions.ts +1 -0
  113. package/src/pm-plugins/drag-and-drop/commands.ts +3 -0
  114. package/src/pm-plugins/drag-and-drop/plugin.ts +47 -0
  115. package/src/pm-plugins/drag-and-drop/reducer.ts +1 -0
  116. package/src/pm-plugins/drag-and-drop/types.ts +3 -0
  117. package/src/pm-plugins/keymap.ts +3 -0
  118. package/src/pm-plugins/main.ts +47 -2
  119. package/src/pm-plugins/table-resizing/event-handlers.ts +33 -5
  120. package/src/pm-plugins/table-resizing/plugin.ts +18 -1
  121. package/src/pm-plugins/table-selection-keymap.ts +2 -2
  122. package/src/reducer.ts +5 -2
  123. package/src/types.ts +16 -0
  124. package/src/ui/DragHandle/HandleIconComponent.tsx +2 -9
  125. package/src/ui/DragHandle/index.tsx +37 -16
  126. package/src/ui/FloatingDragMenu/DragMenu.tsx +362 -310
  127. package/src/ui/FloatingDragMenu/DropdownMenu.tsx +150 -0
  128. package/src/ui/FloatingDragMenu/index.tsx +3 -3
  129. package/src/ui/TableFloatingColumnControls/ColumnControls/index.tsx +72 -91
  130. package/src/ui/TableFloatingColumnControls/index.tsx +1 -2
  131. package/src/ui/TableFloatingControls/CornerControls/DragCornerControls.tsx +5 -0
  132. package/src/ui/TableFloatingControls/RowControls/DragControls.tsx +89 -104
  133. package/src/ui/common-styles.ts +11 -1
  134. package/src/ui/consts.ts +1 -0
  135. package/tsconfig.app.json +3 -0
@@ -1,6 +1,7 @@
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
 
5
6
  import { jsx } from '@emotion/react';
6
7
  import type {
@@ -18,14 +19,16 @@ import type {
18
19
  Command,
19
20
  GetEditorContainerWidth,
20
21
  } from '@atlaskit/editor-common/types';
22
+ import { withOuterListeners } from '@atlaskit/editor-common/ui';
21
23
  import {
22
24
  backgroundPaletteTooltipMessages,
23
25
  cellBackgroundColorPalette,
24
26
  ColorPalette,
27
+ getSelectedRowAndColumnFromPalette,
25
28
  } from '@atlaskit/editor-common/ui-color';
26
29
  import {
30
+ ArrowKeyNavigationProvider,
27
31
  ArrowKeyNavigationType,
28
- DropdownMenu,
29
32
  } from '@atlaskit/editor-common/ui-menu';
30
33
  import type { MenuItem } from '@atlaskit/editor-common/ui-menu';
31
34
  import { closestElement } from '@atlaskit/editor-common/utils';
@@ -72,8 +75,9 @@ import type {
72
75
  DragMenuOptionIdType,
73
76
  } from '../../utils/drag-menu';
74
77
  import { getDragMenuConfig } from '../../utils/drag-menu';
75
- import { dragMenuDropdownWidth } from '../consts';
78
+ import { colorPalletteColumns } from '../consts';
76
79
 
80
+ import { DropdownMenu } from './DropdownMenu';
77
81
  import {
78
82
  cellColourPreviewStyles,
79
83
  dragMenuBackgroundColorStyles,
@@ -84,14 +88,11 @@ import {
84
88
  type DragMenuProps = {
85
89
  direction?: TableDirection;
86
90
  index?: number;
87
- tableRef?: HTMLTableElement;
91
+ target?: Element;
88
92
  tableNode?: PmNode;
89
93
  editorView: EditorView;
90
94
  isOpen?: boolean;
91
95
  targetCellPosition?: number;
92
- mountPoint?: HTMLElement;
93
- boundariesElement?: HTMLElement;
94
- scrollableElement?: HTMLElement;
95
96
  pluginConfig?: PluginConfig;
96
97
  getEditorContainerWidth: GetEditorContainerWidth;
97
98
  editorAnalyticsAPI?: EditorAnalyticsAPI;
@@ -253,336 +254,387 @@ const convertToDropdownItems = (
253
254
  return { menuItems, menuCallback };
254
255
  };
255
256
 
256
- export const DragMenu = ({
257
- direction = 'row',
258
- index,
259
- isOpen,
260
- editorView,
261
- tableNode,
262
- mountPoint,
263
- boundariesElement,
264
- scrollableElement,
265
- targetCellPosition,
266
- getEditorContainerWidth,
267
- editorAnalyticsAPI,
268
- pluginConfig,
269
- intl: { formatMessage },
270
- }: DragMenuProps & WrappedComponentProps) => {
271
- const { state, dispatch } = editorView;
272
- const { selection } = state;
273
- const tableMap = tableNode ? TableMap.get(tableNode) : undefined;
274
- const [isSubmenuOpen, setIsSubmenuOpen] = useState(false);
275
-
276
- const selectionRect = isSelectionType(selection, 'cell')
277
- ? getSelectionRect(selection)!
278
- : findCellRectClosestToPos(selection.$from);
279
-
280
- const hasMergedCells =
281
- direction === 'row' ? hasMergedCellsInRow : hasMergedCellsInColumn;
282
-
283
- const shouldMoveDisabled =
284
- index !== undefined && hasMergedCells(index)(selection);
285
-
286
- const hasMergedCellsInTable = getMergedCellsPositions(state.tr).length > 0;
287
- const allowBackgroundColor = pluginConfig?.allowBackgroundColor ?? false;
288
-
289
- const dragMenuConfig = getDragMenuConfig(
290
- direction,
291
- getEditorContainerWidth,
292
- !shouldMoveDisabled,
293
- hasMergedCellsInTable,
294
- editorView,
295
- tableMap,
257
+ const ColorPaletteWithListeners = withOuterListeners(ColorPalette);
258
+
259
+ export const DragMenu = React.memo(
260
+ ({
261
+ direction = 'row',
296
262
  index,
263
+ target,
264
+ isOpen,
265
+ editorView,
266
+ tableNode,
297
267
  targetCellPosition,
298
- selectionRect,
268
+ getEditorContainerWidth,
299
269
  editorAnalyticsAPI,
300
- );
301
-
302
- const { menuItems, menuCallback } = convertToDropdownItems(
303
- dragMenuConfig,
304
- formatMessage,
305
- selectionRect,
306
- );
307
-
308
- const handleSubMenuRef = (ref: HTMLDivElement | null) => {
309
- const parent = closestElement(
310
- editorView.dom as HTMLElement,
311
- '.fabric-editor-popup-scroll-parent',
312
- );
313
- if (!(parent && ref)) {
314
- return;
315
- }
316
- const boundariesRect = parent.getBoundingClientRect();
317
- const rect = ref.getBoundingClientRect();
318
- if (rect.left + rect.width > boundariesRect.width) {
319
- ref.style.left = `-${rect.width}px`;
320
- }
321
- };
322
-
323
- const setColor = (color: string) => {
324
- const { targetCellPosition } = getTablePluginState(editorView.state);
270
+ pluginConfig,
271
+ intl: { formatMessage },
272
+ }: DragMenuProps & WrappedComponentProps) => {
325
273
  const { state, dispatch } = editorView;
326
- setColorWithAnalytics(editorAnalyticsAPI)(
327
- INPUT_METHOD.CONTEXT_MENU,
328
- color,
274
+ const { selection } = state;
275
+ const tableMap = tableNode ? TableMap.get(tableNode) : undefined;
276
+ const [isSubmenuOpen, setIsSubmenuOpen] = useState(false);
277
+ const { isKeyboardModeActive } = getPluginState(state);
278
+
279
+ const selectionRect = isSelectionType(selection, 'cell')
280
+ ? getSelectionRect(selection)!
281
+ : findCellRectClosestToPos(selection.$from);
282
+
283
+ const hasMergedCells =
284
+ direction === 'row' ? hasMergedCellsInRow : hasMergedCellsInColumn;
285
+
286
+ const shouldMoveDisabled =
287
+ index !== undefined && hasMergedCells(index)(selection);
288
+
289
+ const hasMergedCellsInTable = getMergedCellsPositions(state.tr).length > 0;
290
+ const allowBackgroundColor = pluginConfig?.allowBackgroundColor ?? false;
291
+
292
+ const dragMenuConfig = getDragMenuConfig(
293
+ direction,
294
+ getEditorContainerWidth,
295
+ !shouldMoveDisabled,
296
+ hasMergedCellsInTable,
297
+ editorView,
298
+ tableMap,
299
+ index,
329
300
  targetCellPosition,
330
- )(state, dispatch);
331
- closeMenu();
332
- setIsSubmenuOpen(false);
333
- };
301
+ selectionRect,
302
+ editorAnalyticsAPI,
303
+ );
334
304
 
335
- const createBackgroundColorMenuItem = () => {
336
- const { targetCellPosition } = getTablePluginState(editorView.state);
337
- const node = targetCellPosition
338
- ? state.doc.nodeAt(targetCellPosition)
339
- : null;
340
- const background = hexToEditorBackgroundPaletteColor(
341
- node?.attrs?.background || '#ffffff',
305
+ const { menuItems, menuCallback } = convertToDropdownItems(
306
+ dragMenuConfig,
307
+ formatMessage,
308
+ selectionRect,
342
309
  );
343
- return {
344
- content: formatMessage(messages.backgroundColor),
345
- value: { name: 'background' },
346
- elemBefore: (
347
- <span css={elementBeforeIconStyles}>
348
- <EditorBackgroundColorIcon
349
- label={formatMessage(messages.backgroundColor)}
350
- size="medium"
351
- />
352
- </span>
353
- ),
354
- elemAfter: (
355
- <div
356
- className={DropdownMenuSharedCssClassName.SUBMENU}
357
- css={dragMenuBackgroundColorStyles}
358
- >
310
+
311
+ const handleSubMenuRef = (ref: HTMLDivElement | null) => {
312
+ const parent = closestElement(
313
+ editorView.dom as HTMLElement,
314
+ '.fabric-editor-popup-scroll-parent',
315
+ );
316
+ if (!(parent && ref)) {
317
+ return;
318
+ }
319
+ const boundariesRect = parent.getBoundingClientRect();
320
+ const rect = ref.getBoundingClientRect();
321
+ if (rect.left + rect.width > boundariesRect.width) {
322
+ ref.style.left = `-${rect.width}px`;
323
+ }
324
+ };
325
+
326
+ const setColor = (color: string) => {
327
+ const { targetCellPosition } = getTablePluginState(editorView.state);
328
+ const { state, dispatch } = editorView;
329
+ setColorWithAnalytics(editorAnalyticsAPI)(
330
+ INPUT_METHOD.CONTEXT_MENU,
331
+ color,
332
+ targetCellPosition,
333
+ )(state, dispatch);
334
+ closeMenu();
335
+ setIsSubmenuOpen(false);
336
+ };
337
+
338
+ const createBackgroundColorMenuItem = () => {
339
+ const { targetCellPosition } = getTablePluginState(editorView.state);
340
+ const node = targetCellPosition
341
+ ? state.doc.nodeAt(targetCellPosition)
342
+ : null;
343
+ const background = hexToEditorBackgroundPaletteColor(
344
+ node?.attrs?.background || '#ffffff',
345
+ );
346
+
347
+ const { selectedRowIndex, selectedColumnIndex } =
348
+ getSelectedRowAndColumnFromPalette(
349
+ cellBackgroundColorPalette,
350
+ background,
351
+ colorPalletteColumns,
352
+ );
353
+
354
+ return {
355
+ key: 'background',
356
+ content: formatMessage(messages.backgroundColor),
357
+ value: { name: 'background' },
358
+ elemBefore: (
359
+ <span css={elementBeforeIconStyles}>
360
+ <EditorBackgroundColorIcon
361
+ label={formatMessage(messages.backgroundColor)}
362
+ size="medium"
363
+ />
364
+ </span>
365
+ ),
366
+ elemAfter: (
359
367
  <div
360
- css={cellColourPreviewStyles(background)}
361
- className={ClassName.DRAG_SUBMENU_ICON}
362
- />
363
- {isSubmenuOpen && (
364
- <div className={ClassName.DRAG_SUBMENU} ref={handleSubMenuRef}>
365
- <ColorPalette
366
- cols={7}
367
- onClick={setColor}
368
- selectedColor={background}
369
- paletteOptions={{
370
- palette: cellBackgroundColorPalette,
371
- paletteColorTooltipMessages: backgroundPaletteTooltipMessages,
372
- hexToPaletteColor: hexToEditorBackgroundPaletteColor,
373
- }}
374
- />
375
- </div>
376
- )}
377
- </div>
378
- ),
379
- } as MenuItem;
380
- };
368
+ className={DropdownMenuSharedCssClassName.SUBMENU}
369
+ css={dragMenuBackgroundColorStyles}
370
+ >
371
+ <div
372
+ css={cellColourPreviewStyles(background)}
373
+ className={ClassName.DRAG_SUBMENU_ICON}
374
+ />
375
+ {isSubmenuOpen && (
376
+ <div className={ClassName.DRAG_SUBMENU} ref={handleSubMenuRef}>
377
+ <ArrowKeyNavigationProvider
378
+ type={ArrowKeyNavigationType.COLOR}
379
+ selectedRowIndex={selectedRowIndex}
380
+ selectedColumnIndex={selectedColumnIndex}
381
+ handleClose={() => {
382
+ const keyboardEvent = new KeyboardEvent('keydown', {
383
+ key: 'ArrowDown',
384
+ bubbles: true,
385
+ });
386
+ setIsSubmenuOpen(false);
387
+ (target as HTMLElement)?.focus();
388
+ target?.dispatchEvent(keyboardEvent);
389
+ }}
390
+ isPopupPositioned={true}
391
+ isOpenedByKeyboard={isKeyboardModeActive}
392
+ >
393
+ <ColorPaletteWithListeners
394
+ cols={colorPalletteColumns}
395
+ onClick={(color) => {
396
+ setColor(color);
397
+ }}
398
+ selectedColor={background}
399
+ paletteOptions={{
400
+ palette: cellBackgroundColorPalette,
401
+ paletteColorTooltipMessages:
402
+ backgroundPaletteTooltipMessages,
403
+ hexToPaletteColor: hexToEditorBackgroundPaletteColor,
404
+ }}
405
+ />
406
+ </ArrowKeyNavigationProvider>
407
+ </div>
408
+ )}
409
+ </div>
410
+ ),
411
+ } as MenuItem;
412
+ };
413
+
414
+ const toggleHeaderColumn = () => {
415
+ toggleHeaderColumnWithAnalytics(editorAnalyticsAPI)(state, dispatch);
416
+ };
417
+
418
+ const toggleHeaderRow = () => {
419
+ toggleHeaderRowWithAnalytics(editorAnalyticsAPI)(state, dispatch);
420
+ };
421
+
422
+ const toggleRowNumbers = () => {
423
+ toggleNumberColumnWithAnalytics(editorAnalyticsAPI)(state, dispatch);
424
+ };
425
+
426
+ const createHeaderRowColumnMenuItem = (direction: TableDirection) => {
427
+ return direction === 'column'
428
+ ? ({
429
+ key: 'header_column',
430
+ content: formatMessage(messages.headerColumn),
431
+ value: { name: 'header_column' },
432
+ elemAfter: (
433
+ <div css={toggleStyles}>
434
+ <Toggle
435
+ id="toggle-header-column"
436
+ onChange={toggleHeaderColumn}
437
+ isChecked={checkIfHeaderColumnEnabled(selection)}
438
+ />
439
+ </div>
440
+ ),
441
+ } as MenuItem)
442
+ : ({
443
+ key: 'header_row',
444
+ content: formatMessage(messages.headerRow),
445
+ value: { name: 'header_row' },
446
+ elemAfter: (
447
+ <div css={toggleStyles}>
448
+ <Toggle
449
+ id="toggle-header-row"
450
+ onChange={toggleHeaderRow}
451
+ isChecked={checkIfHeaderRowEnabled(selection)}
452
+ />
453
+ </div>
454
+ ),
455
+ } as MenuItem);
456
+ };
457
+
458
+ const createRowNumbersMenuItem = () => {
459
+ return {
460
+ key: 'row_numbers',
461
+ content: formatMessage(messages.rowNumbers),
462
+ value: { name: 'row_numbers' },
463
+ elemAfter: (
464
+ <div css={toggleStyles}>
465
+ <Toggle
466
+ id="toggle-row-numbers"
467
+ onChange={toggleRowNumbers}
468
+ isChecked={checkIfNumberColumnEnabled(selection)}
469
+ />
470
+ </div>
471
+ ),
472
+ } as MenuItem;
473
+ };
474
+
475
+ /**
476
+ * This function is to check if the menu should be closed or not.
477
+ * As when continously clicking on tyle handle on different rows/columns,
478
+ * should open the menu corresponding to the position of the drag handle.
479
+ * @returns true when the menu should be closed, false otherwise
480
+ */
481
+ const shouldCloseMenu = (state: EditorState) => {
482
+ let {
483
+ isDragMenuOpen: previousOpenState,
484
+ dragMenuDirection: previousDragMenuDirection,
485
+ dragMenuIndex: previousDragMenuIndex,
486
+ } = getPluginState(state);
487
+
488
+ // menu open but menu direction changed, means user clicked on drag handle of different row/column
489
+ // menu open menu direction not changed, but index changed, means user clicked on drag handle of same row/column, different cells.
490
+ // 2 scenarios above , menu should not be closed.
491
+ if (
492
+ (previousOpenState === true &&
493
+ previousDragMenuDirection !== direction) ||
494
+ (previousOpenState === true &&
495
+ previousDragMenuDirection === direction &&
496
+ previousDragMenuIndex !== index)
497
+ ) {
498
+ return false;
499
+ } else {
500
+ return true;
501
+ }
502
+ };
503
+
504
+ const closeMenu = (focusTarget: 'editor' | 'handle' = 'handle') => {
505
+ const { state, dispatch } = editorView;
506
+ if (shouldCloseMenu(state)) {
507
+ if (target && focusTarget === 'handle') {
508
+ (target as HTMLElement | null)?.focus();
509
+ } else {
510
+ editorView.dom.focus();
511
+ }
512
+ toggleDragMenu(false, direction, index)(state, dispatch);
513
+ }
514
+ };
381
515
 
382
- const toggleHeaderColumn = () => {
383
- toggleHeaderColumnWithAnalytics(editorAnalyticsAPI)(state, dispatch);
384
- };
516
+ const handleMenuItemActivated = ({ item }: { item: MenuItem }) => {
517
+ menuCallback[item.value.name]?.(state, dispatch);
385
518
 
386
- const toggleHeaderRow = () => {
387
- toggleHeaderRowWithAnalytics(editorAnalyticsAPI)(state, dispatch);
388
- };
519
+ switch (item.value.name) {
520
+ case 'background':
521
+ setIsSubmenuOpen(!isSubmenuOpen);
522
+ break;
523
+ case 'header_column':
524
+ toggleHeaderColumn();
525
+ break;
526
+ case 'header_row':
527
+ toggleHeaderRow();
528
+ break;
529
+ case 'row_numbers':
530
+ toggleRowNumbers();
531
+ break;
532
+ default:
533
+ break;
534
+ }
389
535
 
390
- const toggleRowNumbers = () => {
391
- toggleNumberColumnWithAnalytics(editorAnalyticsAPI)(state, dispatch);
392
- };
536
+ if (
537
+ ['header_column', 'header_row', 'row_numbers', 'background'].indexOf(
538
+ item.value.name,
539
+ ) <= -1
540
+ ) {
541
+ closeMenu('editor');
542
+ }
543
+ };
393
544
 
394
- const createhHeaderRowColumnMenuItem = (direction: TableDirection) => {
395
- return direction === 'column'
396
- ? ({
397
- content: formatMessage(messages.headerColumn),
398
- value: { name: 'header_column' },
399
- elemAfter: (
400
- <div css={toggleStyles}>
401
- <Toggle
402
- id="toggle-header-column"
403
- onChange={toggleHeaderColumn}
404
- isChecked={checkIfHeaderColumnEnabled(selection)}
405
- />
406
- </div>
407
- ),
408
- } as MenuItem)
409
- : ({
410
- content: formatMessage(messages.headerRow),
411
- value: { name: 'header_row' },
412
- elemAfter: (
413
- <div css={toggleStyles}>
414
- <Toggle
415
- id="toggle-header-row"
416
- onChange={toggleHeaderRow}
417
- isChecked={checkIfHeaderRowEnabled(selection)}
418
- />
419
- </div>
420
- ),
421
- } as MenuItem);
422
- };
545
+ const handleItemMouseEnter = ({ item }: { item: MenuItem }) => {
546
+ if (!selectionRect) {
547
+ return;
548
+ }
423
549
 
424
- const createRowNumbersMenuItem = () => {
425
- return {
426
- content: formatMessage(messages.rowNumbers),
427
- value: { name: 'row_numbers' },
428
- elemAfter: (
429
- <div css={toggleStyles}>
430
- <Toggle
431
- id="toggle-row-numbers"
432
- onChange={toggleRowNumbers}
433
- isChecked={checkIfNumberColumnEnabled(selection)}
434
- />
435
- </div>
436
- ),
437
- } as MenuItem;
438
- };
550
+ if (item.value.name === 'background' && !isSubmenuOpen) {
551
+ setIsSubmenuOpen(true);
552
+ }
439
553
 
440
- /**
441
- * This function is to check if the menu should be closed or not.
442
- * As when continously clicking on tyle handle on different rows/columns,
443
- * should open the menu corresponding to the position of the drag handle.
444
- * @returns true when the menu should be closed, false otherwise
445
- */
446
- const shouldCloseMenu = (state: EditorState) => {
447
- let {
448
- isDragMenuOpen: previousOpenState,
449
- dragMenuDirection: previousDragMenuDirection,
450
- dragMenuIndex: previousDragMenuIndex,
451
- } = getPluginState(state);
452
-
453
- // menu open but menu direction changed, means user clicked on drag handle of different row/column
454
- // menu open menu direction not changed, but index changed, means user clicked on drag handle of same row/column, different cells.
455
- // 2 scenarios above , menu should not be closed.
456
- if (
457
- (previousOpenState === true && previousDragMenuDirection !== direction) ||
458
- (previousOpenState === true &&
459
- previousDragMenuDirection === direction &&
460
- previousDragMenuIndex !== index)
461
- ) {
462
- return false;
463
- } else {
464
- return true;
465
- }
466
- };
554
+ if (!item.value.name?.startsWith('delete')) {
555
+ return;
556
+ }
467
557
 
468
- const closeMenu = () => {
469
- const { state, dispatch } = editorView;
470
- if (shouldCloseMenu(state)) {
471
- toggleDragMenu(false, direction, index)(state, dispatch);
472
- }
473
- };
558
+ (item.value.name === 'delete_column'
559
+ ? hoverColumns(getSelectedColumnIndexes(selectionRect), true)
560
+ : hoverRows(getSelectedRowIndexes(selectionRect), true))(
561
+ state,
562
+ dispatch,
563
+ );
564
+ };
565
+
566
+ const handleItemMouseLeave = ({ item }: { item: any }) => {
567
+ if (item.value.name === 'background' && isSubmenuOpen) {
568
+ setIsSubmenuOpen(false);
569
+ }
474
570
 
475
- const handleMenuItemActivated = ({ item }: { item: MenuItem }) => {
476
- menuCallback[item.value.name]?.(state, dispatch);
477
-
478
- switch (item.value.name) {
479
- case 'header_column':
480
- toggleHeaderColumn();
481
- break;
482
- case 'header_row':
483
- toggleHeaderRow();
484
- break;
485
- case 'row_numbers':
486
- toggleRowNumbers();
487
- break;
488
- default:
489
- break;
571
+ if (
572
+ [
573
+ 'sort_column_asc',
574
+ 'sort_column_desc',
575
+ 'delete_column',
576
+ 'delete_row',
577
+ ].indexOf(item.value.name) > -1
578
+ ) {
579
+ clearHoverSelection()(state, dispatch);
580
+ }
581
+ };
582
+
583
+ useEffect(() => {
584
+ // focus on first menu item automatically when menu renders
585
+ // and user is using keyboard
586
+ if (isOpen && target && isKeyboardModeActive) {
587
+ const keyboardEvent = new KeyboardEvent('keydown', {
588
+ key: 'ArrowDown',
589
+ bubbles: true,
590
+ });
591
+ target.dispatchEvent(keyboardEvent);
592
+ }
593
+ }, [isOpen, target, isKeyboardModeActive]);
594
+
595
+ if (!menuItems) {
596
+ return null;
490
597
  }
491
598
 
492
599
  if (
493
- ['header_column', 'header_row', 'row_numbers', 'background'].indexOf(
494
- item.value.name,
495
- ) <= -1
600
+ allowBackgroundColor &&
601
+ getBooleanFF('platform.editor.table.new-cell-context-menu-styling')
496
602
  ) {
497
- closeMenu();
498
- }
499
- };
500
-
501
- const handleItemMouseEnter = ({ item }: { item: MenuItem }) => {
502
- if (!selectionRect) {
503
- return;
504
- }
505
-
506
- if (item.value.name === 'background' && !isSubmenuOpen) {
507
- setIsSubmenuOpen(true);
508
- }
509
-
510
- if (!item.value.name?.startsWith('delete')) {
511
- return;
603
+ menuItems[0].items.unshift(createBackgroundColorMenuItem());
512
604
  }
513
605
 
514
- (item.value.name === 'delete_column'
515
- ? hoverColumns(getSelectedColumnIndexes(selectionRect), true)
516
- : hoverRows(getSelectedRowIndexes(selectionRect), true))(state, dispatch);
517
- };
518
-
519
- const handleItemMouseLeave = ({ item }: { item: any }) => {
520
- if (item.value.name === 'background' && isSubmenuOpen) {
521
- setIsSubmenuOpen(false);
606
+ // If first row, add toggle for Header row, default is true
607
+ // If first column, add toggle for Header column, default is false
608
+ if (
609
+ getBooleanFF('platform.editor.table.new-cell-context-menu-styling') &&
610
+ index === 0
611
+ ) {
612
+ menuItems.push({ items: [createHeaderRowColumnMenuItem(direction)] });
522
613
  }
523
614
 
615
+ // All rows, add toggle for numbered rows, default is false
524
616
  if (
525
- [
526
- 'sort_column_asc',
527
- 'sort_column_desc',
528
- 'delete_column',
529
- 'delete_row',
530
- ].indexOf(item.value.name) > -1
617
+ getBooleanFF('platform.editor.table.new-cell-context-menu-styling') &&
618
+ direction === 'row'
531
619
  ) {
532
- clearHoverSelection()(state, dispatch);
620
+ index === 0
621
+ ? menuItems[menuItems.length - 1].items.push(createRowNumbersMenuItem())
622
+ : menuItems.push({ items: [createRowNumbersMenuItem()] });
533
623
  }
534
- };
535
624
 
536
- if (!menuItems) {
537
- return null;
538
- }
539
-
540
- if (
541
- allowBackgroundColor &&
542
- getBooleanFF('platform.editor.table.new-cell-context-menu-styling')
543
- ) {
544
- menuItems[0].items.unshift(createBackgroundColorMenuItem());
545
- }
546
-
547
- // If first row, add toggle for Hearder row, default is true
548
- // If first column, add toggle for Header column, default is false
549
- if (
550
- getBooleanFF('platform.editor.table.new-cell-context-menu-styling') &&
551
- index === 0
552
- ) {
553
- menuItems.push({ items: [createhHeaderRowColumnMenuItem(direction)] });
554
- }
555
-
556
- // All rows, add toggle for numbered rows, default is false
557
- if (
558
- getBooleanFF('platform.editor.table.new-cell-context-menu-styling') &&
559
- direction === 'row'
560
- ) {
561
- index === 0
562
- ? menuItems[menuItems.length - 1].items.push(createRowNumbersMenuItem())
563
- : menuItems.push({ items: [createRowNumbersMenuItem()] });
564
- }
565
-
566
- return (
567
- <DropdownMenu
568
- mountTo={mountPoint}
569
- //This needs be removed when the a11y is completely handled
570
- //Disabling key navigation now as it works only partially
571
- arrowKeyNavigationProviderOptions={{
572
- type: ArrowKeyNavigationType.MENU,
573
- disableArrowKeyNavigation: true,
574
- }}
575
- items={menuItems}
576
- isOpen={isOpen}
577
- onOpenChange={closeMenu}
578
- onItemActivated={handleMenuItemActivated}
579
- onMouseEnter={handleItemMouseEnter}
580
- onMouseLeave={handleItemMouseLeave}
581
- fitWidth={dragMenuDropdownWidth}
582
- boundariesElement={boundariesElement}
583
- section={{ hasSeparator: true }}
584
- />
585
- );
586
- };
625
+ return (
626
+ <DropdownMenu
627
+ disableKeyboardHandling={isSubmenuOpen}
628
+ section={{ hasSeparator: true }}
629
+ target={target as HTMLElement | undefined}
630
+ items={menuItems}
631
+ onItemActivated={handleMenuItemActivated}
632
+ onMouseEnter={handleItemMouseEnter}
633
+ onMouseLeave={handleItemMouseLeave}
634
+ handleClose={closeMenu}
635
+ />
636
+ );
637
+ },
638
+ );
587
639
 
588
640
  export default injectIntl(DragMenu);