@atlaskit/editor-plugin-table 22.4.8 → 22.4.10

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 (107) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/pm-plugins/commands/split-cell.js +18 -1
  3. package/dist/cjs/pm-plugins/transforms/merge.js +5 -2
  4. package/dist/cjs/ui/FloatingContextualMenu/CellMenuPopup.js +1 -0
  5. package/dist/cjs/ui/FloatingDragMenu/index.js +7 -2
  6. package/dist/cjs/ui/TableMenu/cell/getCellMenuComponents.js +2 -9
  7. package/dist/cjs/ui/TableMenu/cell/items/MergeCellsItem.js +12 -0
  8. package/dist/cjs/ui/TableMenu/cell/items/SplitCellItem.js +12 -0
  9. package/dist/cjs/ui/TableMenu/cell/keys.js +2 -2
  10. package/dist/cjs/ui/TableMenu/column/getColumnMenuComponents.js +4 -11
  11. package/dist/cjs/ui/TableMenu/column/items/ColumnBackgroundSection.js +25 -0
  12. package/dist/cjs/ui/TableMenu/column/items/ColumnToggleSection.js +24 -0
  13. package/dist/cjs/ui/TableMenu/column/items/DistributeColumnsItem.js +10 -0
  14. package/dist/cjs/ui/TableMenu/column/items/HeaderColumnToggleItem.js +17 -1
  15. package/dist/cjs/ui/TableMenu/column/items/SortDecreasingItem.js +3 -1
  16. package/dist/cjs/ui/TableMenu/column/items/SortIncreasingItem.js +3 -1
  17. package/dist/cjs/ui/TableMenu/row/getRowMenuComponents.js +0 -7
  18. package/dist/cjs/ui/TableMenu/row/items/HeaderRowToggleItem.js +9 -0
  19. package/dist/cjs/ui/TableMenu/row/items/MoveRowDownItem.js +10 -0
  20. package/dist/cjs/ui/TableMenu/row/items/MoveRowUpItem.js +10 -0
  21. package/dist/cjs/ui/TableMenu/shared/TableMenu.js +51 -2
  22. package/dist/cjs/ui/TableMenu/shared/TableMenuContext.js +13 -0
  23. package/dist/cjs/ui/TableMenu/shared/consts.js +3 -2
  24. package/dist/cjs/ui/event-handlers.js +6 -1
  25. package/dist/es2019/pm-plugins/commands/split-cell.js +17 -1
  26. package/dist/es2019/pm-plugins/transforms/merge.js +4 -4
  27. package/dist/es2019/ui/FloatingContextualMenu/CellMenuPopup.js +1 -0
  28. package/dist/es2019/ui/FloatingDragMenu/index.js +7 -2
  29. package/dist/es2019/ui/TableMenu/cell/getCellMenuComponents.js +3 -11
  30. package/dist/es2019/ui/TableMenu/cell/items/MergeCellsItem.js +11 -0
  31. package/dist/es2019/ui/TableMenu/cell/items/SplitCellItem.js +11 -0
  32. package/dist/es2019/ui/TableMenu/cell/keys.js +1 -1
  33. package/dist/es2019/ui/TableMenu/column/getColumnMenuComponents.js +4 -12
  34. package/dist/es2019/ui/TableMenu/column/items/ColumnBackgroundSection.js +20 -0
  35. package/dist/es2019/ui/TableMenu/column/items/ColumnToggleSection.js +19 -0
  36. package/dist/es2019/ui/TableMenu/column/items/DistributeColumnsItem.js +11 -0
  37. package/dist/es2019/ui/TableMenu/column/items/HeaderColumnToggleItem.js +15 -0
  38. package/dist/es2019/ui/TableMenu/column/items/SortDecreasingItem.js +3 -1
  39. package/dist/es2019/ui/TableMenu/column/items/SortIncreasingItem.js +3 -1
  40. package/dist/es2019/ui/TableMenu/row/getRowMenuComponents.js +0 -8
  41. package/dist/es2019/ui/TableMenu/row/items/HeaderRowToggleItem.js +8 -0
  42. package/dist/es2019/ui/TableMenu/row/items/MoveRowDownItem.js +8 -0
  43. package/dist/es2019/ui/TableMenu/row/items/MoveRowUpItem.js +8 -0
  44. package/dist/es2019/ui/TableMenu/shared/TableMenu.js +49 -2
  45. package/dist/es2019/ui/TableMenu/shared/TableMenuContext.js +4 -0
  46. package/dist/es2019/ui/TableMenu/shared/consts.js +2 -1
  47. package/dist/es2019/ui/event-handlers.js +4 -1
  48. package/dist/esm/pm-plugins/commands/split-cell.js +17 -1
  49. package/dist/esm/pm-plugins/transforms/merge.js +4 -2
  50. package/dist/esm/ui/FloatingContextualMenu/CellMenuPopup.js +1 -0
  51. package/dist/esm/ui/FloatingDragMenu/index.js +7 -2
  52. package/dist/esm/ui/TableMenu/cell/getCellMenuComponents.js +3 -11
  53. package/dist/esm/ui/TableMenu/cell/items/MergeCellsItem.js +13 -0
  54. package/dist/esm/ui/TableMenu/cell/items/SplitCellItem.js +13 -0
  55. package/dist/esm/ui/TableMenu/cell/keys.js +1 -1
  56. package/dist/esm/ui/TableMenu/column/getColumnMenuComponents.js +4 -12
  57. package/dist/esm/ui/TableMenu/column/items/ColumnBackgroundSection.js +19 -0
  58. package/dist/esm/ui/TableMenu/column/items/ColumnToggleSection.js +18 -0
  59. package/dist/esm/ui/TableMenu/column/items/DistributeColumnsItem.js +11 -0
  60. package/dist/esm/ui/TableMenu/column/items/HeaderColumnToggleItem.js +17 -0
  61. package/dist/esm/ui/TableMenu/column/items/SortDecreasingItem.js +3 -1
  62. package/dist/esm/ui/TableMenu/column/items/SortIncreasingItem.js +3 -1
  63. package/dist/esm/ui/TableMenu/row/getRowMenuComponents.js +0 -8
  64. package/dist/esm/ui/TableMenu/row/items/HeaderRowToggleItem.js +10 -0
  65. package/dist/esm/ui/TableMenu/row/items/MoveRowDownItem.js +10 -0
  66. package/dist/esm/ui/TableMenu/row/items/MoveRowUpItem.js +10 -0
  67. package/dist/esm/ui/TableMenu/shared/TableMenu.js +50 -2
  68. package/dist/esm/ui/TableMenu/shared/TableMenuContext.js +6 -0
  69. package/dist/esm/ui/TableMenu/shared/consts.js +2 -1
  70. package/dist/esm/ui/event-handlers.js +6 -1
  71. package/dist/types/pm-plugins/commands/split-cell.d.ts +2 -0
  72. package/dist/types/pm-plugins/transforms/merge.d.ts +2 -0
  73. package/dist/types/ui/TableMenu/cell/getCellMenuComponents.d.ts +0 -7
  74. package/dist/types/ui/TableMenu/cell/items/MergeCellsItem.d.ts +1 -1
  75. package/dist/types/ui/TableMenu/cell/items/SplitCellItem.d.ts +1 -1
  76. package/dist/types/ui/TableMenu/cell/keys.d.ts +1 -1
  77. package/dist/types/ui/TableMenu/column/getColumnMenuComponents.d.ts +0 -7
  78. package/dist/types/ui/TableMenu/column/items/ColumnBackgroundSection.d.ts +10 -0
  79. package/dist/types/ui/TableMenu/column/items/ColumnToggleSection.d.ts +9 -0
  80. package/dist/types/ui/TableMenu/column/items/DistributeColumnsItem.d.ts +1 -1
  81. package/dist/types/ui/TableMenu/column/items/HeaderColumnToggleItem.d.ts +11 -1
  82. package/dist/types/ui/TableMenu/row/getRowMenuComponents.d.ts +0 -7
  83. package/dist/types/ui/TableMenu/row/items/HeaderRowToggleItem.d.ts +1 -1
  84. package/dist/types/ui/TableMenu/row/items/MoveRowDownItem.d.ts +1 -1
  85. package/dist/types/ui/TableMenu/row/items/MoveRowUpItem.d.ts +1 -1
  86. package/dist/types/ui/TableMenu/shared/TableMenu.d.ts +3 -1
  87. package/dist/types/ui/TableMenu/shared/TableMenuContext.d.ts +14 -0
  88. package/dist/types/ui/TableMenu/shared/consts.d.ts +1 -0
  89. package/dist/types-ts4.5/pm-plugins/commands/split-cell.d.ts +2 -0
  90. package/dist/types-ts4.5/pm-plugins/transforms/merge.d.ts +2 -0
  91. package/dist/types-ts4.5/ui/TableMenu/cell/getCellMenuComponents.d.ts +0 -7
  92. package/dist/types-ts4.5/ui/TableMenu/cell/items/MergeCellsItem.d.ts +1 -1
  93. package/dist/types-ts4.5/ui/TableMenu/cell/items/SplitCellItem.d.ts +1 -1
  94. package/dist/types-ts4.5/ui/TableMenu/cell/keys.d.ts +1 -1
  95. package/dist/types-ts4.5/ui/TableMenu/column/getColumnMenuComponents.d.ts +0 -7
  96. package/dist/types-ts4.5/ui/TableMenu/column/items/ColumnBackgroundSection.d.ts +10 -0
  97. package/dist/types-ts4.5/ui/TableMenu/column/items/ColumnToggleSection.d.ts +9 -0
  98. package/dist/types-ts4.5/ui/TableMenu/column/items/DistributeColumnsItem.d.ts +1 -1
  99. package/dist/types-ts4.5/ui/TableMenu/column/items/HeaderColumnToggleItem.d.ts +11 -1
  100. package/dist/types-ts4.5/ui/TableMenu/row/getRowMenuComponents.d.ts +0 -7
  101. package/dist/types-ts4.5/ui/TableMenu/row/items/HeaderRowToggleItem.d.ts +1 -1
  102. package/dist/types-ts4.5/ui/TableMenu/row/items/MoveRowDownItem.d.ts +1 -1
  103. package/dist/types-ts4.5/ui/TableMenu/row/items/MoveRowUpItem.d.ts +1 -1
  104. package/dist/types-ts4.5/ui/TableMenu/shared/TableMenu.d.ts +3 -1
  105. package/dist/types-ts4.5/ui/TableMenu/shared/TableMenuContext.d.ts +14 -0
  106. package/dist/types-ts4.5/ui/TableMenu/shared/consts.d.ts +1 -0
  107. package/package.json +4 -4
@@ -1,5 +1,21 @@
1
- import { splitCellWithType } from '@atlaskit/editor-tables/utils';
1
+ import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
2
+ import { cellWrapping, splitCellWithType } from '@atlaskit/editor-tables/utils';
2
3
  import { getPluginState } from '../plugin-factory';
4
+ export const canSplitCellSelection = selection => {
5
+ let cellNode;
6
+ if (!(selection instanceof CellSelection)) {
7
+ cellNode = cellWrapping(selection.$from);
8
+ if (!cellNode) {
9
+ return false;
10
+ }
11
+ } else {
12
+ if (selection.$anchorCell.pos !== selection.$headCell.pos) {
13
+ return false;
14
+ }
15
+ cellNode = selection.$anchorCell.nodeAfter;
16
+ }
17
+ return Boolean(cellNode && (cellNode.attrs.colspan !== 1 || cellNode.attrs.rowspan !== 1));
18
+ };
3
19
 
4
20
  /**
5
21
  * We need to split cell keeping the right type of cell given current table configuration.
@@ -116,10 +116,7 @@ export function mergeCells(tr) {
116
116
  }
117
117
  return tr.replaceWith(table.pos, table.pos + table.node.nodeSize, fixedTable).setSelection(Selection.near(tr.doc.resolve((mergedCellPos || 0) + table.start)));
118
118
  }
119
- export function canMergeCells(tr) {
120
- const {
121
- selection
122
- } = tr;
119
+ export function canMergeCellSelection(selection) {
123
120
  if (!(selection instanceof CellSelection) || selection.$anchorCell.pos === selection.$headCell.pos) {
124
121
  return false;
125
122
  }
@@ -134,6 +131,9 @@ export function canMergeCells(tr) {
134
131
  }
135
132
  return true;
136
133
  }
134
+ export function canMergeCells(tr) {
135
+ return canMergeCellSelection(tr.selection);
136
+ }
137
137
  function isEmptyCell(cell) {
138
138
  const {
139
139
  content
@@ -94,6 +94,7 @@ export const CellMenuPopup = ({
94
94
  ref: tableMenuRef
95
95
  }, /*#__PURE__*/React.createElement(TableMenu, {
96
96
  api: api,
97
+ editorView: editorView,
97
98
  surface: CELL_MENU
98
99
  })));
99
100
  };
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Popup } from '@atlaskit/editor-common/ui';
3
+ import { UserIntentPopupWrapper } from '@atlaskit/editor-common/user-intent';
3
4
  import { akEditorFloatingDialogZIndex, akEditorFloatingOverlapPanelZIndex } from '@atlaskit/editor-shared-styles';
4
5
  import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
5
6
  import { fg } from '@atlaskit/platform-feature-flags';
@@ -66,10 +67,14 @@ const FloatingDragMenu = ({
66
67
  forcePlacement: true,
67
68
  offset: expValEquals('platform_editor_table_menu_updates', 'isEnabled', true) ? [TABLE_MENU_OFFSET, 0] : direction === 'row' ? [-9, 0] : [0, -7],
68
69
  stick: true
69
- }, expValEquals('platform_editor_table_menu_updates', 'isEnabled', true) ? /*#__PURE__*/React.createElement(TableMenu, {
70
+ }, expValEquals('platform_editor_table_menu_updates', 'isEnabled', true) ? /*#__PURE__*/React.createElement(UserIntentPopupWrapper, {
70
71
  api: api,
72
+ userIntent: "tableDragMenuPopupOpen"
73
+ }, /*#__PURE__*/React.createElement(TableMenu, {
74
+ api: api,
75
+ editorView: editorView,
71
76
  surface: direction === 'row' ? ROW_MENU : COLUMN_MENU
72
- }) : /*#__PURE__*/React.createElement(DragMenu, {
77
+ })) : /*#__PURE__*/React.createElement(DragMenu, {
73
78
  editorView: editorView,
74
79
  isOpen: isOpen,
75
80
  tableNode: tableNode,
@@ -2,15 +2,7 @@ import React from 'react';
2
2
  import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
3
3
  import { MergeCellsItem } from './items/MergeCellsItem';
4
4
  import { SplitCellItem } from './items/SplitCellItem';
5
- import { CELL_MENU, CELL_ACTION_SECTION, CELL_DANGER_SECTION, CELL_MENU_SECTION_RANK, MERGE_CELLS_ITEM, SPLIT_CELL_ITEM, CELL_ACTION_SECTION_RANK } from './keys';
6
-
7
- /**
8
- * Returns the RegisterComponent[] array defining the cell contextual menu surface.
9
- *
10
- * This is a **UI-only stub** — all items are always visible with no conditional
11
- * logic and no wired actions. Functional behaviour (actions, conditional visibility)
12
- * will be connected in follow-up tickets.
13
- */
5
+ import { CELL_MENU, CELL_ACTION_SECTION, CELL_DANGER_SECTION, CELL_MENU_RANK, MERGE_CELLS_ITEM, SPLIT_CELL_ITEM, CELL_ACTION_SECTION_RANK } from './keys';
14
6
  export const getCellMenuComponents = () => [
15
7
  // --- Menu surface ---
16
8
  {
@@ -24,7 +16,7 @@ export const getCellMenuComponents = () => [
24
16
  parents: [{
25
17
  type: CELL_MENU.type,
26
18
  key: CELL_MENU.key,
27
- rank: CELL_MENU_SECTION_RANK[CELL_ACTION_SECTION.key]
19
+ rank: CELL_MENU_RANK[CELL_ACTION_SECTION.key]
28
20
  }],
29
21
  component: props => /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, props.children)
30
22
  }, {
@@ -53,7 +45,7 @@ export const getCellMenuComponents = () => [
53
45
  parents: [{
54
46
  type: CELL_MENU.type,
55
47
  key: CELL_MENU.key,
56
- rank: CELL_MENU_SECTION_RANK[CELL_DANGER_SECTION.key]
48
+ rank: CELL_MENU_RANK[CELL_DANGER_SECTION.key]
57
49
  }],
58
50
  component: props => /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
59
51
  hasSeparator: true
@@ -2,10 +2,21 @@ import React from 'react';
2
2
  import { useIntl } from 'react-intl';
3
3
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
4
4
  import { TableCellMergeIcon, ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
6
+
7
+ /**
8
+ * Merge cells is only visible when the active selection can actually be merged
9
+ * (multi-cell, non-overlapping).
10
+ */
11
+ const shouldShowMergeCells = tableMenuContext => (tableMenuContext === null || tableMenuContext === void 0 ? void 0 : tableMenuContext.canMergeCells) === true;
5
12
  export const MergeCellsItem = () => {
13
+ const tableMenuContext = useTableMenuContext();
6
14
  const {
7
15
  formatMessage
8
16
  } = useIntl();
17
+ if (!shouldShowMergeCells(tableMenuContext)) {
18
+ return null;
19
+ }
9
20
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
10
21
  elemBefore: /*#__PURE__*/React.createElement(TableCellMergeIcon, {
11
22
  label: "",
@@ -2,10 +2,21 @@ import React from 'react';
2
2
  import { useIntl } from 'react-intl';
3
3
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
4
4
  import { TableCellSplitIcon, ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
6
+
7
+ /**
8
+ * Split cell is only visible when the active selection sits in a cell whose
9
+ * `rowspan` or `colspan` is greater than one.
10
+ */
11
+ const shouldShowSplitCell = tableMenuContext => (tableMenuContext === null || tableMenuContext === void 0 ? void 0 : tableMenuContext.canSplitCell) === true;
5
12
  export const SplitCellItem = () => {
13
+ const tableMenuContext = useTableMenuContext();
6
14
  const {
7
15
  formatMessage
8
16
  } = useIntl();
17
+ if (!shouldShowSplitCell(tableMenuContext)) {
18
+ return null;
19
+ }
9
20
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
10
21
  elemBefore: /*#__PURE__*/React.createElement(TableCellSplitIcon, {
11
22
  label: "",
@@ -17,7 +17,7 @@ export const CELL_DANGER_SECTION = {
17
17
  type: 'menu-section',
18
18
  key: 'cell-danger-section'
19
19
  };
20
- export const CELL_MENU_SECTION_RANK = {
20
+ export const CELL_MENU_RANK = {
21
21
  [CELL_ACTION_SECTION.key]: 100,
22
22
  [CELL_DANGER_SECTION.key]: 200
23
23
  };
@@ -2,6 +2,8 @@ import React from 'react';
2
2
  import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
3
3
  import { AddColumnLeftItem } from './items/AddColumnLeftItem';
4
4
  import { AddColumnRightItem } from './items/AddColumnRightItem';
5
+ import { ColumnBackgroundSection } from './items/ColumnBackgroundSection';
6
+ import { ColumnToggleSection } from './items/ColumnToggleSection';
5
7
  import { DeleteColumnItem } from './items/DeleteColumnItem';
6
8
  import { DistributeColumnsItem } from './items/DistributeColumnsItem';
7
9
  import { HeaderColumnToggleItem } from './items/HeaderColumnToggleItem';
@@ -9,14 +11,6 @@ import { MoveColumnRightItem } from './items/MoveColumnRightItem';
9
11
  import { SortDecreasingItem } from './items/SortDecreasingItem';
10
12
  import { SortIncreasingItem } from './items/SortIncreasingItem';
11
13
  import { COLUMN_MENU, COLUMN_TOGGLE_SECTION, COLUMN_BACKGROUND_SECTION, COLUMN_SORT_SECTION, COLUMN_ADD_SECTION, COLUMN_DANGER_SECTION, COLUMN_SECTION_RANK, HEADER_COLUMN_TOGGLE_ITEM, SORT_INCREASING_ITEM, SORT_DECREASING_ITEM, ADD_COLUMN_LEFT_ITEM, ADD_COLUMN_RIGHT_ITEM, MOVE_COLUMN_RIGHT_ITEM, DISTRIBUTE_COLUMNS_ITEM, DELETE_COLUMN_ITEM, COLUMN_TOGGLE_SECTION_RANK, COLUMN_SORT_SECTION_RANK, COLUMN_ADD_SECTION_RANK, COLUMN_DANGER_SECTION_RANK } from './keys';
12
-
13
- /**
14
- * Returns the RegisterComponent[] array defining the column menu surface.
15
- *
16
- * This is a **UI-only stub** — all items are always visible with no conditional
17
- * logic and no wired actions. Functional behaviour (actions, conditional visibility)
18
- * will be connected in follow-up tickets.
19
- */
20
14
  export const getColumnMenuComponents = () => [
21
15
  // --- Menu surface ---
22
16
  {
@@ -32,7 +26,7 @@ export const getColumnMenuComponents = () => [
32
26
  key: COLUMN_MENU.key,
33
27
  rank: COLUMN_SECTION_RANK[COLUMN_TOGGLE_SECTION.key]
34
28
  }],
35
- component: props => /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, props.children)
29
+ component: props => /*#__PURE__*/React.createElement(ColumnToggleSection, null, props.children)
36
30
  }, {
37
31
  type: HEADER_COLUMN_TOGGLE_ITEM.type,
38
32
  key: HEADER_COLUMN_TOGGLE_ITEM.key,
@@ -52,9 +46,7 @@ export const getColumnMenuComponents = () => [
52
46
  key: COLUMN_MENU.key,
53
47
  rank: COLUMN_SECTION_RANK[COLUMN_BACKGROUND_SECTION.key]
54
48
  }],
55
- component: props => /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
56
- hasSeparator: true
57
- }, props.children)
49
+ component: props => /*#__PURE__*/React.createElement(ColumnBackgroundSection, null, props.children)
58
50
  },
59
51
  // --- Sort section ---
60
52
  {
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
3
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
4
+ import { shouldShowHeaderColumnToggle } from './HeaderColumnToggleItem';
5
+
6
+ /**
7
+ * Background section sits directly below `ColumnToggleSection`. Its separator
8
+ * exists only to divide it from the toggle section; when the toggle section
9
+ * is hidden, the separator must drop too so we don't render a stray rule at
10
+ * the very top of the menu.
11
+ */
12
+ export const ColumnBackgroundSection = ({
13
+ children
14
+ }) => {
15
+ const tableMenuContext = useTableMenuContext();
16
+ const hasSeparator = shouldShowHeaderColumnToggle(tableMenuContext);
17
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
18
+ hasSeparator: hasSeparator
19
+ }, children);
20
+ };
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
3
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
4
+ import { shouldShowHeaderColumnToggle } from './HeaderColumnToggleItem';
5
+
6
+ /**
7
+ * The toggle section currently contains only the Header column toggle. When
8
+ * that item is hidden, the whole section disappears so we don't render an
9
+ * empty wrapper (and so the section below can drop its leading separator).
10
+ */
11
+ export const ColumnToggleSection = ({
12
+ children
13
+ }) => {
14
+ const tableMenuContext = useTableMenuContext();
15
+ if (!shouldShowHeaderColumnToggle(tableMenuContext)) {
16
+ return null;
17
+ }
18
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
19
+ };
@@ -2,10 +2,21 @@ import React from 'react';
2
2
  import { useIntl } from 'react-intl';
3
3
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
4
4
  import { TableColumnsDistributeIcon, ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
6
+
7
+ /** Distribute columns is only visible when more than one column is selected. */
8
+ const shouldShowDistributeColumns = tableMenuContext => {
9
+ var _tableMenuContext$sel;
10
+ return ((_tableMenuContext$sel = tableMenuContext === null || tableMenuContext === void 0 ? void 0 : tableMenuContext.selectedColumnCount) !== null && _tableMenuContext$sel !== void 0 ? _tableMenuContext$sel : 0) > 1;
11
+ };
5
12
  export const DistributeColumnsItem = () => {
13
+ const tableMenuContext = useTableMenuContext();
6
14
  const {
7
15
  formatMessage
8
16
  } = useIntl();
17
+ if (!shouldShowDistributeColumns(tableMenuContext)) {
18
+ return null;
19
+ }
9
20
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
10
21
  elemBefore: /*#__PURE__*/React.createElement(TableColumnsDistributeIcon, {
11
22
  color: "currentColor",
@@ -3,11 +3,26 @@ import { useIntl } from 'react-intl';
3
3
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
4
4
  import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
5
  import Toggle from '@atlaskit/toggle';
6
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
7
+
8
+ /**
9
+ * Header column toggle is only visible when the first column is the entire
10
+ * selection.
11
+ *
12
+ * Exported so `ColumnToggleSection` (which can become empty) and
13
+ * `ColumnBackgroundSection` (which drops its leading separator alongside)
14
+ * can stay in lockstep with this rule without redefining it.
15
+ */
16
+ export const shouldShowHeaderColumnToggle = tableMenuContext => (tableMenuContext === null || tableMenuContext === void 0 ? void 0 : tableMenuContext.isFirstColumn) === true && tableMenuContext.selectedColumnCount === 1;
6
17
  export const HeaderColumnToggleItem = () => {
18
+ const tableMenuContext = useTableMenuContext();
7
19
  const {
8
20
  formatMessage
9
21
  } = useIntl();
10
22
  const label = formatMessage(messages.headerColumn);
23
+ if (!shouldShowHeaderColumnToggle(tableMenuContext)) {
24
+ return null;
25
+ }
11
26
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
12
27
  elemAfter: /*#__PURE__*/React.createElement(Toggle, {
13
28
  label: label,
@@ -2,12 +2,14 @@ import React from 'react';
2
2
  import { useIntl } from 'react-intl';
3
3
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
4
4
  import { ArrowDownIcon, ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
5
6
  export const SortDecreasingItem = () => {
7
+ const tableMenuContext = useTableMenuContext();
6
8
  const {
7
9
  formatMessage
8
10
  } = useIntl();
9
11
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
10
- isDisabled: true,
12
+ isDisabled: Boolean(tableMenuContext === null || tableMenuContext === void 0 ? void 0 : tableMenuContext.hasMergedCellsInTable),
11
13
  elemBefore: /*#__PURE__*/React.createElement(ArrowDownIcon, {
12
14
  color: "currentColor",
13
15
  label: "",
@@ -2,12 +2,14 @@ import React from 'react';
2
2
  import { useIntl } from 'react-intl';
3
3
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
4
4
  import { ArrowUpIcon, ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
5
6
  export const SortIncreasingItem = () => {
7
+ const tableMenuContext = useTableMenuContext();
6
8
  const {
7
9
  formatMessage
8
10
  } = useIntl();
9
11
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
10
- isDisabled: true,
12
+ isDisabled: Boolean(tableMenuContext === null || tableMenuContext === void 0 ? void 0 : tableMenuContext.hasMergedCellsInTable),
11
13
  elemBefore: /*#__PURE__*/React.createElement(ArrowUpIcon, {
12
14
  color: "currentColor",
13
15
  label: "",
@@ -8,14 +8,6 @@ import { MoveRowDownItem } from './items/MoveRowDownItem';
8
8
  import { MoveRowUpItem } from './items/MoveRowUpItem';
9
9
  import { NumberedRowsToggleItem } from './items/NumberedRowsToggleItem';
10
10
  import { ROW_MENU, ROW_TOGGLE_SECTION, ROW_BACKGROUND_SECTION, ROW_ADD_SECTION, ROW_DANGER_SECTION, ROW_MENU_SECTION_RANK, HEADER_ROW_TOGGLE_ITEM, NUMBERED_ROWS_TOGGLE_ITEM, ADD_ROW_ABOVE_ITEM, ADD_ROW_BELOW_ITEM, MOVE_ROW_UP_ITEM, MOVE_ROW_DOWN_ITEM, DELETE_ROW_ITEM, ROW_TOGGLE_SECTION_RANK, ROW_ADD_SECTION_RANK, ROW_DANGER_SECTION_RANK } from './keys';
11
-
12
- /**
13
- * Returns the RegisterComponent[] array defining the row menu surface.
14
- *
15
- * This is a **UI-only stub** — all items are always visible with no conditional
16
- * logic and no wired actions. Functional behaviour (actions, conditional visibility)
17
- * will be connected in follow-up tickets.
18
- */
19
11
  export const getRowMenuComponents = () => [
20
12
  // --- Menu surface ---
21
13
  {
@@ -3,11 +3,19 @@ import { useIntl } from 'react-intl';
3
3
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
4
4
  import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
5
  import Toggle from '@atlaskit/toggle';
6
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
7
+
8
+ /** Header row toggle is only visible when the first row is the entire selection. */
9
+ const shouldShowHeaderRowToggle = tableMenuContext => (tableMenuContext === null || tableMenuContext === void 0 ? void 0 : tableMenuContext.isFirstRow) === true && tableMenuContext.selectedRowCount === 1;
6
10
  export const HeaderRowToggleItem = () => {
11
+ const tableMenuContext = useTableMenuContext();
7
12
  const {
8
13
  formatMessage
9
14
  } = useIntl();
10
15
  const label = formatMessage(messages.headerRow);
16
+ if (!shouldShowHeaderRowToggle(tableMenuContext)) {
17
+ return null;
18
+ }
11
19
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
12
20
  elemAfter: /*#__PURE__*/React.createElement(Toggle, {
13
21
  label: label,
@@ -4,12 +4,20 @@ import { moveRowDown, moveRowDownOld, tooltip } from '@atlaskit/editor-common/ke
4
4
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
5
5
  import { TableRowMoveDownIcon, ToolbarDropdownItem, ToolbarKeyboardShortcutHint } from '@atlaskit/editor-toolbar';
6
6
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
7
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
7
8
  const getMoveRowDownShortcut = () => tooltip(expValEquals('editor-a11y-fy26-keyboard-move-row-column', 'isEnabled', true) ? moveRowDown : moveRowDownOld);
9
+
10
+ /** Move row down is hidden when the selection includes the last row (cannot move further down). */
11
+ const shouldShowMoveRowDown = tableMenuContext => !(tableMenuContext !== null && tableMenuContext !== void 0 && tableMenuContext.isLastRow);
8
12
  export const MoveRowDownItem = () => {
9
13
  var _getMoveRowDownShortc;
14
+ const tableMenuContext = useTableMenuContext();
10
15
  const {
11
16
  formatMessage
12
17
  } = useIntl();
18
+ if (!shouldShowMoveRowDown(tableMenuContext)) {
19
+ return null;
20
+ }
13
21
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
14
22
  elemBefore: /*#__PURE__*/React.createElement(TableRowMoveDownIcon, {
15
23
  color: "currentColor",
@@ -4,12 +4,20 @@ import { moveRowUp, moveRowUpOld, tooltip } from '@atlaskit/editor-common/keymap
4
4
  import { tableMessages as messages } from '@atlaskit/editor-common/messages';
5
5
  import { TableRowMoveUpIcon, ToolbarDropdownItem, ToolbarKeyboardShortcutHint } from '@atlaskit/editor-toolbar';
6
6
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
7
+ import { useTableMenuContext } from '../../shared/TableMenuContext';
7
8
  const getMoveRowUpShortcut = () => tooltip(expValEquals('editor-a11y-fy26-keyboard-move-row-column', 'isEnabled', true) ? moveRowUp : moveRowUpOld);
9
+
10
+ /** Move row up is hidden when the selection includes row 0 (cannot move further up). */
11
+ const shouldShowMoveRowUp = tableMenuContext => !(tableMenuContext !== null && tableMenuContext !== void 0 && tableMenuContext.isFirstRow);
8
12
  export const MoveRowUpItem = () => {
9
13
  var _getMoveRowUpShortcut;
14
+ const tableMenuContext = useTableMenuContext();
10
15
  const {
11
16
  formatMessage
12
17
  } = useIntl();
18
+ if (!shouldShowMoveRowUp(tableMenuContext)) {
19
+ return null;
20
+ }
13
21
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
14
22
  elemBefore: /*#__PURE__*/React.createElement(TableRowMoveUpIcon, {
15
23
  color: "currentColor",
@@ -2,28 +2,75 @@
2
2
  import "./TableMenu.compiled.css";
3
3
  import { ax, ix } from "@compiled/react/runtime";
4
4
  import React, { memo, useMemo } from 'react';
5
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
6
+ import { EditorToolbarProvider } from '@atlaskit/editor-common/toolbar';
7
+ import { TableMap } from '@atlaskit/editor-tables/table-map';
8
+ import { getSelectionRect } from '@atlaskit/editor-tables/utils';
5
9
  import { SurfaceRenderer } from '@atlaskit/editor-ui-control-model';
6
10
  import { Box } from '@atlaskit/primitives/compiled';
11
+ import { canSplitCellSelection } from '../../../pm-plugins/commands/split-cell';
12
+ import { canMergeCellSelection } from '../../../pm-plugins/transforms/merge';
13
+ import { TableMenuProvider } from './TableMenuContext';
7
14
  const tableMenuContainerStyles = {
8
15
  container: "_2rko1qi0 _1reo15vq _18m915vq _1bsb1178 _16qs130s _bfhk1bhr"
9
16
  };
17
+ const EMPTY_CONTEXT = {};
10
18
  export const TableMenu = /*#__PURE__*/memo(({
11
19
  api,
20
+ editorView,
12
21
  surface
13
22
  }) => {
14
23
  const components = useMemo(() => {
15
24
  var _api$uiControlRegistr, _api$uiControlRegistr2;
16
25
  return (_api$uiControlRegistr = api === null || api === void 0 ? void 0 : (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(surface.key)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [];
17
26
  }, [api, surface.key]);
27
+ const {
28
+ tableNode,
29
+ selection
30
+ } = useSharedPluginStateWithSelector(api !== null && api !== void 0 ? api : undefined, ['table', 'selection'], states => {
31
+ var _states$tableState, _states$selectionStat;
32
+ return {
33
+ tableNode: (_states$tableState = states.tableState) === null || _states$tableState === void 0 ? void 0 : _states$tableState.tableNode,
34
+ selection: (_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection
35
+ };
36
+ });
37
+ const tableMenuContext = useMemo(() => {
38
+ if (!selection || !tableNode) {
39
+ return EMPTY_CONTEXT;
40
+ }
41
+ const tableMap = TableMap.get(tableNode);
42
+ const selectionRect = getSelectionRect(selection);
43
+ const cellOps = {
44
+ canMergeCells: canMergeCellSelection(selection),
45
+ canSplitCell: canSplitCellSelection(selection),
46
+ hasMergedCellsInTable: tableMap.hasMergedCells()
47
+ };
48
+ if (!selectionRect) {
49
+ return cellOps;
50
+ }
51
+ return {
52
+ ...cellOps,
53
+ isFirstRow: selectionRect.top === 0,
54
+ isLastRow: selectionRect.bottom === tableMap.height,
55
+ selectedRowCount: selectionRect.bottom - selectionRect.top,
56
+ isFirstColumn: selectionRect.left === 0,
57
+ isLastColumn: selectionRect.right === tableMap.width,
58
+ selectedColumnCount: selectionRect.right - selectionRect.left
59
+ };
60
+ }, [selection, tableNode]);
18
61
  if (components.length === 0) {
19
62
  return null;
20
63
  }
21
- return /*#__PURE__*/React.createElement(Box, {
64
+ return /*#__PURE__*/React.createElement(EditorToolbarProvider, {
65
+ editorView: editorView !== null && editorView !== void 0 ? editorView : null
66
+ }, /*#__PURE__*/React.createElement(TableMenuProvider, {
67
+ value: tableMenuContext
68
+ }, /*#__PURE__*/React.createElement(Box, {
22
69
  xcss: tableMenuContainerStyles.container,
23
70
  testId: surface.key
24
71
  }, /*#__PURE__*/React.createElement(SurfaceRenderer, {
25
72
  surface: surface,
26
73
  components: components
27
- }));
74
+ }))));
28
75
  });
29
76
  TableMenu.displayName = 'TableMenu';
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ const TableMenuContext = /*#__PURE__*/React.createContext(undefined);
3
+ export const TableMenuProvider = TableMenuContext.Provider;
4
+ export const useTableMenuContext = () => React.useContext(TableMenuContext);
@@ -1 +1,2 @@
1
- export const TABLE_MENU_WIDTH = 280;
1
+ export const TABLE_MENU_WIDTH = 280;
2
+ export const TABLE_MENU_SELECTOR = '[data-testid="column-handle-menu"], [data-testid="row-handle-menu"], [data-toolbar-nested-dropdown-menu]';
@@ -8,6 +8,7 @@ import { findParentNodeOfTypeClosestToPos } from '@atlaskit/editor-prosemirror/u
8
8
  import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
9
9
  import { TableMap } from '@atlaskit/editor-tables/table-map';
10
10
  import { cellAround, findCellRectClosestToPos, findTable, getSelectionRect, removeTable } from '@atlaskit/editor-tables/utils';
11
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
11
12
  import { addResizeHandleDecorations, clearHoverSelection, hideInsertColumnOrRowButton, hideResizeHandleLine, hoverCell, hoverColumns, selectColumn, setEditorFocus, setTableHovered, showInsertColumnButton, showInsertRowButton, showResizeHandleLine } from '../pm-plugins/commands';
12
13
  import { getPluginState as getDragDropPluginState } from '../pm-plugins/drag-and-drop/plugin-factory';
13
14
  import { getPluginState } from '../pm-plugins/plugin-factory';
@@ -19,11 +20,13 @@ import { convertHTMLCellIndexToColumnIndex, getColumnIndexMappedToColumnIndexInF
19
20
  import { getColumnOrRowIndex, getMousePositionHorizontalRelativeByElement, getMousePositionVerticalRelativeByElement, hasResizeHandler, isCell, isColumnControlsDecorations, isCornerButton, isDragColumnFloatingInsertDot, isDragCornerButton, isDragRowFloatingInsertDot, isInsertRowButton, isResizeHandleDecoration, isRowControlsButton, isTableContainerOrWrapper, isTableControlsButton } from '../pm-plugins/utils/dom';
20
21
  import { getAllowAddColumnCustomStep } from '../pm-plugins/utils/get-allow-add-column-custom-step';
21
22
  import { TableCssClassName as ClassName, RESIZE_HANDLE_AREA_DECORATION_GAP } from '../types';
23
+ import { TABLE_MENU_SELECTOR } from './TableMenu/shared/consts';
22
24
  const isFocusingCalendar = event => event instanceof FocusEvent && event.relatedTarget instanceof HTMLElement && event.relatedTarget.getAttribute('aria-label') === 'calendar';
23
25
  const isFocusingModal = event => event instanceof FocusEvent && event.relatedTarget instanceof HTMLElement && event.relatedTarget.closest('[role="dialog"]');
24
26
  const isFocusingFloatingToolbar = event => event instanceof FocusEvent && event.relatedTarget instanceof HTMLElement && event.relatedTarget.closest('[role="toolbar"]');
25
27
  const isFocusingDragHandles = event => event instanceof FocusEvent && event.relatedTarget instanceof HTMLElement && event.relatedTarget.closest('button') && event.relatedTarget.getAttribute('draggable') === 'true';
26
28
  const isFocusingDragHandlesClickableZone = event => event instanceof FocusEvent && event.relatedTarget instanceof HTMLElement && event.relatedTarget.closest('button') && event.relatedTarget.classList.contains(ClassName.DRAG_HANDLE_BUTTON_CLICKABLE_ZONE);
29
+ const isFocusingTableMenu = event => expValEquals('platform_editor_table_menu_updates', 'isEnabled', true) && event instanceof FocusEvent && event.relatedTarget instanceof HTMLElement && Boolean(event.relatedTarget.closest(TABLE_MENU_SELECTOR));
27
30
  export const handleBlur = (view, event) => {
28
31
  const {
29
32
  state,
@@ -31,7 +34,7 @@ export const handleBlur = (view, event) => {
31
34
  } = view;
32
35
  // IE version check for ED-4665
33
36
  // Calendar focus check for ED-10466
34
- if (getBrowserInfo().ie_version !== 11 && !isFocusingCalendar(event) && !isFocusingModal(event) && !isFocusingFloatingToolbar(event) && !isFocusingDragHandles(event) && !isFocusingDragHandlesClickableZone(event)) {
37
+ if (getBrowserInfo().ie_version !== 11 && !isFocusingCalendar(event) && !isFocusingModal(event) && !isFocusingFloatingToolbar(event) && !isFocusingDragHandles(event) && !isFocusingDragHandlesClickableZone(event) && !isFocusingTableMenu(event)) {
35
38
  setEditorFocus(false)(state, dispatch);
36
39
  }
37
40
  event.preventDefault();
@@ -1,5 +1,21 @@
1
- import { splitCellWithType } from '@atlaskit/editor-tables/utils';
1
+ import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
2
+ import { cellWrapping, splitCellWithType } from '@atlaskit/editor-tables/utils';
2
3
  import { getPluginState } from '../plugin-factory';
4
+ export var canSplitCellSelection = function canSplitCellSelection(selection) {
5
+ var cellNode;
6
+ if (!(selection instanceof CellSelection)) {
7
+ cellNode = cellWrapping(selection.$from);
8
+ if (!cellNode) {
9
+ return false;
10
+ }
11
+ } else {
12
+ if (selection.$anchorCell.pos !== selection.$headCell.pos) {
13
+ return false;
14
+ }
15
+ cellNode = selection.$anchorCell.nodeAfter;
16
+ }
17
+ return Boolean(cellNode && (cellNode.attrs.colspan !== 1 || cellNode.attrs.rowspan !== 1));
18
+ };
3
19
 
4
20
  /**
5
21
  * We need to split cell keeping the right type of cell given current table configuration.
@@ -113,8 +113,7 @@ export function mergeCells(tr) {
113
113
  }
114
114
  return tr.replaceWith(table.pos, table.pos + table.node.nodeSize, fixedTable).setSelection(Selection.near(tr.doc.resolve((mergedCellPos || 0) + table.start)));
115
115
  }
116
- export function canMergeCells(tr) {
117
- var selection = tr.selection;
116
+ export function canMergeCellSelection(selection) {
118
117
  if (!(selection instanceof CellSelection) || selection.$anchorCell.pos === selection.$headCell.pos) {
119
118
  return false;
120
119
  }
@@ -129,6 +128,9 @@ export function canMergeCells(tr) {
129
128
  }
130
129
  return true;
131
130
  }
131
+ export function canMergeCells(tr) {
132
+ return canMergeCellSelection(tr.selection);
133
+ }
132
134
  function isEmptyCell(cell) {
133
135
  var content = cell.content;
134
136
  return content.childCount === 1 && content.firstChild && content.firstChild.isTextblock && content.firstChild.childCount === 0;
@@ -90,6 +90,7 @@ export var CellMenuPopup = function CellMenuPopup(_ref) {
90
90
  ref: tableMenuRef
91
91
  }, /*#__PURE__*/React.createElement(TableMenu, {
92
92
  api: api,
93
+ editorView: editorView,
93
94
  surface: CELL_MENU
94
95
  })));
95
96
  };
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Popup } from '@atlaskit/editor-common/ui';
3
+ import { UserIntentPopupWrapper } from '@atlaskit/editor-common/user-intent';
3
4
  import { akEditorFloatingDialogZIndex, akEditorFloatingOverlapPanelZIndex } from '@atlaskit/editor-shared-styles';
4
5
  import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
5
6
  import { fg } from '@atlaskit/platform-feature-flags';
@@ -65,10 +66,14 @@ var FloatingDragMenu = function FloatingDragMenu(_ref) {
65
66
  forcePlacement: true,
66
67
  offset: expValEquals('platform_editor_table_menu_updates', 'isEnabled', true) ? [TABLE_MENU_OFFSET, 0] : direction === 'row' ? [-9, 0] : [0, -7],
67
68
  stick: true
68
- }, expValEquals('platform_editor_table_menu_updates', 'isEnabled', true) ? /*#__PURE__*/React.createElement(TableMenu, {
69
+ }, expValEquals('platform_editor_table_menu_updates', 'isEnabled', true) ? /*#__PURE__*/React.createElement(UserIntentPopupWrapper, {
69
70
  api: api,
71
+ userIntent: "tableDragMenuPopupOpen"
72
+ }, /*#__PURE__*/React.createElement(TableMenu, {
73
+ api: api,
74
+ editorView: editorView,
70
75
  surface: direction === 'row' ? ROW_MENU : COLUMN_MENU
71
- }) : /*#__PURE__*/React.createElement(DragMenu, {
76
+ })) : /*#__PURE__*/React.createElement(DragMenu, {
72
77
  editorView: editorView,
73
78
  isOpen: isOpen,
74
79
  tableNode: tableNode,