@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
@@ -1,12 +1,5 @@
1
1
  import type { PropsWithChildren } from 'react';
2
- import React, {
3
- useCallback,
4
- useEffect,
5
- useLayoutEffect,
6
- useMemo,
7
- useRef,
8
- useState,
9
- } from 'react';
2
+ import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
10
3
 
11
4
  import rafSchd from 'raf-schd';
12
5
  import { useIntl } from 'react-intl-next';
@@ -16,10 +9,7 @@ import { TABLE_OVERFLOW_CHANGE_TRIGGER } from '@atlaskit/editor-common/analytics
16
9
  import { getGuidelinesWithHighlights } from '@atlaskit/editor-common/guideline';
17
10
  import type { GuidelineConfig } from '@atlaskit/editor-common/guideline';
18
11
  import { useSharedPluginState } from '@atlaskit/editor-common/hooks';
19
- import {
20
- focusTableResizer,
21
- ToolTipContent,
22
- } from '@atlaskit/editor-common/keymaps';
12
+ import { focusTableResizer, ToolTipContent } from '@atlaskit/editor-common/keymaps';
23
13
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
24
14
  import type { HandleResize, HandleSize } from '@atlaskit/editor-common/resizer';
25
15
  import { ResizerNext } from '@atlaskit/editor-common/resizer';
@@ -28,74 +18,69 @@ import { chainCommands } from '@atlaskit/editor-prosemirror/commands';
28
18
  import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
29
19
  import type { Transaction } from '@atlaskit/editor-prosemirror/state';
30
20
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
21
+ import { akEditorGutterPadding } from '@atlaskit/editor-shared-styles';
31
22
  import { findTable } from '@atlaskit/editor-tables/utils';
32
23
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
33
24
  import { token } from '@atlaskit/tokens';
34
25
 
35
- import {
36
- setTableAlignmentWithTableContentWithPos,
37
- updateWidthToWidest,
38
- } from '../commands/misc';
26
+ import { setTableAlignmentWithTableContentWithPos, updateWidthToWidest } from '../commands/misc';
39
27
  import { META_KEYS } from '../pm-plugins/table-analytics';
40
28
  import {
41
- COLUMN_MIN_WIDTH,
42
- getColgroupChildrenLength,
43
- previewScaleTable,
44
- scaleTable,
45
- TABLE_MAX_WIDTH,
29
+ COLUMN_MIN_WIDTH,
30
+ getColgroupChildrenLength,
31
+ previewScaleTable,
32
+ scaleTable,
33
+ TABLE_MAX_WIDTH,
46
34
  } from '../pm-plugins/table-resizing/utils';
47
35
  import { pluginKey as tableWidthPluginKey } from '../pm-plugins/table-width';
48
36
  import type { PluginInjectionAPI, TableSharedStateInternal } from '../types';
49
37
  import {
50
- TABLE_GUIDELINE_VISIBLE_ADJUSTMENT,
51
- TABLE_HIGHLIGHT_GAP,
52
- TABLE_HIGHLIGHT_TOLERANCE,
53
- TABLE_SNAP_GAP,
38
+ TABLE_GUIDELINE_VISIBLE_ADJUSTMENT,
39
+ TABLE_HIGHLIGHT_GAP,
40
+ TABLE_HIGHLIGHT_TOLERANCE,
41
+ TABLE_SNAP_GAP,
54
42
  } from '../ui/consts';
43
+ import { ALIGN_CENTER, ALIGN_START, normaliseAlignment } from '../utils/alignment';
55
44
  import {
56
- ALIGN_CENTER,
57
- ALIGN_START,
58
- normaliseAlignment,
59
- } from '../utils/alignment';
60
- import {
61
- generateResizedPayload,
62
- generateResizeFrameRatePayloads,
63
- useMeasureFramerate,
45
+ generateResizedPayload,
46
+ generateResizeFrameRatePayloads,
47
+ useMeasureFramerate,
64
48
  } from '../utils/analytics';
65
49
  import {
66
- defaultGuidelines,
67
- defaultGuidelinesForPreserveTable,
50
+ defaultGuidelines,
51
+ defaultGuidelinesForPreserveTable,
52
+ PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET,
68
53
  } from '../utils/guidelines';
69
54
  import {
70
- defaultSnappingWidths,
71
- defaultTablePreserveSnappingWidths,
72
- findClosestSnap,
55
+ defaultSnappingWidths,
56
+ defaultTablePreserveSnappingWidths,
57
+ findClosestSnap,
58
+ PRESERVE_TABLE_SNAPPING_LENGTH_OFFSET,
73
59
  } from '../utils/snapping';
74
60
 
75
61
  interface TableResizerProps {
76
- width: number;
77
- maxWidth: number;
78
- containerWidth: number;
79
- lineLength: number;
80
- updateWidth: (width: number) => void;
81
- editorView: EditorView;
82
- getPos: () => number | undefined;
83
- node: PMNode;
84
- tableRef: HTMLTableElement;
85
- displayGuideline: (guideline: GuidelineConfig[]) => boolean;
86
- attachAnalyticsEvent: (
87
- payload: TableEventPayload,
88
- ) => ((tr: Transaction) => boolean) | undefined;
89
- displayGapCursor: (toggle: boolean) => boolean;
90
- pluginInjectionApi?: PluginInjectionAPI;
91
- isTableScalingEnabled?: boolean;
92
- isTableAlignmentEnabled?: boolean;
93
- isWholeTableInDanger?: boolean;
62
+ width: number;
63
+ maxWidth: number;
64
+ containerWidth: number;
65
+ lineLength: number;
66
+ updateWidth: (width: number) => void;
67
+ editorView: EditorView;
68
+ getPos: () => number | undefined;
69
+ node: PMNode;
70
+ tableRef: HTMLTableElement;
71
+ displayGuideline: (guideline: GuidelineConfig[]) => boolean;
72
+ attachAnalyticsEvent: (payload: TableEventPayload) => ((tr: Transaction) => boolean) | undefined;
73
+ displayGapCursor: (toggle: boolean) => boolean;
74
+ pluginInjectionApi?: PluginInjectionAPI;
75
+ isTableScalingEnabled?: boolean;
76
+ isTableAlignmentEnabled?: boolean;
77
+ isWholeTableInDanger?: boolean;
78
+ isFullWidthModeEnabled?: boolean;
94
79
  }
95
80
 
96
81
  export interface TableResizerImprovementProps extends TableResizerProps {
97
- onResizeStop?: () => void;
98
- onResizeStart?: () => void;
82
+ onResizeStop?: () => void;
83
+ onResizeStart?: () => void;
99
84
  }
100
85
 
101
86
  type ResizerNextHandler = React.ElementRef<typeof ResizerNext>;
@@ -106,18 +91,16 @@ const FULL_WIDTH_EDITOR_CONTENT_WIDTH = 1800;
106
91
 
107
92
  const handles = { right: true };
108
93
  const handleStyles = {
109
- right: {
110
- // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage/preview
111
- right: '-14px',
112
- marginTop: token('space.150', '12px'),
113
- },
94
+ right: {
95
+ // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage/preview
96
+ right: '-14px',
97
+ marginTop: token('space.150', '12px'),
98
+ },
114
99
  };
115
100
 
116
- const getResizerHandleHeight = (
117
- tableRef: HTMLTableElement | undefined,
118
- ): HandleSize | undefined => {
119
- const tableHeight = tableRef?.clientHeight ?? 0;
120
- /*
101
+ const getResizerHandleHeight = (tableRef: HTMLTableElement | undefined): HandleSize | undefined => {
102
+ const tableHeight = tableRef?.clientHeight ?? 0;
103
+ /*
121
104
  - One row table height (minimum possible table height) ~ 45px
122
105
  - Two row table height ~ 90px
123
106
  - Three row table height ~ 134px
@@ -126,23 +109,23 @@ const getResizerHandleHeight = (
126
109
  - > 46 because the height of the table can be a float number like 45.44.
127
110
  - < 96 is the height of large resize handle.
128
111
  */
129
- if (tableHeight >= 96) {
130
- return 'large';
131
- }
112
+ if (tableHeight >= 96) {
113
+ return 'large';
114
+ }
132
115
 
133
- if (tableHeight > 46) {
134
- return 'medium';
135
- }
116
+ if (tableHeight > 46) {
117
+ return 'medium';
118
+ }
136
119
 
137
- return 'small';
120
+ return 'small';
138
121
  };
139
122
 
140
123
  const getResizerMinWidth = (node: PMNode) => {
141
- const currentColumnCount = getColgroupChildrenLength(node);
142
- const minColumnWidth = Math.min(3, currentColumnCount) * COLUMN_MIN_WIDTH;
143
- // add an extra pixel as the scale table logic will scale columns to be tableContainerWidth - 1
144
- // the table can't scale past its min-width, so instead restrict table container min width to avoid that situation
145
- return minColumnWidth + 1;
124
+ const currentColumnCount = getColgroupChildrenLength(node);
125
+ const minColumnWidth = Math.min(3, currentColumnCount) * COLUMN_MIN_WIDTH;
126
+ // add an extra pixel as the scale table logic will scale columns to be tableContainerWidth - 1
127
+ // the table can't scale past its min-width, so instead restrict table container min width to avoid that situation
128
+ return minColumnWidth + 1;
146
129
  };
147
130
 
148
131
  /**
@@ -150,584 +133,590 @@ const getResizerMinWidth = (node: PMNode) => {
150
133
  * So the guideline container won't make the fabric-editor-popup-scroll-parent overflow
151
134
  * @param guidelines
152
135
  * @param containerWidth editorWidth
136
+ * @param lineLength
137
+ * @param isTableScalingEnabled
138
+ * @param isFullWidthModeEnabled
153
139
  */
154
140
  const getVisibleGuidelines = (
155
- guidelines: GuidelineConfig[],
156
- containerWidth: number,
141
+ guidelines: GuidelineConfig[],
142
+ containerWidth: number,
143
+ lineLength: number,
144
+ isTableScalingEnabled: boolean,
145
+ isFullWidthModeEnabled: boolean,
157
146
  ) => {
158
- return guidelines.filter((guideline) => {
159
- return (
160
- guideline.position &&
161
- guideline.position.x !== undefined &&
162
- typeof guideline.position.x === 'number' &&
163
- Math.abs(guideline.position.x * 2) <
164
- containerWidth + TABLE_GUIDELINE_VISIBLE_ADJUSTMENT
165
- );
166
- });
147
+ let guidelineVisibleAdjustment = TABLE_GUIDELINE_VISIBLE_ADJUSTMENT;
148
+ if (isTableScalingEnabled) {
149
+ // Notes:
150
+ // Example: containerWidth = 1244, lineLength = 1180 (used for when editor full width mode is enabled)
151
+ // Full width/dynamic x coordinate can be float number.
152
+ // Ex: guideline.position.x can be 590.5. So 590.5 * 2 = 1181 (not 1180).
153
+ // For PTW we need to ensure that dynamic guideline never gets excluded: 1181 should be > width + guidelineVisibleAdjustment
154
+ // guidelineVisibleAdjustment is set as a negative value, so we making it positive and adding + 1
155
+ const preserve_table_widths_adjustment = -1 * PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET + 1;
156
+
157
+ guidelineVisibleAdjustment = isFullWidthModeEnabled
158
+ ? preserve_table_widths_adjustment // guidelineVisibleAdjustment = -2, if lineLength = 1180, 1181 < 1180 + 2 is true.
159
+ : -2 * akEditorGutterPadding + preserve_table_widths_adjustment; // guidelineVisibleAdjustment = -62, if containerWidth is 1244, 1181 < 1244 - 62 = 1182 is true.
160
+ }
161
+ const width = isTableScalingEnabled && isFullWidthModeEnabled ? lineLength : containerWidth;
162
+
163
+ return guidelines.filter((guideline) => {
164
+ return (
165
+ guideline.position &&
166
+ guideline.position.x !== undefined &&
167
+ typeof guideline.position.x === 'number' &&
168
+ Math.abs(guideline.position.x * 2) < width + guidelineVisibleAdjustment
169
+ );
170
+ });
167
171
  };
168
172
 
169
173
  export const TableResizer = ({
170
- children,
171
- width,
172
- maxWidth,
173
- containerWidth,
174
- lineLength,
175
- updateWidth,
176
- onResizeStop,
177
- onResizeStart,
178
- editorView,
179
- getPos,
180
- node,
181
- tableRef,
182
- displayGuideline,
183
- attachAnalyticsEvent,
184
- displayGapCursor,
185
- isTableScalingEnabled,
186
- isTableAlignmentEnabled,
187
- isWholeTableInDanger,
188
- pluginInjectionApi,
174
+ children,
175
+ width,
176
+ maxWidth,
177
+ containerWidth,
178
+ lineLength,
179
+ updateWidth,
180
+ onResizeStop,
181
+ onResizeStart,
182
+ editorView,
183
+ getPos,
184
+ node,
185
+ tableRef,
186
+ displayGuideline,
187
+ attachAnalyticsEvent,
188
+ displayGapCursor,
189
+ isTableScalingEnabled,
190
+ isTableAlignmentEnabled,
191
+ isWholeTableInDanger,
192
+ pluginInjectionApi,
193
+ isFullWidthModeEnabled,
189
194
  }: PropsWithChildren<TableResizerImprovementProps>) => {
190
- const currentGap = useRef(0);
191
- // track resizing state - use ref over state to avoid re-render
192
- const isResizing = useRef(false);
193
- const areResizeMetaKeysPressed = useRef(false);
194
- const resizerRef = useRef<ResizerNextHandler>(null);
195
- const { tableState } = useSharedPluginState(pluginInjectionApi, ['table']);
196
- const { widthToWidest } = tableState as TableSharedStateInternal;
197
-
198
- // used to reposition tooltip when table is resizing via keyboard
199
- const updateTooltip = React.useRef<() => void>();
200
- const [snappingEnabled, setSnappingEnabled] = useState(false);
201
-
202
- const { formatMessage } = useIntl();
203
-
204
- const isTableSelected =
205
- findTable(editorView.state?.selection)?.pos === getPos();
206
-
207
- const resizerMinWidth = getResizerMinWidth(node);
208
- const handleSize = getResizerHandleHeight(tableRef);
209
-
210
- const { startMeasure, endMeasure, countFrames } = useMeasureFramerate();
211
-
212
- const excludeGuidelineConfig = useMemo(
213
- () => ({
214
- innerGuidelines: !!isTableAlignmentEnabled,
215
- breakoutPoints: !!(
216
- isTableAlignmentEnabled && tableState?.isFullWidthModeEnabled
217
- ),
218
- }),
219
- [tableState, isTableAlignmentEnabled],
220
- );
221
-
222
- const updateActiveGuidelines = useCallback(
223
- ({ gap, keys }: { gap: number; keys: string[] }) => {
224
- if (gap !== currentGap.current) {
225
- currentGap.current = gap;
226
- const visibleGuidelines = getVisibleGuidelines(
227
- isTableScalingEnabled
228
- ? defaultGuidelinesForPreserveTable(
229
- containerWidth,
230
- excludeGuidelineConfig,
231
- )
232
- : defaultGuidelines,
233
- containerWidth,
234
- );
235
-
236
- displayGuideline(
237
- getGuidelinesWithHighlights(
238
- gap,
239
- TABLE_SNAP_GAP,
240
- keys,
241
- visibleGuidelines,
242
- ),
243
- );
244
- }
245
- },
246
- [
247
- isTableScalingEnabled,
248
- excludeGuidelineConfig,
249
- containerWidth,
250
- displayGuideline,
251
- ],
252
- );
253
-
254
- const guidelineSnaps = useMemo(
255
- () =>
256
- snappingEnabled
257
- ? {
258
- x: isTableScalingEnabled
259
- ? defaultTablePreserveSnappingWidths(
260
- containerWidth,
261
- excludeGuidelineConfig,
262
- )
263
- : defaultSnappingWidths,
264
- }
265
- : undefined,
266
- [
267
- snappingEnabled,
268
- isTableScalingEnabled,
269
- excludeGuidelineConfig,
270
- containerWidth,
271
- ],
272
- );
273
-
274
- const switchToCenterAlignment = useCallback(
275
- (pos, node, newWidth, state, dispatch) => {
276
- if (
277
- isTableAlignmentEnabled &&
278
- node &&
279
- node.attrs.layout === ALIGN_START &&
280
- newWidth > lineLength &&
281
- lineLength < FULL_WIDTH_EDITOR_CONTENT_WIDTH && // We don't want to switch alignment in Full-width editor
282
- isResizing.current
283
- ) {
284
- const tableNodeWithPos = { pos, node };
285
- const tr = setTableAlignmentWithTableContentWithPos(
286
- ALIGN_CENTER,
287
- tableNodeWithPos,
288
- )(state);
289
-
290
- if (tr) {
291
- dispatch(tr);
292
- }
293
-
294
- return true;
295
- }
296
-
297
- return false;
298
- },
299
- [lineLength, isTableAlignmentEnabled, isResizing],
300
- );
301
-
302
- useEffect(() => {
303
- return () => {
304
- // only bring back the cursor if this table was deleted - i.e. if a user was resizing, then another
305
- // deleted this table
306
- if (isResizing.current) {
307
- const {
308
- dispatch,
309
- state: { tr },
310
- } = editorView;
311
- displayGapCursor(true);
312
- displayGuideline([]);
313
- tr.setMeta(tableWidthPluginKey, {
314
- resizing: false,
315
- tableLocalId: '',
316
- tableRef: null,
317
- });
318
- dispatch(tr);
319
- }
320
- };
321
- }, [editorView, displayGuideline, displayGapCursor]);
322
-
323
- const handleResizeStart = useCallback(() => {
324
- startMeasure();
325
- isResizing.current = true;
326
- const {
327
- dispatch,
328
- state: { tr },
329
- } = editorView;
330
- displayGapCursor(false);
331
-
332
- tr.setMeta(tableWidthPluginKey, {
333
- resizing: true,
334
- tableLocalId: node.attrs.localId,
335
- tableRef: tableRef,
336
- });
337
- tr.setMeta(META_KEYS.OVERFLOW_TRIGGER, {
338
- name: TABLE_OVERFLOW_CHANGE_TRIGGER.RESIZED,
339
- });
340
-
341
- dispatch(tr);
342
-
343
- const visibleGuidelines = getVisibleGuidelines(
344
- isTableScalingEnabled
345
- ? defaultGuidelinesForPreserveTable(
346
- containerWidth,
347
- excludeGuidelineConfig,
348
- )
349
- : defaultGuidelines,
350
- containerWidth,
351
- );
352
-
353
- setSnappingEnabled(displayGuideline(visibleGuidelines));
354
- if (onResizeStart) {
355
- onResizeStart();
356
- }
357
- }, [
358
- startMeasure,
359
- editorView,
360
- displayGapCursor,
361
- node.attrs.localId,
362
- tableRef,
363
- isTableScalingEnabled,
364
- excludeGuidelineConfig,
365
- containerWidth,
366
- displayGuideline,
367
- onResizeStart,
368
- ]);
369
-
370
- const handleResize = useCallback(
371
- (originalState: any, delta: any) => {
372
- countFrames();
373
- const newWidth = originalState.width + delta.width;
374
- let pos: number | undefined;
375
- try {
376
- pos = getPos();
377
- } catch (e) {
378
- return;
379
- }
380
- if (typeof pos !== 'number') {
381
- return;
382
- }
383
-
384
- previewScaleTable(
385
- tableRef,
386
- {
387
- node,
388
- prevNode: node,
389
- start: pos + 1,
390
- parentWidth: newWidth,
391
- },
392
- editorView.domAtPos.bind(editorView),
393
- isTableScalingEnabled,
394
- );
395
-
396
- const closestSnap = findClosestSnap(
397
- newWidth,
398
- isTableScalingEnabled
399
- ? defaultTablePreserveSnappingWidths(
400
- containerWidth,
401
- excludeGuidelineConfig,
402
- )
403
- : defaultSnappingWidths,
404
- isTableScalingEnabled
405
- ? defaultGuidelinesForPreserveTable(
406
- containerWidth,
407
- excludeGuidelineConfig,
408
- )
409
- : defaultGuidelines,
410
- TABLE_HIGHLIGHT_GAP,
411
- TABLE_HIGHLIGHT_TOLERANCE,
412
- );
413
-
414
- updateActiveGuidelines(closestSnap);
415
-
416
- // When snapping to the full width guideline, resize the table to be 1800px
417
- const { state, dispatch } = editorView;
418
- const currentTableNodeLocalId = node?.attrs?.localId ?? '';
419
-
420
- const fullWidthGuideline = defaultGuidelinesForPreserveTable(
421
- containerWidth,
422
- excludeGuidelineConfig,
423
- ).filter((guideline) => guideline.isFullWidth)[0];
424
-
425
- const isFullWidthGuidelineActive = closestSnap.keys.includes(
426
- fullWidthGuideline.key,
427
- );
428
- const shouldUpdateWidthToWidest =
429
- !!isTableScalingEnabled && isFullWidthGuidelineActive;
430
-
431
- chainCommands(
432
- (state, dispatch) => {
433
- return switchToCenterAlignment(pos, node, newWidth, state, dispatch);
434
- },
435
- updateWidthToWidest({
436
- [currentTableNodeLocalId]: shouldUpdateWidthToWidest,
437
- }),
438
- )(state, dispatch);
439
-
440
- updateWidth(shouldUpdateWidthToWidest ? TABLE_MAX_WIDTH : newWidth);
441
-
442
- return newWidth;
443
- },
444
- [
445
- countFrames,
446
- isTableScalingEnabled,
447
- excludeGuidelineConfig,
448
- tableRef,
449
- node,
450
- editorView,
451
- updateActiveGuidelines,
452
- containerWidth,
453
- updateWidth,
454
- getPos,
455
- switchToCenterAlignment,
456
- ],
457
- );
458
-
459
- const scheduleResize = useMemo(() => rafSchd(handleResize), [handleResize]);
460
-
461
- const handleResizeStop = useCallback<HandleResize>(
462
- (originalState, delta) => {
463
- isResizing.current = false;
464
- let newWidth = originalState.width + delta.width;
465
- const { state, dispatch } = editorView;
466
- const pos = getPos();
467
- const currentTableNodeLocalId = node?.attrs?.localId ?? '';
468
- newWidth =
469
- widthToWidest &&
470
- currentTableNodeLocalId &&
471
- widthToWidest[currentTableNodeLocalId]
472
- ? TABLE_MAX_WIDTH
473
- : newWidth;
474
-
475
- let tr = state.tr.setMeta(tableWidthPluginKey, {
476
- resizing: false,
477
- tableLocalId: '',
478
- tableRef: null,
479
- });
480
- const frameRateSamples = endMeasure();
481
-
482
- if (frameRateSamples.length > 0) {
483
- const resizeFrameRatePayloads = generateResizeFrameRatePayloads({
484
- docSize: state.doc.nodeSize,
485
- frameRateSamples,
486
- originalNode: node,
487
- });
488
- resizeFrameRatePayloads.forEach((payload) => {
489
- attachAnalyticsEvent(payload)?.(tr);
490
- });
491
- }
492
-
493
- if (typeof pos === 'number') {
494
- tr = tr.setNodeMarkup(pos, undefined, {
495
- ...node.attrs,
496
- width: newWidth,
497
- });
498
-
499
- const newNode = tr.doc.nodeAt(pos)!;
500
- tr = scaleTable(
501
- tableRef,
502
- {
503
- node: newNode,
504
- prevNode: node,
505
- start: pos + 1,
506
- parentWidth: newWidth,
507
- },
508
- editorView.domAtPos.bind(editorView),
509
- isTableScalingEnabled,
510
- )(tr);
511
-
512
- const scaledNode = tr.doc.nodeAt(pos)!;
513
-
514
- attachAnalyticsEvent(
515
- generateResizedPayload({
516
- originalNode: node,
517
- resizedNode: scaledNode,
518
- }),
519
- )?.(tr);
520
- }
521
- displayGapCursor(true);
522
- dispatch(tr);
523
-
524
- if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
525
- if (delta.width < 0) {
526
- pluginInjectionApi?.accessibilityUtils?.actions.ariaNotify(
527
- formatMessage(messages.tableSizeDecreaseScreenReaderInformation, {
528
- newWidth: newWidth,
529
- }),
530
- );
531
- } else if (delta.width > 0) {
532
- pluginInjectionApi?.accessibilityUtils?.actions.ariaNotify(
533
- formatMessage(messages.tableSizeIncreaseScreenReaderInformation, {
534
- newWidth: newWidth,
535
- }),
536
- );
537
- }
538
- }
539
-
540
- // Hide guidelines when resizing stops
541
- displayGuideline([]);
542
- updateWidth(newWidth);
543
- scheduleResize.cancel();
544
-
545
- if (onResizeStop) {
546
- onResizeStop();
547
- }
548
-
549
- return newWidth;
550
- },
551
- [
552
- displayGapCursor,
553
- updateWidth,
554
- editorView,
555
- getPos,
556
- node,
557
- tableRef,
558
- scheduleResize,
559
- displayGuideline,
560
- attachAnalyticsEvent,
561
- endMeasure,
562
- onResizeStop,
563
- isTableScalingEnabled,
564
- widthToWidest,
565
- formatMessage,
566
- pluginInjectionApi,
567
- ],
568
- );
569
-
570
- const handleTableSizeChangeOnKeypress = useCallback(
571
- (step: number) => {
572
- const newWidth = width + step;
573
-
574
- if (newWidth > maxWidth || newWidth < resizerMinWidth) {
575
- return;
576
- }
577
- handleResizeStop(
578
- { width: width, x: 0, y: 0, height: 0 },
579
- { width: step, height: 0 },
580
- );
581
- },
582
- [width, handleResizeStop, maxWidth, resizerMinWidth],
583
- );
584
-
585
- const handleEscape = useCallback((): void => {
586
- editorView?.focus();
587
- }, [editorView]);
588
-
589
- const handleKeyDown = useCallback(
590
- (event: KeyboardEvent): void => {
591
- const isBracketKey =
592
- event.code === 'BracketRight' || event.code === 'BracketLeft';
593
-
594
- const metaKey = browser.mac ? event.metaKey : event.ctrlKey;
595
-
596
- if (event.altKey || metaKey || event.shiftKey) {
597
- areResizeMetaKeysPressed.current = true;
598
- }
599
-
600
- if (event.altKey && metaKey) {
601
- if (isBracketKey) {
602
- event.preventDefault();
603
- handleTableSizeChangeOnKeypress(
604
- event.code === 'BracketRight'
605
- ? RESIZE_STEP_VALUE
606
- : -RESIZE_STEP_VALUE,
607
- );
608
- }
609
- } else if (!areResizeMetaKeysPressed.current) {
610
- handleEscape();
611
- }
612
- },
613
- [handleEscape, handleTableSizeChangeOnKeypress],
614
- );
615
-
616
- const handleKeyUp = useCallback(
617
- (event: KeyboardEvent): void => {
618
- if (event.altKey || event.metaKey) {
619
- areResizeMetaKeysPressed.current = false;
620
- }
621
- return;
622
- },
623
- [areResizeMetaKeysPressed],
624
- );
625
-
626
- useLayoutEffect(() => {
627
- if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
628
- if (!resizerRef.current) {
629
- return;
630
- }
631
- const resizeHandleThumbEl = resizerRef.current.getResizerThumbEl();
632
-
633
- const globalKeyDownHandler = (event: KeyboardEvent): void => {
634
- const metaKey = browser.mac ? event.metaKey : event.ctrlKey;
635
-
636
- if (!isTableSelected) {
637
- return;
638
- }
639
- if (
640
- event.altKey &&
641
- event.shiftKey &&
642
- metaKey &&
643
- event.code === 'KeyR'
644
- ) {
645
- event.preventDefault();
646
-
647
- if (!resizeHandleThumbEl) {
648
- return;
649
- }
650
- resizeHandleThumbEl.focus();
651
- resizeHandleThumbEl.scrollIntoView({
652
- behavior: 'smooth',
653
- block: 'center',
654
- inline: 'nearest',
655
- });
656
- }
657
- };
658
-
659
- const editorViewDom = editorView?.dom as HTMLElement | undefined;
660
- editorViewDom?.addEventListener('keydown', globalKeyDownHandler);
661
- resizeHandleThumbEl?.addEventListener('keydown', handleKeyDown);
662
- resizeHandleThumbEl?.addEventListener('keyup', handleKeyUp);
663
- return () => {
664
- editorViewDom?.removeEventListener('keydown', globalKeyDownHandler);
665
- resizeHandleThumbEl?.removeEventListener('keydown', handleKeyDown);
666
- resizeHandleThumbEl?.removeEventListener('keyup', handleKeyUp);
667
- };
668
- }
669
- }, [
670
- resizerRef,
671
- editorView,
672
- handleResizeStop,
673
- isTableSelected,
674
- handleKeyDown,
675
- handleKeyUp,
676
- ]);
677
-
678
- useLayoutEffect(() => {
679
- if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
680
- updateTooltip.current?.();
681
- }
682
- }, [width]);
683
-
684
- const resizeRatio =
685
- !isTableAlignmentEnabled ||
686
- (isTableAlignmentEnabled &&
687
- normaliseAlignment(node.attrs.layout) === ALIGN_CENTER)
688
- ? 2
689
- : 1;
690
-
691
- return (
692
- <>
693
- <ResizerNext
694
- ref={resizerRef}
695
- enable={handles}
696
- width={width}
697
- handleAlignmentMethod="sticky"
698
- handleSize={handleSize}
699
- handleStyles={handleStyles}
700
- handleResizeStart={handleResizeStart}
701
- handleResize={scheduleResize}
702
- handleResizeStop={handleResizeStop}
703
- resizeRatio={resizeRatio}
704
- minWidth={resizerMinWidth}
705
- maxWidth={maxWidth}
706
- snapGap={TABLE_SNAP_GAP}
707
- snap={guidelineSnaps}
708
- handlePositioning="adjacent"
709
- isHandleVisible={isTableSelected}
710
- needExtendedResizeZone={!isTableSelected}
711
- appearance={
712
- isTableSelected && isWholeTableInDanger ? 'danger' : undefined
713
- }
714
- handleHighlight="shadow"
715
- handleTooltipContent={
716
- getBooleanFF('platform.editor.a11y-table-resizing_uapcv')
717
- ? ({ update }) => {
718
- updateTooltip.current = update;
719
- return (
720
- <ToolTipContent
721
- description={formatMessage(messages.resizeTable)}
722
- keymap={focusTableResizer}
723
- />
724
- );
725
- }
726
- : formatMessage(messages.resizeTable)
727
- }
728
- >
729
- {children}
730
- </ResizerNext>
731
- </>
732
- );
195
+ const currentGap = useRef(0);
196
+ // track resizing state - use ref over state to avoid re-render
197
+ const isResizing = useRef(false);
198
+ const areResizeMetaKeysPressed = useRef(false);
199
+ const resizerRef = useRef<ResizerNextHandler>(null);
200
+ const { tableState } = useSharedPluginState(pluginInjectionApi, ['table']);
201
+ const { widthToWidest } = tableState as TableSharedStateInternal;
202
+
203
+ // used to reposition tooltip when table is resizing via keyboard
204
+ const updateTooltip = React.useRef<() => void>();
205
+ const [snappingEnabled, setSnappingEnabled] = useState(false);
206
+
207
+ const { formatMessage } = useIntl();
208
+
209
+ const isTableSelected = findTable(editorView.state?.selection)?.pos === getPos();
210
+
211
+ const resizerMinWidth = getResizerMinWidth(node);
212
+ const handleSize = getResizerHandleHeight(tableRef);
213
+
214
+ const { startMeasure, endMeasure, countFrames } = useMeasureFramerate();
215
+
216
+ const excludeGuidelineConfig = useMemo(
217
+ () => ({
218
+ innerGuidelines: !!isTableAlignmentEnabled,
219
+ breakoutPoints: !!(isTableAlignmentEnabled && tableState?.isFullWidthModeEnabled),
220
+ }),
221
+ [tableState, isTableAlignmentEnabled],
222
+ );
223
+
224
+ const updateActiveGuidelines = useCallback(
225
+ ({ gap, keys }: { gap: number; keys: string[] }) => {
226
+ if (gap !== currentGap.current) {
227
+ currentGap.current = gap;
228
+ const visibleGuidelines = getVisibleGuidelines(
229
+ isTableScalingEnabled
230
+ ? defaultGuidelinesForPreserveTable(
231
+ PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET,
232
+ isFullWidthModeEnabled ? lineLength + 2 * akEditorGutterPadding : containerWidth,
233
+ excludeGuidelineConfig,
234
+ )
235
+ : defaultGuidelines,
236
+ containerWidth,
237
+ lineLength,
238
+ Boolean(isTableScalingEnabled),
239
+ Boolean(isFullWidthModeEnabled),
240
+ );
241
+ displayGuideline(getGuidelinesWithHighlights(gap, TABLE_SNAP_GAP, keys, visibleGuidelines));
242
+ }
243
+ },
244
+ [
245
+ isTableScalingEnabled,
246
+ excludeGuidelineConfig,
247
+ containerWidth,
248
+ displayGuideline,
249
+ lineLength,
250
+ isFullWidthModeEnabled,
251
+ ],
252
+ );
253
+
254
+ const guidelineSnaps = useMemo(
255
+ () =>
256
+ snappingEnabled
257
+ ? {
258
+ x: isTableScalingEnabled
259
+ ? defaultTablePreserveSnappingWidths(
260
+ PRESERVE_TABLE_SNAPPING_LENGTH_OFFSET, // was hardcoded to 0, using PRESERVE_TABLE_SNAPPING_LENGTH_OFFSET instead.
261
+ isFullWidthModeEnabled ? lineLength + 2 * akEditorGutterPadding : containerWidth,
262
+ excludeGuidelineConfig,
263
+ )
264
+ : defaultSnappingWidths,
265
+ }
266
+ : undefined,
267
+ [
268
+ snappingEnabled,
269
+ isTableScalingEnabled,
270
+ excludeGuidelineConfig,
271
+ containerWidth,
272
+ lineLength,
273
+ isFullWidthModeEnabled,
274
+ ],
275
+ );
276
+
277
+ const switchToCenterAlignment = useCallback(
278
+ (pos, node, newWidth, state, dispatch) => {
279
+ if (
280
+ isTableAlignmentEnabled &&
281
+ node &&
282
+ node.attrs.layout === ALIGN_START &&
283
+ newWidth > lineLength &&
284
+ lineLength < FULL_WIDTH_EDITOR_CONTENT_WIDTH && // We don't want to switch alignment in Full-width editor
285
+ isResizing.current
286
+ ) {
287
+ const tableNodeWithPos = { pos, node };
288
+ const tr = setTableAlignmentWithTableContentWithPos(ALIGN_CENTER, tableNodeWithPos)(state);
289
+
290
+ if (tr) {
291
+ dispatch(tr);
292
+ }
293
+
294
+ return true;
295
+ }
296
+
297
+ return false;
298
+ },
299
+ [lineLength, isTableAlignmentEnabled, isResizing],
300
+ );
301
+
302
+ useEffect(() => {
303
+ return () => {
304
+ // only bring back the cursor if this table was deleted - i.e. if a user was resizing, then another
305
+ // deleted this table
306
+ if (isResizing.current) {
307
+ const {
308
+ dispatch,
309
+ state: { tr },
310
+ } = editorView;
311
+ displayGapCursor(true);
312
+ displayGuideline([]);
313
+ tr.setMeta(tableWidthPluginKey, {
314
+ resizing: false,
315
+ tableLocalId: '',
316
+ tableRef: null,
317
+ });
318
+ dispatch(tr);
319
+ }
320
+ };
321
+ }, [editorView, displayGuideline, displayGapCursor]);
322
+
323
+ const handleResizeStart = useCallback(() => {
324
+ startMeasure();
325
+ isResizing.current = true;
326
+ const {
327
+ dispatch,
328
+ state: { tr },
329
+ } = editorView;
330
+ displayGapCursor(false);
331
+
332
+ tr.setMeta(tableWidthPluginKey, {
333
+ resizing: true,
334
+ tableLocalId: node.attrs.localId,
335
+ tableRef: tableRef,
336
+ });
337
+ tr.setMeta(META_KEYS.OVERFLOW_TRIGGER, {
338
+ name: TABLE_OVERFLOW_CHANGE_TRIGGER.RESIZED,
339
+ });
340
+
341
+ dispatch(tr);
342
+
343
+ const visibleGuidelines = getVisibleGuidelines(
344
+ isTableScalingEnabled
345
+ ? defaultGuidelinesForPreserveTable(
346
+ PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET,
347
+ isFullWidthModeEnabled ? lineLength + 2 * akEditorGutterPadding : containerWidth,
348
+ excludeGuidelineConfig,
349
+ )
350
+ : defaultGuidelines,
351
+ containerWidth,
352
+ lineLength,
353
+ Boolean(isTableScalingEnabled),
354
+ Boolean(isFullWidthModeEnabled),
355
+ );
356
+
357
+ setSnappingEnabled(displayGuideline(visibleGuidelines));
358
+ if (onResizeStart) {
359
+ onResizeStart();
360
+ }
361
+ }, [
362
+ startMeasure,
363
+ editorView,
364
+ displayGapCursor,
365
+ node.attrs.localId,
366
+ tableRef,
367
+ isTableScalingEnabled,
368
+ excludeGuidelineConfig,
369
+ containerWidth,
370
+ lineLength,
371
+ displayGuideline,
372
+ onResizeStart,
373
+ isFullWidthModeEnabled,
374
+ ]);
375
+
376
+ const handleResize = useCallback(
377
+ (originalState: any, delta: any) => {
378
+ countFrames();
379
+ const newWidth = originalState.width + delta.width;
380
+ let pos: number | undefined;
381
+ try {
382
+ pos = getPos();
383
+ } catch (e) {
384
+ return;
385
+ }
386
+ if (typeof pos !== 'number') {
387
+ return;
388
+ }
389
+
390
+ previewScaleTable(
391
+ tableRef,
392
+ {
393
+ node,
394
+ prevNode: node,
395
+ start: pos + 1,
396
+ parentWidth: newWidth,
397
+ },
398
+ editorView.domAtPos.bind(editorView),
399
+ isTableScalingEnabled,
400
+ );
401
+
402
+ const editorContainerWidth = isFullWidthModeEnabled
403
+ ? lineLength + 2 * akEditorGutterPadding
404
+ : containerWidth;
405
+
406
+ const closestSnap = findClosestSnap(
407
+ newWidth,
408
+ isTableScalingEnabled
409
+ ? defaultTablePreserveSnappingWidths(
410
+ PRESERVE_TABLE_SNAPPING_LENGTH_OFFSET,
411
+ editorContainerWidth,
412
+ excludeGuidelineConfig,
413
+ )
414
+ : defaultSnappingWidths,
415
+ isTableScalingEnabled
416
+ ? defaultGuidelinesForPreserveTable(
417
+ PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET,
418
+ editorContainerWidth,
419
+ excludeGuidelineConfig,
420
+ )
421
+ : defaultGuidelines,
422
+ TABLE_HIGHLIGHT_GAP,
423
+ TABLE_HIGHLIGHT_TOLERANCE,
424
+ );
425
+
426
+ updateActiveGuidelines(closestSnap);
427
+
428
+ // When snapping to the full width guideline, resize the table to be 1800px
429
+ const { state, dispatch } = editorView;
430
+ const currentTableNodeLocalId = node?.attrs?.localId ?? '';
431
+
432
+ const fullWidthGuideline = defaultGuidelinesForPreserveTable(
433
+ PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET,
434
+ editorContainerWidth,
435
+ excludeGuidelineConfig,
436
+ ).filter((guideline) => guideline.isFullWidth)[0];
437
+
438
+ const isFullWidthGuidelineActive = closestSnap.keys.includes(fullWidthGuideline.key);
439
+ const shouldUpdateWidthToWidest = !!isTableScalingEnabled && isFullWidthGuidelineActive;
440
+
441
+ chainCommands(
442
+ (state, dispatch) => {
443
+ return switchToCenterAlignment(pos, node, newWidth, state, dispatch);
444
+ },
445
+ updateWidthToWidest({
446
+ [currentTableNodeLocalId]: shouldUpdateWidthToWidest,
447
+ }),
448
+ )(state, dispatch);
449
+
450
+ updateWidth(shouldUpdateWidthToWidest ? TABLE_MAX_WIDTH : newWidth);
451
+
452
+ return newWidth;
453
+ },
454
+ [
455
+ countFrames,
456
+ isTableScalingEnabled,
457
+ isFullWidthModeEnabled,
458
+ excludeGuidelineConfig,
459
+ tableRef,
460
+ node,
461
+ editorView,
462
+ updateActiveGuidelines,
463
+ containerWidth,
464
+ lineLength,
465
+ updateWidth,
466
+ getPos,
467
+ switchToCenterAlignment,
468
+ ],
469
+ );
470
+
471
+ const scheduleResize = useMemo(() => rafSchd(handleResize), [handleResize]);
472
+
473
+ const handleResizeStop = useCallback<HandleResize>(
474
+ (originalState, delta) => {
475
+ isResizing.current = false;
476
+ let newWidth = originalState.width + delta.width;
477
+ const { state, dispatch } = editorView;
478
+ const pos = getPos();
479
+ const currentTableNodeLocalId = node?.attrs?.localId ?? '';
480
+ newWidth =
481
+ widthToWidest && currentTableNodeLocalId && widthToWidest[currentTableNodeLocalId]
482
+ ? TABLE_MAX_WIDTH
483
+ : newWidth;
484
+
485
+ let tr = state.tr.setMeta(tableWidthPluginKey, {
486
+ resizing: false,
487
+ tableLocalId: '',
488
+ tableRef: null,
489
+ });
490
+ const frameRateSamples = endMeasure();
491
+
492
+ if (frameRateSamples.length > 0) {
493
+ const resizeFrameRatePayloads = generateResizeFrameRatePayloads({
494
+ docSize: state.doc.nodeSize,
495
+ frameRateSamples,
496
+ originalNode: node,
497
+ });
498
+ resizeFrameRatePayloads.forEach((payload) => {
499
+ attachAnalyticsEvent(payload)?.(tr);
500
+ });
501
+ }
502
+
503
+ if (typeof pos === 'number') {
504
+ tr = tr.setNodeMarkup(pos, undefined, {
505
+ ...node.attrs,
506
+ width: newWidth,
507
+ });
508
+
509
+ const newNode = tr.doc.nodeAt(pos)!;
510
+ tr = scaleTable(
511
+ tableRef,
512
+ {
513
+ node: newNode,
514
+ prevNode: node,
515
+ start: pos + 1,
516
+ parentWidth: newWidth,
517
+ },
518
+ editorView.domAtPos.bind(editorView),
519
+ isTableScalingEnabled,
520
+ )(tr);
521
+
522
+ const scaledNode = tr.doc.nodeAt(pos)!;
523
+
524
+ attachAnalyticsEvent(
525
+ generateResizedPayload({
526
+ originalNode: node,
527
+ resizedNode: scaledNode,
528
+ }),
529
+ )?.(tr);
530
+ }
531
+ displayGapCursor(true);
532
+ dispatch(tr);
533
+
534
+ if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
535
+ if (delta.width < 0) {
536
+ pluginInjectionApi?.accessibilityUtils?.actions.ariaNotify(
537
+ formatMessage(messages.tableSizeDecreaseScreenReaderInformation, {
538
+ newWidth: newWidth,
539
+ }),
540
+ );
541
+ } else if (delta.width > 0) {
542
+ pluginInjectionApi?.accessibilityUtils?.actions.ariaNotify(
543
+ formatMessage(messages.tableSizeIncreaseScreenReaderInformation, {
544
+ newWidth: newWidth,
545
+ }),
546
+ );
547
+ }
548
+ }
549
+
550
+ // Hide guidelines when resizing stops
551
+ displayGuideline([]);
552
+ updateWidth(newWidth);
553
+ scheduleResize.cancel();
554
+
555
+ if (onResizeStop) {
556
+ onResizeStop();
557
+ }
558
+
559
+ return newWidth;
560
+ },
561
+ [
562
+ displayGapCursor,
563
+ updateWidth,
564
+ editorView,
565
+ getPos,
566
+ node,
567
+ tableRef,
568
+ scheduleResize,
569
+ displayGuideline,
570
+ attachAnalyticsEvent,
571
+ endMeasure,
572
+ onResizeStop,
573
+ isTableScalingEnabled,
574
+ widthToWidest,
575
+ formatMessage,
576
+ pluginInjectionApi,
577
+ ],
578
+ );
579
+
580
+ const handleTableSizeChangeOnKeypress = useCallback(
581
+ (step: number) => {
582
+ const newWidth = width + step;
583
+
584
+ if (newWidth > maxWidth || newWidth < resizerMinWidth) {
585
+ return;
586
+ }
587
+ handleResizeStop({ width: width, x: 0, y: 0, height: 0 }, { width: step, height: 0 });
588
+ },
589
+ [width, handleResizeStop, maxWidth, resizerMinWidth],
590
+ );
591
+
592
+ const handleEscape = useCallback((): void => {
593
+ editorView?.focus();
594
+ }, [editorView]);
595
+
596
+ const handleKeyDown = useCallback(
597
+ (event: KeyboardEvent): void => {
598
+ const isBracketKey = event.code === 'BracketRight' || event.code === 'BracketLeft';
599
+
600
+ const metaKey = browser.mac ? event.metaKey : event.ctrlKey;
601
+
602
+ if (event.altKey || metaKey || event.shiftKey) {
603
+ areResizeMetaKeysPressed.current = true;
604
+ }
605
+
606
+ if (event.altKey && metaKey) {
607
+ if (isBracketKey) {
608
+ event.preventDefault();
609
+ handleTableSizeChangeOnKeypress(
610
+ event.code === 'BracketRight' ? RESIZE_STEP_VALUE : -RESIZE_STEP_VALUE,
611
+ );
612
+ }
613
+ } else if (!areResizeMetaKeysPressed.current) {
614
+ handleEscape();
615
+ }
616
+ },
617
+ [handleEscape, handleTableSizeChangeOnKeypress],
618
+ );
619
+
620
+ const handleKeyUp = useCallback(
621
+ (event: KeyboardEvent): void => {
622
+ if (event.altKey || event.metaKey) {
623
+ areResizeMetaKeysPressed.current = false;
624
+ }
625
+ return;
626
+ },
627
+ [areResizeMetaKeysPressed],
628
+ );
629
+
630
+ useLayoutEffect(() => {
631
+ if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
632
+ if (!resizerRef.current) {
633
+ return;
634
+ }
635
+ const resizeHandleThumbEl = resizerRef.current.getResizerThumbEl();
636
+
637
+ const globalKeyDownHandler = (event: KeyboardEvent): void => {
638
+ const metaKey = browser.mac ? event.metaKey : event.ctrlKey;
639
+
640
+ if (!isTableSelected) {
641
+ return;
642
+ }
643
+ if (event.altKey && event.shiftKey && metaKey && event.code === 'KeyR') {
644
+ event.preventDefault();
645
+
646
+ if (!resizeHandleThumbEl) {
647
+ return;
648
+ }
649
+ resizeHandleThumbEl.focus();
650
+ resizeHandleThumbEl.scrollIntoView({
651
+ behavior: 'smooth',
652
+ block: 'center',
653
+ inline: 'nearest',
654
+ });
655
+ }
656
+ };
657
+
658
+ const editorViewDom = editorView?.dom as HTMLElement | undefined;
659
+ editorViewDom?.addEventListener('keydown', globalKeyDownHandler);
660
+ resizeHandleThumbEl?.addEventListener('keydown', handleKeyDown);
661
+ resizeHandleThumbEl?.addEventListener('keyup', handleKeyUp);
662
+ return () => {
663
+ editorViewDom?.removeEventListener('keydown', globalKeyDownHandler);
664
+ resizeHandleThumbEl?.removeEventListener('keydown', handleKeyDown);
665
+ resizeHandleThumbEl?.removeEventListener('keyup', handleKeyUp);
666
+ };
667
+ }
668
+ }, [resizerRef, editorView, handleResizeStop, isTableSelected, handleKeyDown, handleKeyUp]);
669
+
670
+ useLayoutEffect(() => {
671
+ if (getBooleanFF('platform.editor.a11y-table-resizing_uapcv')) {
672
+ updateTooltip.current?.();
673
+ }
674
+ }, [width]);
675
+
676
+ const resizeRatio =
677
+ !isTableAlignmentEnabled ||
678
+ (isTableAlignmentEnabled && normaliseAlignment(node.attrs.layout) === ALIGN_CENTER)
679
+ ? 2
680
+ : 1;
681
+
682
+ return (
683
+ <>
684
+ <ResizerNext
685
+ ref={resizerRef}
686
+ enable={handles}
687
+ width={width}
688
+ handleAlignmentMethod="sticky"
689
+ handleSize={handleSize}
690
+ handleStyles={handleStyles}
691
+ handleResizeStart={handleResizeStart}
692
+ handleResize={scheduleResize}
693
+ handleResizeStop={handleResizeStop}
694
+ resizeRatio={resizeRatio}
695
+ minWidth={resizerMinWidth}
696
+ maxWidth={maxWidth}
697
+ snapGap={TABLE_SNAP_GAP}
698
+ snap={guidelineSnaps}
699
+ handlePositioning="adjacent"
700
+ isHandleVisible={isTableSelected}
701
+ needExtendedResizeZone={!isTableSelected}
702
+ appearance={isTableSelected && isWholeTableInDanger ? 'danger' : undefined}
703
+ handleHighlight="shadow"
704
+ handleTooltipContent={
705
+ getBooleanFF('platform.editor.a11y-table-resizing_uapcv')
706
+ ? ({ update }) => {
707
+ updateTooltip.current = update;
708
+ return (
709
+ <ToolTipContent
710
+ description={formatMessage(messages.resizeTable)}
711
+ keymap={focusTableResizer}
712
+ />
713
+ );
714
+ }
715
+ : formatMessage(messages.resizeTable)
716
+ }
717
+ >
718
+ {children}
719
+ </ResizerNext>
720
+ </>
721
+ );
733
722
  };