@atlaskit/editor-plugin-table 7.16.11 → 7.16.13

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 (254) hide show
  1. package/.eslintrc.js +3 -3
  2. package/CHANGELOG.md +16 -0
  3. package/dist/cjs/commands/misc.js +3 -3
  4. package/dist/cjs/nodeviews/TableCell.js +10 -10
  5. package/dist/cjs/nodeviews/TableContainer.js +83 -27
  6. package/dist/cjs/nodeviews/TableResizer.js +40 -19
  7. package/dist/cjs/nodeviews/TableRow.js +23 -23
  8. package/dist/cjs/pm-plugins/table-resizing/plugin.js +3 -3
  9. package/dist/cjs/pm-plugins/table-resizing/utils/resize-state.js +4 -4
  10. package/dist/cjs/pm-plugins/table-resizing/utils/scale-table.js +3 -3
  11. package/dist/cjs/ui/FloatingContextualMenu/styles.js +1 -1
  12. package/dist/cjs/ui/FloatingDragMenu/styles.js +1 -1
  13. package/dist/cjs/ui/common-styles.js +13 -13
  14. package/dist/cjs/ui/ui-styles.js +25 -25
  15. package/dist/cjs/utils/guidelines.js +7 -4
  16. package/dist/cjs/utils/merged-cells.js +3 -3
  17. package/dist/cjs/utils/snapping.js +7 -8
  18. package/dist/es2019/commands/misc.js +3 -3
  19. package/dist/es2019/nodeviews/TableContainer.js +70 -9
  20. package/dist/es2019/nodeviews/TableResizer.js +42 -21
  21. package/dist/es2019/nodeviews/TableRow.js +21 -21
  22. package/dist/es2019/pm-plugins/table-resizing/plugin.js +3 -3
  23. package/dist/es2019/pm-plugins/table-resizing/utils/resize-state.js +4 -4
  24. package/dist/es2019/pm-plugins/table-resizing/utils/scale-table.js +3 -3
  25. package/dist/es2019/ui/FloatingContextualMenu/styles.js +47 -47
  26. package/dist/es2019/ui/FloatingDragMenu/styles.js +30 -30
  27. package/dist/es2019/ui/common-styles.js +802 -816
  28. package/dist/es2019/ui/ui-styles.js +665 -678
  29. package/dist/es2019/utils/guidelines.js +5 -2
  30. package/dist/es2019/utils/merged-cells.js +3 -3
  31. package/dist/es2019/utils/snapping.js +5 -6
  32. package/dist/esm/commands/misc.js +3 -3
  33. package/dist/esm/nodeviews/TableCell.js +10 -10
  34. package/dist/esm/nodeviews/TableContainer.js +85 -29
  35. package/dist/esm/nodeviews/TableResizer.js +42 -21
  36. package/dist/esm/nodeviews/TableRow.js +23 -23
  37. package/dist/esm/pm-plugins/table-resizing/plugin.js +3 -3
  38. package/dist/esm/pm-plugins/table-resizing/utils/resize-state.js +4 -4
  39. package/dist/esm/pm-plugins/table-resizing/utils/scale-table.js +3 -3
  40. package/dist/esm/ui/FloatingContextualMenu/styles.js +1 -1
  41. package/dist/esm/ui/FloatingDragMenu/styles.js +1 -1
  42. package/dist/esm/ui/common-styles.js +13 -13
  43. package/dist/esm/ui/ui-styles.js +25 -25
  44. package/dist/esm/utils/guidelines.js +6 -3
  45. package/dist/esm/utils/merged-cells.js +3 -3
  46. package/dist/esm/utils/snapping.js +6 -7
  47. package/dist/types/nodeviews/TableResizer.d.ts +2 -1
  48. package/dist/types/pm-plugins/decorations/utils/index.d.ts +1 -1
  49. package/dist/types/pm-plugins/drag-and-drop/utils/autoscrollers.d.ts +1 -1
  50. package/dist/types/pm-plugins/drag-and-drop/utils/getDragBehaviour.d.ts +1 -1
  51. package/dist/types/pm-plugins/table-resizing/utils/index.d.ts +1 -1
  52. package/dist/types/ui/ColumnResizeWidget/index.d.ts +1 -1
  53. package/dist/types/ui/FloatingAlignmentButtons/FloatingAlignmentButtons.d.ts +1 -1
  54. package/dist/types/ui/FloatingToolbarLabel/FloatingToolbarLabel.d.ts +1 -1
  55. package/dist/types/ui/TableFloatingColumnControls/ColumnDropTargets/ColumnDropTarget.d.ts +1 -1
  56. package/dist/types/ui/TableFloatingControls/CornerControls/index.d.ts +1 -1
  57. package/dist/types/ui/icons/DragHandleDisabledIcon.d.ts +1 -1
  58. package/dist/types/utils/guidelines.d.ts +2 -1
  59. package/dist/types/utils/snapping.d.ts +3 -2
  60. package/dist/types-ts4.5/nodeviews/TableResizer.d.ts +2 -1
  61. package/dist/types-ts4.5/pm-plugins/decorations/utils/index.d.ts +1 -1
  62. package/dist/types-ts4.5/pm-plugins/drag-and-drop/utils/autoscrollers.d.ts +1 -1
  63. package/dist/types-ts4.5/pm-plugins/drag-and-drop/utils/getDragBehaviour.d.ts +1 -1
  64. package/dist/types-ts4.5/pm-plugins/table-resizing/utils/index.d.ts +1 -1
  65. package/dist/types-ts4.5/ui/ColumnResizeWidget/index.d.ts +1 -1
  66. package/dist/types-ts4.5/ui/FloatingAlignmentButtons/FloatingAlignmentButtons.d.ts +1 -1
  67. package/dist/types-ts4.5/ui/FloatingToolbarLabel/FloatingToolbarLabel.d.ts +1 -1
  68. package/dist/types-ts4.5/ui/TableFloatingColumnControls/ColumnDropTargets/ColumnDropTarget.d.ts +1 -1
  69. package/dist/types-ts4.5/ui/TableFloatingControls/CornerControls/index.d.ts +1 -1
  70. package/dist/types-ts4.5/ui/icons/DragHandleDisabledIcon.d.ts +1 -1
  71. package/dist/types-ts4.5/utils/guidelines.d.ts +2 -1
  72. package/dist/types-ts4.5/utils/snapping.d.ts +3 -2
  73. package/docs/0-intro.tsx +9 -7
  74. package/package.json +3 -3
  75. package/report.api.md +67 -66
  76. package/src/commands/clear.ts +36 -44
  77. package/src/commands/collapse.ts +8 -8
  78. package/src/commands/column-resize.ts +412 -452
  79. package/src/commands/delete.ts +14 -14
  80. package/src/commands/display-mode.ts +10 -11
  81. package/src/commands/go-to-next-cell.ts +48 -54
  82. package/src/commands/hover.ts +210 -227
  83. package/src/commands/index.ts +35 -35
  84. package/src/commands/insert.ts +208 -235
  85. package/src/commands/misc.ts +655 -748
  86. package/src/commands/referentiality.ts +9 -9
  87. package/src/commands/selection.ts +433 -563
  88. package/src/commands/sort.ts +68 -86
  89. package/src/commands/split-cell.ts +14 -14
  90. package/src/commands/toggle.ts +69 -67
  91. package/src/commands-with-analytics.ts +570 -639
  92. package/src/create-plugin-config.ts +13 -13
  93. package/src/event-handlers.ts +513 -612
  94. package/src/handlers.ts +120 -133
  95. package/src/nodeviews/ExternalDropTargets.tsx +68 -73
  96. package/src/nodeviews/OverflowShadowsObserver.ts +148 -157
  97. package/src/nodeviews/TableCell.ts +47 -54
  98. package/src/nodeviews/TableComponent.tsx +1018 -1112
  99. package/src/nodeviews/TableComponentWithSharedState.tsx +91 -94
  100. package/src/nodeviews/TableContainer.tsx +384 -340
  101. package/src/nodeviews/TableNodeViewBase.ts +19 -24
  102. package/src/nodeviews/TableResizer.tsx +642 -653
  103. package/src/nodeviews/TableRow.ts +580 -629
  104. package/src/nodeviews/TableStickyScrollbar.ts +173 -190
  105. package/src/nodeviews/__mocks__/OverflowShadowsObserver.ts +8 -8
  106. package/src/nodeviews/__mocks__/OverridableMock.ts +14 -15
  107. package/src/nodeviews/table.tsx +345 -375
  108. package/src/nodeviews/types.ts +21 -24
  109. package/src/nodeviews/update-overflow-shadows.ts +8 -14
  110. package/src/plugin.tsx +578 -603
  111. package/src/pm-plugins/analytics/actions.ts +10 -12
  112. package/src/pm-plugins/analytics/commands.ts +31 -37
  113. package/src/pm-plugins/analytics/plugin-factory.ts +4 -2
  114. package/src/pm-plugins/analytics/plugin-key.ts +1 -3
  115. package/src/pm-plugins/analytics/plugin.ts +60 -70
  116. package/src/pm-plugins/analytics/reducer.ts +19 -19
  117. package/src/pm-plugins/analytics/types.ts +10 -10
  118. package/src/pm-plugins/analytics/utils/moved-event.ts +38 -38
  119. package/src/pm-plugins/decorations/plugin.ts +58 -77
  120. package/src/pm-plugins/decorations/utils/column-controls.ts +59 -71
  121. package/src/pm-plugins/decorations/utils/column-resizing.ts +50 -57
  122. package/src/pm-plugins/decorations/utils/compose-decorations.ts +6 -6
  123. package/src/pm-plugins/decorations/utils/index.ts +3 -6
  124. package/src/pm-plugins/decorations/utils/types.ts +7 -12
  125. package/src/pm-plugins/default-table-selection.ts +3 -3
  126. package/src/pm-plugins/drag-and-drop/actions.ts +25 -25
  127. package/src/pm-plugins/drag-and-drop/commands-with-analytics.ts +158 -190
  128. package/src/pm-plugins/drag-and-drop/commands.ts +154 -170
  129. package/src/pm-plugins/drag-and-drop/consts.ts +4 -5
  130. package/src/pm-plugins/drag-and-drop/plugin-factory.ts +23 -20
  131. package/src/pm-plugins/drag-and-drop/plugin-key.ts +1 -3
  132. package/src/pm-plugins/drag-and-drop/plugin.ts +329 -383
  133. package/src/pm-plugins/drag-and-drop/reducer.ts +30 -30
  134. package/src/pm-plugins/drag-and-drop/types.ts +8 -8
  135. package/src/pm-plugins/drag-and-drop/utils/autoscrollers.ts +38 -41
  136. package/src/pm-plugins/drag-and-drop/utils/getDragBehaviour.ts +3 -6
  137. package/src/pm-plugins/drag-and-drop/utils/monitor.ts +57 -70
  138. package/src/pm-plugins/keymap.ts +208 -220
  139. package/src/pm-plugins/main.ts +348 -400
  140. package/src/pm-plugins/plugin-factory.ts +32 -34
  141. package/src/pm-plugins/safari-delete-composition-text-issue-workaround.ts +83 -97
  142. package/src/pm-plugins/sticky-headers/commands.ts +2 -6
  143. package/src/pm-plugins/sticky-headers/plugin-key.ts +1 -3
  144. package/src/pm-plugins/sticky-headers/plugin-state.ts +41 -44
  145. package/src/pm-plugins/sticky-headers/plugin.ts +4 -4
  146. package/src/pm-plugins/sticky-headers/types.ts +8 -8
  147. package/src/pm-plugins/sticky-headers/util.ts +10 -10
  148. package/src/pm-plugins/table-analytics.ts +70 -72
  149. package/src/pm-plugins/table-local-id.ts +180 -184
  150. package/src/pm-plugins/table-resizing/commands.ts +72 -85
  151. package/src/pm-plugins/table-resizing/event-handlers.ts +298 -317
  152. package/src/pm-plugins/table-resizing/plugin-factory.ts +10 -10
  153. package/src/pm-plugins/table-resizing/plugin-key.ts +1 -3
  154. package/src/pm-plugins/table-resizing/plugin.ts +61 -68
  155. package/src/pm-plugins/table-resizing/reducer.ts +30 -33
  156. package/src/pm-plugins/table-resizing/utils/colgroup.ts +84 -84
  157. package/src/pm-plugins/table-resizing/utils/column-state.ts +78 -81
  158. package/src/pm-plugins/table-resizing/utils/content-width.ts +94 -114
  159. package/src/pm-plugins/table-resizing/utils/dom.ts +93 -110
  160. package/src/pm-plugins/table-resizing/utils/index.ts +29 -34
  161. package/src/pm-plugins/table-resizing/utils/misc.ts +94 -119
  162. package/src/pm-plugins/table-resizing/utils/resize-column.ts +93 -106
  163. package/src/pm-plugins/table-resizing/utils/resize-logic.ts +240 -257
  164. package/src/pm-plugins/table-resizing/utils/resize-state.ts +343 -372
  165. package/src/pm-plugins/table-resizing/utils/scale-table.ts +202 -207
  166. package/src/pm-plugins/table-resizing/utils/types.ts +17 -17
  167. package/src/pm-plugins/table-resizing/utils/unit-to-number.ts +1 -2
  168. package/src/pm-plugins/table-selection-keymap.ts +25 -51
  169. package/src/pm-plugins/table-width.ts +191 -204
  170. package/src/pm-plugins/view-mode-sort/index.ts +223 -227
  171. package/src/pm-plugins/view-mode-sort/plugin-key.ts +3 -2
  172. package/src/pm-plugins/view-mode-sort/types.ts +12 -12
  173. package/src/pm-plugins/view-mode-sort/utils.ts +108 -117
  174. package/src/reducer.ts +139 -155
  175. package/src/toolbar.tsx +815 -905
  176. package/src/transforms/column-width.ts +186 -213
  177. package/src/transforms/delete-columns.ts +208 -222
  178. package/src/transforms/delete-rows.ts +117 -121
  179. package/src/transforms/fix-tables.ts +190 -215
  180. package/src/transforms/merge.ts +263 -269
  181. package/src/transforms/replace-table.ts +27 -43
  182. package/src/transforms/split.ts +65 -75
  183. package/src/types.ts +421 -427
  184. package/src/ui/ColumnResizeWidget/index.tsx +40 -47
  185. package/src/ui/DragHandle/HandleIconComponent.tsx +9 -13
  186. package/src/ui/DragHandle/index.tsx +221 -250
  187. package/src/ui/DragPreview/index.tsx +35 -35
  188. package/src/ui/FloatingAlignmentButtons/FloatingAlignmentButtons.tsx +33 -41
  189. package/src/ui/FloatingContextualButton/FixedButton.tsx +154 -157
  190. package/src/ui/FloatingContextualButton/index.tsx +109 -115
  191. package/src/ui/FloatingContextualButton/styles.ts +43 -46
  192. package/src/ui/FloatingContextualMenu/ContextualMenu.tsx +634 -694
  193. package/src/ui/FloatingContextualMenu/index.tsx +83 -101
  194. package/src/ui/FloatingContextualMenu/styles.ts +57 -65
  195. package/src/ui/FloatingDeleteButton/DeleteButton.tsx +37 -37
  196. package/src/ui/FloatingDeleteButton/getPopUpOptions.ts +47 -57
  197. package/src/ui/FloatingDeleteButton/index.tsx +319 -350
  198. package/src/ui/FloatingDragMenu/DragMenu.tsx +555 -596
  199. package/src/ui/FloatingDragMenu/DropdownMenu.tsx +152 -162
  200. package/src/ui/FloatingDragMenu/index.tsx +88 -102
  201. package/src/ui/FloatingDragMenu/styles.ts +51 -54
  202. package/src/ui/FloatingInsertButton/InsertButton.tsx +204 -217
  203. package/src/ui/FloatingInsertButton/getPopupOptions.ts +100 -115
  204. package/src/ui/FloatingInsertButton/index.tsx +248 -292
  205. package/src/ui/FloatingToolbarLabel/FloatingToolbarLabel.tsx +24 -29
  206. package/src/ui/TableFloatingColumnControls/ColumnControls/index.tsx +308 -329
  207. package/src/ui/TableFloatingColumnControls/ColumnDropTargets/ColumnDropTarget.tsx +85 -94
  208. package/src/ui/TableFloatingColumnControls/ColumnDropTargets/index.tsx +46 -46
  209. package/src/ui/TableFloatingColumnControls/index.tsx +116 -136
  210. package/src/ui/TableFloatingControls/CornerControls/ClassicCornerControls.tsx +79 -91
  211. package/src/ui/TableFloatingControls/CornerControls/DragCornerControls.tsx +95 -102
  212. package/src/ui/TableFloatingControls/CornerControls/index.tsx +1 -4
  213. package/src/ui/TableFloatingControls/CornerControls/types.ts +8 -8
  214. package/src/ui/TableFloatingControls/FloatingControlsWithSelection.tsx +50 -50
  215. package/src/ui/TableFloatingControls/NumberColumn/index.tsx +111 -124
  216. package/src/ui/TableFloatingControls/RowControls/ClassicControls.tsx +86 -105
  217. package/src/ui/TableFloatingControls/RowControls/DragControls.tsx +305 -341
  218. package/src/ui/TableFloatingControls/RowDropTarget/index.tsx +72 -75
  219. package/src/ui/TableFloatingControls/index.tsx +191 -193
  220. package/src/ui/TableFullWidthLabel/index.tsx +20 -20
  221. package/src/ui/common-styles.ts +880 -912
  222. package/src/ui/consts.ts +29 -74
  223. package/src/ui/icons/AddColLeftIcon.tsx +33 -39
  224. package/src/ui/icons/AddColRightIcon.tsx +33 -39
  225. package/src/ui/icons/AddRowAboveIcon.tsx +16 -22
  226. package/src/ui/icons/AddRowBelowIcon.tsx +33 -39
  227. package/src/ui/icons/DisplayModeIcon.tsx +31 -31
  228. package/src/ui/icons/DragHandleDisabledIcon.tsx +19 -21
  229. package/src/ui/icons/DragHandleIcon.tsx +12 -12
  230. package/src/ui/icons/DragInMotionIcon.tsx +45 -52
  231. package/src/ui/icons/MergeCellsIcon.tsx +22 -28
  232. package/src/ui/icons/MinimisedHandle.tsx +9 -9
  233. package/src/ui/icons/SplitCellIcon.tsx +30 -36
  234. package/src/ui/ui-styles.ts +769 -798
  235. package/src/utils/alignment.ts +1 -1
  236. package/src/utils/analytics.ts +192 -208
  237. package/src/utils/collapse.ts +55 -64
  238. package/src/utils/column-controls.ts +237 -254
  239. package/src/utils/create.ts +30 -30
  240. package/src/utils/decoration.ts +482 -502
  241. package/src/utils/dom.ts +127 -134
  242. package/src/utils/drag-menu.ts +322 -373
  243. package/src/utils/get-allow-add-column-custom-step.ts +4 -5
  244. package/src/utils/guidelines.ts +16 -21
  245. package/src/utils/index.ts +68 -68
  246. package/src/utils/merged-cells.ts +245 -254
  247. package/src/utils/nodes.ts +91 -106
  248. package/src/utils/paste.ts +119 -135
  249. package/src/utils/row-controls.ts +199 -213
  250. package/src/utils/selection.ts +77 -87
  251. package/src/utils/snapping.ts +87 -100
  252. package/src/utils/table.ts +44 -44
  253. package/src/utils/transforms.ts +5 -5
  254. package/src/utils/update-plugin-state-decorations.ts +5 -9
@@ -7,36 +7,25 @@ import type { WrappedComponentProps } from 'react-intl-next';
7
7
  import { injectIntl } from 'react-intl-next';
8
8
 
9
9
  type DropdownItem = MenuItem & {
10
- value: {
11
- name: string;
12
- };
10
+ value: {
11
+ name: string;
12
+ };
13
13
  };
14
14
 
15
15
  import { TableSortOrder as SortOrder } from '@atlaskit/custom-steps';
16
16
  import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
17
17
  import type { EditorAnalyticsAPI } from '@atlaskit/editor-common/analytics';
18
- import {
19
- addColumnAfter,
20
- addRowAfter,
21
- backspace,
22
- tooltip,
23
- } from '@atlaskit/editor-common/keymaps';
18
+ import { addColumnAfter, addRowAfter, backspace, tooltip } from '@atlaskit/editor-common/keymaps';
24
19
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
25
20
  import { DropdownMenuSharedCssClassName } from '@atlaskit/editor-common/styles';
26
- import type {
27
- GetEditorContainerWidth,
28
- GetEditorFeatureFlags,
29
- } from '@atlaskit/editor-common/types';
21
+ import type { GetEditorContainerWidth, GetEditorFeatureFlags } from '@atlaskit/editor-common/types';
30
22
  import {
31
- backgroundPaletteTooltipMessages,
32
- cellBackgroundColorPalette,
33
- ColorPalette,
23
+ backgroundPaletteTooltipMessages,
24
+ cellBackgroundColorPalette,
25
+ ColorPalette,
34
26
  } from '@atlaskit/editor-common/ui-color';
35
27
  import type { MenuItem } from '@atlaskit/editor-common/ui-menu';
36
- import {
37
- ArrowKeyNavigationType,
38
- DropdownMenu,
39
- } from '@atlaskit/editor-common/ui-menu';
28
+ import { ArrowKeyNavigationType, DropdownMenu } from '@atlaskit/editor-common/ui-menu';
40
29
  import { closestElement } from '@atlaskit/editor-common/utils';
41
30
  import { hexToEditorBackgroundPaletteColor } from '@atlaskit/editor-palette';
42
31
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
@@ -48,698 +37,649 @@ import EditorBackgroundColorIcon from '@atlaskit/icon/glyph/editor/background-co
48
37
  import RemoveIcon from '@atlaskit/icon/glyph/editor/remove';
49
38
 
50
39
  import {
51
- clearHoverSelection,
52
- hoverColumns,
53
- hoverMergedCells,
54
- hoverRows,
55
- toggleContextualMenu,
40
+ clearHoverSelection,
41
+ hoverColumns,
42
+ hoverMergedCells,
43
+ hoverRows,
44
+ toggleContextualMenu,
56
45
  } from '../../commands';
57
46
  import {
58
- deleteColumnsWithAnalytics,
59
- deleteRowsWithAnalytics,
60
- distributeColumnsWidthsWithAnalytics,
61
- emptyMultipleCellsWithAnalytics,
62
- insertColumnWithAnalytics,
63
- insertRowWithAnalytics,
64
- mergeCellsWithAnalytics,
65
- setColorWithAnalytics,
66
- sortColumnWithAnalytics,
67
- splitCellWithAnalytics,
47
+ deleteColumnsWithAnalytics,
48
+ deleteRowsWithAnalytics,
49
+ distributeColumnsWidthsWithAnalytics,
50
+ emptyMultipleCellsWithAnalytics,
51
+ insertColumnWithAnalytics,
52
+ insertRowWithAnalytics,
53
+ mergeCellsWithAnalytics,
54
+ setColorWithAnalytics,
55
+ sortColumnWithAnalytics,
56
+ splitCellWithAnalytics,
68
57
  } from '../../commands-with-analytics';
69
58
  import { getPluginState } from '../../pm-plugins/plugin-factory';
70
59
  import { getNewResizeStateFromSelectedColumns } from '../../pm-plugins/table-resizing/utils/resize-state';
71
60
  import { canMergeCells } from '../../transforms';
72
61
  import { TableCssClassName as ClassName } from '../../types';
73
62
  import {
74
- getMergedCellsPositions,
75
- getSelectedColumnIndexes,
76
- getSelectedRowIndexes,
63
+ getMergedCellsPositions,
64
+ getSelectedColumnIndexes,
65
+ getSelectedRowIndexes,
77
66
  } from '../../utils';
78
- import {
79
- contextualMenuDropdownWidth,
80
- contextualMenuDropdownWidthDnD,
81
- } from '../consts';
82
- import {
83
- AddColRightIcon,
84
- AddRowBelowIcon,
85
- MergeCellsIcon,
86
- SplitCellIcon,
87
- } from '../icons';
67
+ import { contextualMenuDropdownWidth, contextualMenuDropdownWidthDnD } from '../consts';
68
+ import { AddColRightIcon, AddRowBelowIcon, MergeCellsIcon, SplitCellIcon } from '../icons';
88
69
 
89
70
  import { cellColourPreviewStyles, elementBeforeIconStyles } from './styles';
90
71
 
91
72
  export interface Props {
92
- editorView: EditorView;
93
- isOpen: boolean;
94
- selectionRect: Rect;
95
- targetCellPosition?: number; // We keep this because we need to know when to rerender
96
- mountPoint?: HTMLElement;
97
- allowMergeCells?: boolean;
98
- allowColumnSorting?: boolean;
99
- allowBackgroundColor?: boolean;
100
- boundariesElement?: HTMLElement;
101
- offset?: Array<number>;
102
- editorAnalyticsAPI?: EditorAnalyticsAPI;
103
- getEditorContainerWidth: GetEditorContainerWidth;
104
- getEditorFeatureFlags?: GetEditorFeatureFlags;
73
+ editorView: EditorView;
74
+ isOpen: boolean;
75
+ selectionRect: Rect;
76
+ targetCellPosition?: number; // We keep this because we need to know when to rerender
77
+ mountPoint?: HTMLElement;
78
+ allowMergeCells?: boolean;
79
+ allowColumnSorting?: boolean;
80
+ allowBackgroundColor?: boolean;
81
+ boundariesElement?: HTMLElement;
82
+ offset?: Array<number>;
83
+ editorAnalyticsAPI?: EditorAnalyticsAPI;
84
+ getEditorContainerWidth: GetEditorContainerWidth;
85
+ getEditorFeatureFlags?: GetEditorFeatureFlags;
105
86
  }
106
87
 
107
88
  export interface State {
108
- isSubmenuOpen: boolean;
89
+ isSubmenuOpen: boolean;
109
90
  }
110
91
 
111
- export class ContextualMenu extends Component<
112
- Props & WrappedComponentProps,
113
- State
114
- > {
115
- state: State = {
116
- isSubmenuOpen: false,
117
- };
118
-
119
- static defaultProps = {
120
- boundariesElement:
121
- typeof document !== 'undefined' ? document.body : undefined,
122
- };
123
-
124
- render() {
125
- const { isOpen, mountPoint, offset, boundariesElement, editorView } =
126
- this.props;
127
- const { isDragAndDropEnabled } = getPluginState(editorView.state);
128
- const items = isDragAndDropEnabled
129
- ? this.createNewContextMenuItems()
130
- : this.createOriginalContextMenuItems();
131
-
132
- return (
133
- <div
134
- data-testid="table-cell-contextual-menu"
135
- onMouseLeave={this.closeSubmenu}
136
- >
137
- <DropdownMenu
138
- mountTo={mountPoint}
139
- //This needs be removed when the a11y is completely handled
140
- //Disabling key navigation now as it works only partially
141
- arrowKeyNavigationProviderOptions={{
142
- type: ArrowKeyNavigationType.MENU,
143
- disableArrowKeyNavigation: true,
144
- }}
145
- items={items}
146
- isOpen={isOpen}
147
- onOpenChange={this.handleOpenChange}
148
- onItemActivated={this.onMenuItemActivated}
149
- onMouseEnter={this.handleItemMouseEnter}
150
- onMouseLeave={this.handleItemMouseLeave}
151
- fitHeight={188}
152
- fitWidth={
153
- isDragAndDropEnabled
154
- ? contextualMenuDropdownWidthDnD
155
- : contextualMenuDropdownWidth
156
- }
157
- boundariesElement={boundariesElement}
158
- offset={offset}
159
- section={isDragAndDropEnabled ? { hasSeparator: true } : undefined}
160
- />
161
- </div>
162
- );
163
- }
164
-
165
- private handleSubMenuRef = (ref: HTMLDivElement | null) => {
166
- const parent = closestElement(
167
- this.props.editorView.dom as HTMLElement,
168
- '.fabric-editor-popup-scroll-parent',
169
- );
170
- if (!(parent && ref)) {
171
- return;
172
- }
173
- const boundariesRect = parent.getBoundingClientRect();
174
- const rect = ref.getBoundingClientRect();
175
- if (rect.left + rect.width > boundariesRect.width) {
176
- ref.style.left = `-${rect.width}px`;
177
- }
178
- };
179
-
180
- private createBackgroundColorItem = () => {
181
- const {
182
- allowBackgroundColor,
183
- editorView: { state },
184
- isOpen,
185
- intl: { formatMessage },
186
- editorView,
187
- } = this.props;
188
- const { isSubmenuOpen } = this.state;
189
- const { targetCellPosition, isDragAndDropEnabled } = getPluginState(
190
- editorView.state,
191
- );
192
-
193
- if (allowBackgroundColor) {
194
- const node =
195
- isOpen && targetCellPosition
196
- ? state.doc.nodeAt(targetCellPosition)
197
- : null;
198
- const background = hexToEditorBackgroundPaletteColor(
199
- node?.attrs?.background || '#ffffff',
200
- );
201
- return {
202
- content: isDragAndDropEnabled
203
- ? formatMessage(messages.backgroundColor)
204
- : formatMessage(messages.cellBackground),
205
- value: { name: 'background' },
206
- elemBefore: isDragAndDropEnabled ? (
207
- <span css={elementBeforeIconStyles}>
208
- <EditorBackgroundColorIcon
209
- label={formatMessage(messages.backgroundColor)}
210
- size="medium"
211
- />
212
- </span>
213
- ) : undefined,
214
- elemAfter: (
215
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
216
- <div className={DropdownMenuSharedCssClassName.SUBMENU}>
217
- <div
218
- css={cellColourPreviewStyles(background)}
219
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
220
- className={
221
- isDragAndDropEnabled
222
- ? ClassName.CONTEXTUAL_MENU_ICON_SMALL
223
- : ClassName.CONTEXTUAL_MENU_ICON
224
- }
225
- />
226
- {isSubmenuOpen && (
227
- <div
228
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
229
- className={ClassName.CONTEXTUAL_SUBMENU}
230
- ref={this.handleSubMenuRef}
231
- >
232
- <ColorPalette
233
- cols={7}
234
- onClick={this.setColor}
235
- selectedColor={node?.attrs?.background || '#ffffff'}
236
- paletteOptions={{
237
- palette: cellBackgroundColorPalette,
238
- paletteColorTooltipMessages:
239
- backgroundPaletteTooltipMessages,
240
- hexToPaletteColor: hexToEditorBackgroundPaletteColor,
241
- }}
242
- />
243
- </div>
244
- )}
245
- </div>
246
- ),
247
- } as MenuItem;
248
- }
249
- };
250
-
251
- private createMergeSplitCellItems = () => {
252
- const {
253
- allowMergeCells,
254
- editorView: { state },
255
- intl: { formatMessage },
256
- editorView,
257
- } = this.props;
258
- const { isDragAndDropEnabled } = getPluginState(editorView.state);
259
-
260
- if (allowMergeCells) {
261
- return [
262
- {
263
- content: formatMessage(messages.mergeCells),
264
- value: { name: 'merge' },
265
- isDisabled: !canMergeCells(state.tr),
266
- elemBefore: isDragAndDropEnabled ? (
267
- <span css={elementBeforeIconStyles}>
268
- <MergeCellsIcon />
269
- </span>
270
- ) : undefined,
271
- },
272
- {
273
- content: formatMessage(messages.splitCell),
274
- value: { name: 'split' },
275
- isDisabled: !splitCell(state),
276
- elemBefore: isDragAndDropEnabled ? (
277
- <span css={elementBeforeIconStyles}>
278
- <SplitCellIcon />
279
- </span>
280
- ) : undefined,
281
- },
282
- ] as MenuItem[];
283
- }
284
- return [];
285
- };
286
-
287
- private createInsertColumnItem = () => {
288
- const {
289
- intl: { formatMessage },
290
- editorView,
291
- } = this.props;
292
- const { isDragAndDropEnabled } = getPluginState(editorView.state);
293
-
294
- return {
295
- content: formatMessage(
296
- isDragAndDropEnabled ? messages.addColumnRight : messages.insertColumn,
297
- ),
298
- value: { name: 'insert_column' },
299
- elemAfter: <div css={shortcutStyle}>{tooltip(addColumnAfter)}</div>,
300
- elemBefore: isDragAndDropEnabled ? (
301
- <span css={elementBeforeIconStyles}>
302
- <AddColRightIcon />
303
- </span>
304
- ) : undefined,
305
- } as MenuItem;
306
- };
307
-
308
- private createInsertRowItem = () => {
309
- const {
310
- intl: { formatMessage },
311
- editorView,
312
- } = this.props;
313
- const { isDragAndDropEnabled } = getPluginState(editorView.state);
314
-
315
- return {
316
- content: formatMessage(
317
- isDragAndDropEnabled ? messages.addRowBelow : messages.insertRow,
318
- ),
319
- value: { name: 'insert_row' },
320
- elemAfter: <div css={shortcutStyle}>{tooltip(addRowAfter)}</div>,
321
- elemBefore: isDragAndDropEnabled ? (
322
- <span css={elementBeforeIconStyles}>
323
- <AddRowBelowIcon />
324
- </span>
325
- ) : undefined,
326
- } as MenuItem;
327
- };
328
-
329
- private createClearCellsItem = () => {
330
- const {
331
- selectionRect,
332
- intl: { formatMessage },
333
- editorView,
334
- } = this.props;
335
- const { isDragAndDropEnabled } = getPluginState(editorView.state);
336
- const { top, bottom, right, left } = selectionRect;
337
- const noOfColumns = right - left;
338
- const noOfRows = bottom - top;
339
-
340
- return {
341
- content: formatMessage(messages.clearCells, {
342
- 0: Math.max(noOfColumns, noOfRows),
343
- }),
344
- value: { name: 'clear' },
345
- elemAfter: <div css={shortcutStyle}>{tooltip(backspace)}</div>,
346
- elemBefore: isDragAndDropEnabled ? (
347
- <span css={elementBeforeIconStyles}>
348
- <CrossCircleIcon
349
- label={formatMessage(messages.clearCells, {
350
- 0: Math.max(noOfColumns, noOfRows),
351
- })}
352
- />
353
- </span>
354
- ) : undefined,
355
- } as MenuItem;
356
- };
357
-
358
- private createDeleteColumnItem = () => {
359
- const {
360
- selectionRect,
361
- intl: { formatMessage },
362
- editorView,
363
- } = this.props;
364
- const { isDragAndDropEnabled } = getPluginState(editorView.state);
365
-
366
- const { right, left } = selectionRect;
367
- const noOfColumns = right - left;
368
-
369
- return {
370
- content: formatMessage(messages.removeColumns, {
371
- 0: noOfColumns,
372
- }),
373
- value: { name: 'delete_column' },
374
- elemBefore: isDragAndDropEnabled ? (
375
- <span css={elementBeforeIconStyles}>
376
- <RemoveIcon
377
- label={formatMessage(messages.removeColumns, {
378
- 0: noOfColumns,
379
- })}
380
- />
381
- </span>
382
- ) : undefined,
383
- } as MenuItem;
384
- };
385
-
386
- private createDeleteRowItem = () => {
387
- const {
388
- selectionRect,
389
- intl: { formatMessage },
390
- editorView,
391
- } = this.props;
392
- const { isDragAndDropEnabled } = getPluginState(editorView.state);
393
-
394
- const { bottom, top } = selectionRect;
395
- const noOfRows = bottom - top;
396
-
397
- return {
398
- content: formatMessage(messages.removeRows, {
399
- 0: noOfRows,
400
- }),
401
- value: { name: 'delete_row' },
402
- elemBefore: isDragAndDropEnabled ? (
403
- <span css={elementBeforeIconStyles}>
404
- <RemoveIcon
405
- label={formatMessage(messages.removeRows, {
406
- 0: noOfRows,
407
- })}
408
- />
409
- </span>
410
- ) : undefined,
411
- } as MenuItem;
412
- };
413
-
414
- private createDistributeColumnsItem = () => {
415
- const {
416
- selectionRect,
417
- intl: { formatMessage },
418
- editorView,
419
- getEditorContainerWidth,
420
- } = this.props;
421
- const {
422
- isDragAndDropEnabled,
423
- pluginConfig: { allowDistributeColumns },
424
- } = getPluginState(editorView.state);
425
- if (allowDistributeColumns && !isDragAndDropEnabled) {
426
- const { isTableScalingEnabled = false } = getPluginState(
427
- editorView.state,
428
- );
429
- const newResizeState = getNewResizeStateFromSelectedColumns(
430
- selectionRect,
431
- editorView.state,
432
- editorView.domAtPos.bind(editorView),
433
- getEditorContainerWidth,
434
- isTableScalingEnabled,
435
- );
436
-
437
- const wouldChange = newResizeState?.changed ?? false;
438
-
439
- return {
440
- content: formatMessage(messages.distributeColumns),
441
- value: { name: 'distribute_columns' },
442
- isDisabled: !wouldChange,
443
- } as MenuItem;
444
- }
445
- return null;
446
- };
447
-
448
- private createSortColumnItems = () => {
449
- const {
450
- intl: { formatMessage },
451
- editorView,
452
- allowColumnSorting,
453
- } = this.props;
454
- const { isDragAndDropEnabled } = getPluginState(editorView.state);
455
-
456
- if (allowColumnSorting && !isDragAndDropEnabled) {
457
- const hasMergedCellsInTable =
458
- getMergedCellsPositions(editorView.state.tr).length > 0;
459
- const warning = hasMergedCellsInTable
460
- ? {
461
- tooltipDescription: formatMessage(messages.canNotSortTable),
462
- isDisabled: true,
463
- }
464
- : {};
465
-
466
- return [
467
- {
468
- content: formatMessage(messages.sortColumnASC),
469
- value: { name: 'sort_column_asc' },
470
- ...warning,
471
- },
472
- {
473
- content: formatMessage(messages.sortColumnDESC),
474
- value: { name: 'sort_column_desc' },
475
- ...warning,
476
- },
477
- ] as MenuItem[];
478
- }
479
-
480
- return null;
481
- };
482
-
483
- private createOriginalContextMenuItems = () => {
484
- let items: MenuItem[] = [];
485
- const backgroundColorItem = this.createBackgroundColorItem();
486
- backgroundColorItem && items.push(backgroundColorItem);
487
-
488
- items.push(this.createInsertColumnItem());
489
-
490
- items.push(this.createInsertRowItem());
491
-
492
- items.push(this.createDeleteColumnItem());
493
-
494
- items.push(this.createDeleteRowItem());
495
-
496
- items.push(...this.createMergeSplitCellItems());
497
-
498
- const distributeColumnsItem = this.createDistributeColumnsItem();
499
- distributeColumnsItem && items.push(distributeColumnsItem);
500
-
501
- const sortColumnItems = this.createSortColumnItems();
502
- sortColumnItems && items.push(...sortColumnItems);
503
-
504
- items.push(this.createClearCellsItem());
505
-
506
- return [{ items }];
507
- };
508
-
509
- private createNewContextMenuItems = () => {
510
- const backgroundColorItem = this.createBackgroundColorItem();
511
- const mergeSplitCellItems = this.createMergeSplitCellItems();
512
- const insertColumnItem = this.createInsertColumnItem();
513
- const insertRowItem = this.createInsertRowItem();
514
- const clearCellsItem = this.createClearCellsItem();
515
- const deleteColumnItem = this.createDeleteColumnItem();
516
- const deleteRowItem = this.createDeleteRowItem();
517
-
518
- // Group items so when table.menu.group-items FF is enabled, a divider shows under split cell, above add column
519
- let items: { items: MenuItem[] }[] = [
520
- {
521
- items: [],
522
- },
523
- {
524
- items: [],
525
- },
526
- ];
527
-
528
- backgroundColorItem && items[0].items.push(backgroundColorItem);
529
- items[0].items.push(...mergeSplitCellItems);
530
- items[1].items.push(insertColumnItem);
531
- items[1].items.push(insertRowItem);
532
- items[1].items.push(clearCellsItem);
533
- items[1].items.push(deleteColumnItem);
534
- items[1].items.push(deleteRowItem);
535
-
536
- return items;
537
- };
538
-
539
- private onMenuItemActivated = ({ item }: { item: DropdownItem }) => {
540
- const {
541
- editorView,
542
- selectionRect,
543
- editorAnalyticsAPI,
544
- getEditorContainerWidth,
545
- getEditorFeatureFlags,
546
- } = this.props;
547
- // TargetCellPosition could be outdated: https://product-fabric.atlassian.net/browse/ED-8129
548
- const { state, dispatch } = editorView;
549
- const { targetCellPosition, isTableScalingEnabled = false } =
550
- getPluginState(state);
551
-
552
- const { tableDuplicateCellColouring = false } = getEditorFeatureFlags
553
- ? getEditorFeatureFlags()
554
- : {};
555
-
556
- switch (item.value.name) {
557
- case 'sort_column_desc':
558
- sortColumnWithAnalytics(editorAnalyticsAPI)(
559
- INPUT_METHOD.CONTEXT_MENU,
560
- selectionRect.left,
561
- SortOrder.DESC,
562
- )(state, dispatch);
563
- this.toggleOpen();
564
- break;
565
- case 'sort_column_asc':
566
- sortColumnWithAnalytics(editorAnalyticsAPI)(
567
- INPUT_METHOD.CONTEXT_MENU,
568
- selectionRect.left,
569
- SortOrder.ASC,
570
- )(state, dispatch);
571
- this.toggleOpen();
572
- break;
573
- case 'merge':
574
- mergeCellsWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.CONTEXT_MENU)(
575
- state,
576
- dispatch,
577
- );
578
- this.toggleOpen();
579
- break;
580
- case 'split':
581
- splitCellWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.CONTEXT_MENU)(
582
- state,
583
- dispatch,
584
- );
585
- this.toggleOpen();
586
- break;
587
- case 'distribute_columns':
588
- const newResizeStateWithAnalytics =
589
- getNewResizeStateFromSelectedColumns(
590
- selectionRect,
591
- state,
592
- editorView.domAtPos.bind(editorView),
593
- getEditorContainerWidth,
594
- isTableScalingEnabled,
595
- );
596
-
597
- if (newResizeStateWithAnalytics) {
598
- distributeColumnsWidthsWithAnalytics(editorAnalyticsAPI)(
599
- INPUT_METHOD.CONTEXT_MENU,
600
- newResizeStateWithAnalytics,
601
- )(state, dispatch);
602
- this.toggleOpen();
603
- }
604
- break;
605
- case 'clear':
606
- emptyMultipleCellsWithAnalytics(editorAnalyticsAPI)(
607
- INPUT_METHOD.CONTEXT_MENU,
608
- targetCellPosition,
609
- )(state, dispatch);
610
- this.toggleOpen();
611
- break;
612
- case 'insert_column':
613
- insertColumnWithAnalytics(
614
- editorAnalyticsAPI,
615
- isTableScalingEnabled,
616
- tableDuplicateCellColouring,
617
- )(INPUT_METHOD.CONTEXT_MENU, selectionRect.right)(
618
- state,
619
- dispatch,
620
- editorView,
621
- );
622
- this.toggleOpen();
623
- break;
624
- case 'insert_row':
625
- insertRowWithAnalytics(editorAnalyticsAPI, tableDuplicateCellColouring)(
626
- INPUT_METHOD.CONTEXT_MENU,
627
- {
628
- index: selectionRect.bottom,
629
- moveCursorToInsertedRow: true,
630
- },
631
- )(state, dispatch);
632
- this.toggleOpen();
633
- break;
634
- case 'delete_column':
635
- deleteColumnsWithAnalytics(editorAnalyticsAPI)(
636
- INPUT_METHOD.CONTEXT_MENU,
637
- selectionRect,
638
- )(state, dispatch, editorView);
639
- this.toggleOpen();
640
- break;
641
- case 'delete_row':
642
- const {
643
- pluginConfig: { isHeaderRowRequired },
644
- } = getPluginState(state);
645
-
646
- deleteRowsWithAnalytics(editorAnalyticsAPI)(
647
- INPUT_METHOD.CONTEXT_MENU,
648
- selectionRect,
649
- !!isHeaderRowRequired,
650
- )(state, dispatch);
651
- this.toggleOpen();
652
- break;
653
- }
654
- };
655
-
656
- private toggleOpen = () => {
657
- const {
658
- isOpen,
659
- editorView: { state, dispatch },
660
- } = this.props;
661
- toggleContextualMenu()(state, dispatch);
662
- if (!isOpen) {
663
- this.setState({
664
- isSubmenuOpen: false,
665
- });
666
- }
667
- };
668
-
669
- private handleOpenChange = () => {
670
- const {
671
- editorView: { state, dispatch },
672
- } = this.props;
673
- toggleContextualMenu()(state, dispatch);
674
- this.setState({ isSubmenuOpen: false });
675
- };
676
-
677
- private handleItemMouseEnter = ({ item }: { item: any }) => {
678
- const {
679
- editorView: { state, dispatch },
680
- selectionRect,
681
- } = this.props;
682
-
683
- if (item.value.name === 'background') {
684
- if (!this.state.isSubmenuOpen) {
685
- this.setState({ isSubmenuOpen: true });
686
- }
687
- }
688
-
689
- if (item.value.name === 'delete_column') {
690
- hoverColumns(getSelectedColumnIndexes(selectionRect), true)(
691
- state,
692
- dispatch,
693
- );
694
- }
695
-
696
- if (item.value.name === 'delete_row') {
697
- hoverRows(getSelectedRowIndexes(selectionRect), true)(state, dispatch);
698
- }
699
-
700
- if (
701
- ['sort_column_asc', 'sort_column_desc'].indexOf(item.value.name) > -1 &&
702
- getMergedCellsPositions(state.tr).length !== 0
703
- ) {
704
- hoverMergedCells()(state, dispatch);
705
- }
706
- };
707
-
708
- private handleItemMouseLeave = ({ item }: { item: any }) => {
709
- const { state, dispatch } = this.props.editorView;
710
- if (item.value.name === 'background') {
711
- this.closeSubmenu();
712
- }
713
- if (
714
- [
715
- 'sort_column_asc',
716
- 'sort_column_desc',
717
- 'delete_column',
718
- 'delete_row',
719
- ].indexOf(item.value.name) > -1
720
- ) {
721
- clearHoverSelection()(state, dispatch);
722
- }
723
- };
724
-
725
- private closeSubmenu = () => {
726
- if (this.state.isSubmenuOpen) {
727
- this.setState({ isSubmenuOpen: false });
728
- }
729
- };
730
-
731
- private setColor = (color: string) => {
732
- const { editorView, editorAnalyticsAPI } = this.props;
733
- // TargetCellPosition could be outdated: https://product-fabric.atlassian.net/browse/ED-8129
734
- const { targetCellPosition } = getPluginState(editorView.state);
735
- const { state, dispatch } = editorView;
736
- setColorWithAnalytics(editorAnalyticsAPI)(
737
- INPUT_METHOD.CONTEXT_MENU,
738
- color,
739
- targetCellPosition,
740
- )(state, dispatch);
741
- this.toggleOpen();
742
- };
92
+ export class ContextualMenu extends Component<Props & WrappedComponentProps, State> {
93
+ state: State = {
94
+ isSubmenuOpen: false,
95
+ };
96
+
97
+ static defaultProps = {
98
+ boundariesElement: typeof document !== 'undefined' ? document.body : undefined,
99
+ };
100
+
101
+ render() {
102
+ const { isOpen, mountPoint, offset, boundariesElement, editorView } = this.props;
103
+ const { isDragAndDropEnabled } = getPluginState(editorView.state);
104
+ const items = isDragAndDropEnabled
105
+ ? this.createNewContextMenuItems()
106
+ : this.createOriginalContextMenuItems();
107
+
108
+ return (
109
+ <div data-testid="table-cell-contextual-menu" onMouseLeave={this.closeSubmenu}>
110
+ <DropdownMenu
111
+ mountTo={mountPoint}
112
+ //This needs be removed when the a11y is completely handled
113
+ //Disabling key navigation now as it works only partially
114
+ arrowKeyNavigationProviderOptions={{
115
+ type: ArrowKeyNavigationType.MENU,
116
+ disableArrowKeyNavigation: true,
117
+ }}
118
+ items={items}
119
+ isOpen={isOpen}
120
+ onOpenChange={this.handleOpenChange}
121
+ onItemActivated={this.onMenuItemActivated}
122
+ onMouseEnter={this.handleItemMouseEnter}
123
+ onMouseLeave={this.handleItemMouseLeave}
124
+ fitHeight={188}
125
+ fitWidth={
126
+ isDragAndDropEnabled ? contextualMenuDropdownWidthDnD : contextualMenuDropdownWidth
127
+ }
128
+ boundariesElement={boundariesElement}
129
+ offset={offset}
130
+ section={isDragAndDropEnabled ? { hasSeparator: true } : undefined}
131
+ />
132
+ </div>
133
+ );
134
+ }
135
+
136
+ private handleSubMenuRef = (ref: HTMLDivElement | null) => {
137
+ const parent = closestElement(
138
+ this.props.editorView.dom as HTMLElement,
139
+ '.fabric-editor-popup-scroll-parent',
140
+ );
141
+ if (!(parent && ref)) {
142
+ return;
143
+ }
144
+ const boundariesRect = parent.getBoundingClientRect();
145
+ const rect = ref.getBoundingClientRect();
146
+ if (rect.left + rect.width > boundariesRect.width) {
147
+ ref.style.left = `-${rect.width}px`;
148
+ }
149
+ };
150
+
151
+ private createBackgroundColorItem = () => {
152
+ const {
153
+ allowBackgroundColor,
154
+ editorView: { state },
155
+ isOpen,
156
+ intl: { formatMessage },
157
+ editorView,
158
+ } = this.props;
159
+ const { isSubmenuOpen } = this.state;
160
+ const { targetCellPosition, isDragAndDropEnabled } = getPluginState(editorView.state);
161
+
162
+ if (allowBackgroundColor) {
163
+ const node = isOpen && targetCellPosition ? state.doc.nodeAt(targetCellPosition) : null;
164
+ const background = hexToEditorBackgroundPaletteColor(node?.attrs?.background || '#ffffff');
165
+ return {
166
+ content: isDragAndDropEnabled
167
+ ? formatMessage(messages.backgroundColor)
168
+ : formatMessage(messages.cellBackground),
169
+ value: { name: 'background' },
170
+ elemBefore: isDragAndDropEnabled ? (
171
+ <span css={elementBeforeIconStyles}>
172
+ <EditorBackgroundColorIcon
173
+ label={formatMessage(messages.backgroundColor)}
174
+ size="medium"
175
+ />
176
+ </span>
177
+ ) : undefined,
178
+ elemAfter: (
179
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
180
+ <div className={DropdownMenuSharedCssClassName.SUBMENU}>
181
+ <div
182
+ css={cellColourPreviewStyles(background)}
183
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
184
+ className={
185
+ isDragAndDropEnabled
186
+ ? ClassName.CONTEXTUAL_MENU_ICON_SMALL
187
+ : ClassName.CONTEXTUAL_MENU_ICON
188
+ }
189
+ />
190
+ {isSubmenuOpen && (
191
+ <div
192
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
193
+ className={ClassName.CONTEXTUAL_SUBMENU}
194
+ ref={this.handleSubMenuRef}
195
+ >
196
+ <ColorPalette
197
+ cols={7}
198
+ onClick={this.setColor}
199
+ selectedColor={node?.attrs?.background || '#ffffff'}
200
+ paletteOptions={{
201
+ palette: cellBackgroundColorPalette,
202
+ paletteColorTooltipMessages: backgroundPaletteTooltipMessages,
203
+ hexToPaletteColor: hexToEditorBackgroundPaletteColor,
204
+ }}
205
+ />
206
+ </div>
207
+ )}
208
+ </div>
209
+ ),
210
+ } as MenuItem;
211
+ }
212
+ };
213
+
214
+ private createMergeSplitCellItems = () => {
215
+ const {
216
+ allowMergeCells,
217
+ editorView: { state },
218
+ intl: { formatMessage },
219
+ editorView,
220
+ } = this.props;
221
+ const { isDragAndDropEnabled } = getPluginState(editorView.state);
222
+
223
+ if (allowMergeCells) {
224
+ return [
225
+ {
226
+ content: formatMessage(messages.mergeCells),
227
+ value: { name: 'merge' },
228
+ isDisabled: !canMergeCells(state.tr),
229
+ elemBefore: isDragAndDropEnabled ? (
230
+ <span css={elementBeforeIconStyles}>
231
+ <MergeCellsIcon />
232
+ </span>
233
+ ) : undefined,
234
+ },
235
+ {
236
+ content: formatMessage(messages.splitCell),
237
+ value: { name: 'split' },
238
+ isDisabled: !splitCell(state),
239
+ elemBefore: isDragAndDropEnabled ? (
240
+ <span css={elementBeforeIconStyles}>
241
+ <SplitCellIcon />
242
+ </span>
243
+ ) : undefined,
244
+ },
245
+ ] as MenuItem[];
246
+ }
247
+ return [];
248
+ };
249
+
250
+ private createInsertColumnItem = () => {
251
+ const {
252
+ intl: { formatMessage },
253
+ editorView,
254
+ } = this.props;
255
+ const { isDragAndDropEnabled } = getPluginState(editorView.state);
256
+
257
+ return {
258
+ content: formatMessage(
259
+ isDragAndDropEnabled ? messages.addColumnRight : messages.insertColumn,
260
+ ),
261
+ value: { name: 'insert_column' },
262
+ elemAfter: <div css={shortcutStyle}>{tooltip(addColumnAfter)}</div>,
263
+ elemBefore: isDragAndDropEnabled ? (
264
+ <span css={elementBeforeIconStyles}>
265
+ <AddColRightIcon />
266
+ </span>
267
+ ) : undefined,
268
+ } as MenuItem;
269
+ };
270
+
271
+ private createInsertRowItem = () => {
272
+ const {
273
+ intl: { formatMessage },
274
+ editorView,
275
+ } = this.props;
276
+ const { isDragAndDropEnabled } = getPluginState(editorView.state);
277
+
278
+ return {
279
+ content: formatMessage(isDragAndDropEnabled ? messages.addRowBelow : messages.insertRow),
280
+ value: { name: 'insert_row' },
281
+ elemAfter: <div css={shortcutStyle}>{tooltip(addRowAfter)}</div>,
282
+ elemBefore: isDragAndDropEnabled ? (
283
+ <span css={elementBeforeIconStyles}>
284
+ <AddRowBelowIcon />
285
+ </span>
286
+ ) : undefined,
287
+ } as MenuItem;
288
+ };
289
+
290
+ private createClearCellsItem = () => {
291
+ const {
292
+ selectionRect,
293
+ intl: { formatMessage },
294
+ editorView,
295
+ } = this.props;
296
+ const { isDragAndDropEnabled } = getPluginState(editorView.state);
297
+ const { top, bottom, right, left } = selectionRect;
298
+ const noOfColumns = right - left;
299
+ const noOfRows = bottom - top;
300
+
301
+ return {
302
+ content: formatMessage(messages.clearCells, {
303
+ 0: Math.max(noOfColumns, noOfRows),
304
+ }),
305
+ value: { name: 'clear' },
306
+ elemAfter: <div css={shortcutStyle}>{tooltip(backspace)}</div>,
307
+ elemBefore: isDragAndDropEnabled ? (
308
+ <span css={elementBeforeIconStyles}>
309
+ <CrossCircleIcon
310
+ label={formatMessage(messages.clearCells, {
311
+ 0: Math.max(noOfColumns, noOfRows),
312
+ })}
313
+ />
314
+ </span>
315
+ ) : undefined,
316
+ } as MenuItem;
317
+ };
318
+
319
+ private createDeleteColumnItem = () => {
320
+ const {
321
+ selectionRect,
322
+ intl: { formatMessage },
323
+ editorView,
324
+ } = this.props;
325
+ const { isDragAndDropEnabled } = getPluginState(editorView.state);
326
+
327
+ const { right, left } = selectionRect;
328
+ const noOfColumns = right - left;
329
+
330
+ return {
331
+ content: formatMessage(messages.removeColumns, {
332
+ 0: noOfColumns,
333
+ }),
334
+ value: { name: 'delete_column' },
335
+ elemBefore: isDragAndDropEnabled ? (
336
+ <span css={elementBeforeIconStyles}>
337
+ <RemoveIcon
338
+ label={formatMessage(messages.removeColumns, {
339
+ 0: noOfColumns,
340
+ })}
341
+ />
342
+ </span>
343
+ ) : undefined,
344
+ } as MenuItem;
345
+ };
346
+
347
+ private createDeleteRowItem = () => {
348
+ const {
349
+ selectionRect,
350
+ intl: { formatMessage },
351
+ editorView,
352
+ } = this.props;
353
+ const { isDragAndDropEnabled } = getPluginState(editorView.state);
354
+
355
+ const { bottom, top } = selectionRect;
356
+ const noOfRows = bottom - top;
357
+
358
+ return {
359
+ content: formatMessage(messages.removeRows, {
360
+ 0: noOfRows,
361
+ }),
362
+ value: { name: 'delete_row' },
363
+ elemBefore: isDragAndDropEnabled ? (
364
+ <span css={elementBeforeIconStyles}>
365
+ <RemoveIcon
366
+ label={formatMessage(messages.removeRows, {
367
+ 0: noOfRows,
368
+ })}
369
+ />
370
+ </span>
371
+ ) : undefined,
372
+ } as MenuItem;
373
+ };
374
+
375
+ private createDistributeColumnsItem = () => {
376
+ const {
377
+ selectionRect,
378
+ intl: { formatMessage },
379
+ editorView,
380
+ getEditorContainerWidth,
381
+ } = this.props;
382
+ const {
383
+ isDragAndDropEnabled,
384
+ pluginConfig: { allowDistributeColumns },
385
+ } = getPluginState(editorView.state);
386
+ if (allowDistributeColumns && !isDragAndDropEnabled) {
387
+ const { isTableScalingEnabled = false } = getPluginState(editorView.state);
388
+ const newResizeState = getNewResizeStateFromSelectedColumns(
389
+ selectionRect,
390
+ editorView.state,
391
+ editorView.domAtPos.bind(editorView),
392
+ getEditorContainerWidth,
393
+ isTableScalingEnabled,
394
+ );
395
+
396
+ const wouldChange = newResizeState?.changed ?? false;
397
+
398
+ return {
399
+ content: formatMessage(messages.distributeColumns),
400
+ value: { name: 'distribute_columns' },
401
+ isDisabled: !wouldChange,
402
+ } as MenuItem;
403
+ }
404
+ return null;
405
+ };
406
+
407
+ private createSortColumnItems = () => {
408
+ const {
409
+ intl: { formatMessage },
410
+ editorView,
411
+ allowColumnSorting,
412
+ } = this.props;
413
+ const { isDragAndDropEnabled } = getPluginState(editorView.state);
414
+
415
+ if (allowColumnSorting && !isDragAndDropEnabled) {
416
+ const hasMergedCellsInTable = getMergedCellsPositions(editorView.state.tr).length > 0;
417
+ const warning = hasMergedCellsInTable
418
+ ? {
419
+ tooltipDescription: formatMessage(messages.canNotSortTable),
420
+ isDisabled: true,
421
+ }
422
+ : {};
423
+
424
+ return [
425
+ {
426
+ content: formatMessage(messages.sortColumnASC),
427
+ value: { name: 'sort_column_asc' },
428
+ ...warning,
429
+ },
430
+ {
431
+ content: formatMessage(messages.sortColumnDESC),
432
+ value: { name: 'sort_column_desc' },
433
+ ...warning,
434
+ },
435
+ ] as MenuItem[];
436
+ }
437
+
438
+ return null;
439
+ };
440
+
441
+ private createOriginalContextMenuItems = () => {
442
+ let items: MenuItem[] = [];
443
+ const backgroundColorItem = this.createBackgroundColorItem();
444
+ backgroundColorItem && items.push(backgroundColorItem);
445
+
446
+ items.push(this.createInsertColumnItem());
447
+
448
+ items.push(this.createInsertRowItem());
449
+
450
+ items.push(this.createDeleteColumnItem());
451
+
452
+ items.push(this.createDeleteRowItem());
453
+
454
+ items.push(...this.createMergeSplitCellItems());
455
+
456
+ const distributeColumnsItem = this.createDistributeColumnsItem();
457
+ distributeColumnsItem && items.push(distributeColumnsItem);
458
+
459
+ const sortColumnItems = this.createSortColumnItems();
460
+ sortColumnItems && items.push(...sortColumnItems);
461
+
462
+ items.push(this.createClearCellsItem());
463
+
464
+ return [{ items }];
465
+ };
466
+
467
+ private createNewContextMenuItems = () => {
468
+ const backgroundColorItem = this.createBackgroundColorItem();
469
+ const mergeSplitCellItems = this.createMergeSplitCellItems();
470
+ const insertColumnItem = this.createInsertColumnItem();
471
+ const insertRowItem = this.createInsertRowItem();
472
+ const clearCellsItem = this.createClearCellsItem();
473
+ const deleteColumnItem = this.createDeleteColumnItem();
474
+ const deleteRowItem = this.createDeleteRowItem();
475
+
476
+ // Group items so when table.menu.group-items FF is enabled, a divider shows under split cell, above add column
477
+ let items: { items: MenuItem[] }[] = [
478
+ {
479
+ items: [],
480
+ },
481
+ {
482
+ items: [],
483
+ },
484
+ ];
485
+
486
+ backgroundColorItem && items[0].items.push(backgroundColorItem);
487
+ items[0].items.push(...mergeSplitCellItems);
488
+ items[1].items.push(insertColumnItem);
489
+ items[1].items.push(insertRowItem);
490
+ items[1].items.push(clearCellsItem);
491
+ items[1].items.push(deleteColumnItem);
492
+ items[1].items.push(deleteRowItem);
493
+
494
+ return items;
495
+ };
496
+
497
+ private onMenuItemActivated = ({ item }: { item: DropdownItem }) => {
498
+ const {
499
+ editorView,
500
+ selectionRect,
501
+ editorAnalyticsAPI,
502
+ getEditorContainerWidth,
503
+ getEditorFeatureFlags,
504
+ } = this.props;
505
+ // TargetCellPosition could be outdated: https://product-fabric.atlassian.net/browse/ED-8129
506
+ const { state, dispatch } = editorView;
507
+ const { targetCellPosition, isTableScalingEnabled = false } = getPluginState(state);
508
+
509
+ const { tableDuplicateCellColouring = false } = getEditorFeatureFlags
510
+ ? getEditorFeatureFlags()
511
+ : {};
512
+
513
+ switch (item.value.name) {
514
+ case 'sort_column_desc':
515
+ sortColumnWithAnalytics(editorAnalyticsAPI)(
516
+ INPUT_METHOD.CONTEXT_MENU,
517
+ selectionRect.left,
518
+ SortOrder.DESC,
519
+ )(state, dispatch);
520
+ this.toggleOpen();
521
+ break;
522
+ case 'sort_column_asc':
523
+ sortColumnWithAnalytics(editorAnalyticsAPI)(
524
+ INPUT_METHOD.CONTEXT_MENU,
525
+ selectionRect.left,
526
+ SortOrder.ASC,
527
+ )(state, dispatch);
528
+ this.toggleOpen();
529
+ break;
530
+ case 'merge':
531
+ mergeCellsWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.CONTEXT_MENU)(state, dispatch);
532
+ this.toggleOpen();
533
+ break;
534
+ case 'split':
535
+ splitCellWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.CONTEXT_MENU)(state, dispatch);
536
+ this.toggleOpen();
537
+ break;
538
+ case 'distribute_columns':
539
+ const newResizeStateWithAnalytics = getNewResizeStateFromSelectedColumns(
540
+ selectionRect,
541
+ state,
542
+ editorView.domAtPos.bind(editorView),
543
+ getEditorContainerWidth,
544
+ isTableScalingEnabled,
545
+ );
546
+
547
+ if (newResizeStateWithAnalytics) {
548
+ distributeColumnsWidthsWithAnalytics(editorAnalyticsAPI)(
549
+ INPUT_METHOD.CONTEXT_MENU,
550
+ newResizeStateWithAnalytics,
551
+ )(state, dispatch);
552
+ this.toggleOpen();
553
+ }
554
+ break;
555
+ case 'clear':
556
+ emptyMultipleCellsWithAnalytics(editorAnalyticsAPI)(
557
+ INPUT_METHOD.CONTEXT_MENU,
558
+ targetCellPosition,
559
+ )(state, dispatch);
560
+ this.toggleOpen();
561
+ break;
562
+ case 'insert_column':
563
+ insertColumnWithAnalytics(
564
+ editorAnalyticsAPI,
565
+ isTableScalingEnabled,
566
+ tableDuplicateCellColouring,
567
+ )(INPUT_METHOD.CONTEXT_MENU, selectionRect.right)(state, dispatch, editorView);
568
+ this.toggleOpen();
569
+ break;
570
+ case 'insert_row':
571
+ insertRowWithAnalytics(editorAnalyticsAPI, tableDuplicateCellColouring)(
572
+ INPUT_METHOD.CONTEXT_MENU,
573
+ {
574
+ index: selectionRect.bottom,
575
+ moveCursorToInsertedRow: true,
576
+ },
577
+ )(state, dispatch);
578
+ this.toggleOpen();
579
+ break;
580
+ case 'delete_column':
581
+ deleteColumnsWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.CONTEXT_MENU, selectionRect)(
582
+ state,
583
+ dispatch,
584
+ editorView,
585
+ );
586
+ this.toggleOpen();
587
+ break;
588
+ case 'delete_row':
589
+ const {
590
+ pluginConfig: { isHeaderRowRequired },
591
+ } = getPluginState(state);
592
+
593
+ deleteRowsWithAnalytics(editorAnalyticsAPI)(
594
+ INPUT_METHOD.CONTEXT_MENU,
595
+ selectionRect,
596
+ !!isHeaderRowRequired,
597
+ )(state, dispatch);
598
+ this.toggleOpen();
599
+ break;
600
+ }
601
+ };
602
+
603
+ private toggleOpen = () => {
604
+ const {
605
+ isOpen,
606
+ editorView: { state, dispatch },
607
+ } = this.props;
608
+ toggleContextualMenu()(state, dispatch);
609
+ if (!isOpen) {
610
+ this.setState({
611
+ isSubmenuOpen: false,
612
+ });
613
+ }
614
+ };
615
+
616
+ private handleOpenChange = () => {
617
+ const {
618
+ editorView: { state, dispatch },
619
+ } = this.props;
620
+ toggleContextualMenu()(state, dispatch);
621
+ this.setState({ isSubmenuOpen: false });
622
+ };
623
+
624
+ private handleItemMouseEnter = ({ item }: { item: any }) => {
625
+ const {
626
+ editorView: { state, dispatch },
627
+ selectionRect,
628
+ } = this.props;
629
+
630
+ if (item.value.name === 'background') {
631
+ if (!this.state.isSubmenuOpen) {
632
+ this.setState({ isSubmenuOpen: true });
633
+ }
634
+ }
635
+
636
+ if (item.value.name === 'delete_column') {
637
+ hoverColumns(getSelectedColumnIndexes(selectionRect), true)(state, dispatch);
638
+ }
639
+
640
+ if (item.value.name === 'delete_row') {
641
+ hoverRows(getSelectedRowIndexes(selectionRect), true)(state, dispatch);
642
+ }
643
+
644
+ if (
645
+ ['sort_column_asc', 'sort_column_desc'].indexOf(item.value.name) > -1 &&
646
+ getMergedCellsPositions(state.tr).length !== 0
647
+ ) {
648
+ hoverMergedCells()(state, dispatch);
649
+ }
650
+ };
651
+
652
+ private handleItemMouseLeave = ({ item }: { item: any }) => {
653
+ const { state, dispatch } = this.props.editorView;
654
+ if (item.value.name === 'background') {
655
+ this.closeSubmenu();
656
+ }
657
+ if (
658
+ ['sort_column_asc', 'sort_column_desc', 'delete_column', 'delete_row'].indexOf(
659
+ item.value.name,
660
+ ) > -1
661
+ ) {
662
+ clearHoverSelection()(state, dispatch);
663
+ }
664
+ };
665
+
666
+ private closeSubmenu = () => {
667
+ if (this.state.isSubmenuOpen) {
668
+ this.setState({ isSubmenuOpen: false });
669
+ }
670
+ };
671
+
672
+ private setColor = (color: string) => {
673
+ const { editorView, editorAnalyticsAPI } = this.props;
674
+ // TargetCellPosition could be outdated: https://product-fabric.atlassian.net/browse/ED-8129
675
+ const { targetCellPosition } = getPluginState(editorView.state);
676
+ const { state, dispatch } = editorView;
677
+ setColorWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.CONTEXT_MENU, color, targetCellPosition)(
678
+ state,
679
+ dispatch,
680
+ );
681
+ this.toggleOpen();
682
+ };
743
683
  }
744
684
 
745
685
  export default injectIntl(ContextualMenu);