@atlaskit/editor-plugin-layout 10.8.1 → 10.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/cjs/layoutPlugin.js +2 -5
  3. package/dist/cjs/pm-plugins/actions.js +112 -115
  4. package/dist/cjs/pm-plugins/utils/layout-column-selection.js +63 -96
  5. package/dist/cjs/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +7 -2
  6. package/dist/cjs/ui/LayoutColumnMenu/DistributeColumnsDropdownItem.js +16 -6
  7. package/dist/cjs/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +4 -4
  8. package/dist/cjs/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +1 -1
  9. package/dist/cjs/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +2 -2
  10. package/dist/cjs/ui/LayoutColumnMenu/components.js +20 -9
  11. package/dist/cjs/ui/LayoutColumnMenu/index.js +6 -2
  12. package/dist/cjs/ui/LayoutColumnMenu/keys.js +8 -3
  13. package/dist/cjs/ui/LayoutColumnMenu/useSelectedLayoutColumns.js +4 -3
  14. package/dist/cjs/ui/LayoutColumnMenu/verticalAlignIcons.js +6 -6
  15. package/dist/cjs/ui/toolbar.js +69 -11
  16. package/dist/es2019/layoutPlugin.js +2 -5
  17. package/dist/es2019/pm-plugins/actions.js +45 -51
  18. package/dist/es2019/pm-plugins/utils/layout-column-selection.js +62 -91
  19. package/dist/es2019/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +8 -3
  20. package/dist/es2019/ui/LayoutColumnMenu/DistributeColumnsDropdownItem.js +18 -7
  21. package/dist/es2019/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +4 -4
  22. package/dist/es2019/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +1 -1
  23. package/dist/es2019/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +2 -2
  24. package/dist/es2019/ui/LayoutColumnMenu/components.js +23 -10
  25. package/dist/es2019/ui/LayoutColumnMenu/index.js +6 -2
  26. package/dist/es2019/ui/LayoutColumnMenu/keys.js +10 -3
  27. package/dist/es2019/ui/LayoutColumnMenu/useSelectedLayoutColumns.js +6 -4
  28. package/dist/es2019/ui/LayoutColumnMenu/verticalAlignIcons.js +6 -6
  29. package/dist/es2019/ui/toolbar.js +67 -11
  30. package/dist/esm/layoutPlugin.js +3 -6
  31. package/dist/esm/pm-plugins/actions.js +113 -116
  32. package/dist/esm/pm-plugins/utils/layout-column-selection.js +62 -95
  33. package/dist/esm/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +8 -3
  34. package/dist/esm/ui/LayoutColumnMenu/DistributeColumnsDropdownItem.js +17 -7
  35. package/dist/esm/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +4 -4
  36. package/dist/esm/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +1 -1
  37. package/dist/esm/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +2 -2
  38. package/dist/esm/ui/LayoutColumnMenu/components.js +21 -10
  39. package/dist/esm/ui/LayoutColumnMenu/index.js +6 -2
  40. package/dist/esm/ui/LayoutColumnMenu/keys.js +7 -2
  41. package/dist/esm/ui/LayoutColumnMenu/useSelectedLayoutColumns.js +5 -4
  42. package/dist/esm/ui/LayoutColumnMenu/verticalAlignIcons.js +6 -6
  43. package/dist/esm/ui/toolbar.js +70 -12
  44. package/dist/types/layoutPluginType.d.ts +3 -1
  45. package/dist/types/pm-plugins/actions.d.ts +5 -1
  46. package/dist/types/pm-plugins/utils/layout-column-selection.d.ts +9 -8
  47. package/dist/types/ui/LayoutColumnMenu/keys.d.ts +2 -0
  48. package/dist/types/ui/LayoutColumnMenu/verticalAlignIcons.d.ts +2 -2
  49. package/dist/types-ts4.5/layoutPluginType.d.ts +3 -1
  50. package/dist/types-ts4.5/pm-plugins/actions.d.ts +5 -1
  51. package/dist/types-ts4.5/pm-plugins/utils/layout-column-selection.d.ts +9 -8
  52. package/dist/types-ts4.5/ui/LayoutColumnMenu/keys.d.ts +2 -0
  53. package/dist/types-ts4.5/ui/LayoutColumnMenu/verticalAlignIcons.d.ts +2 -2
  54. package/package.json +4 -3
@@ -1,121 +1,92 @@
1
1
  import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
2
- import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
3
- const isLayoutColumn = node => (node === null || node === void 0 ? void 0 : node.type.name) === 'layoutColumn';
4
- const isLayoutSection = node => (node === null || node === void 0 ? void 0 : node.type.name) === 'layoutSection';
5
- const getLayoutColumnIndexAtPos = $pos => {
6
- for (let depth = $pos.depth; depth > 0; depth--) {
7
- if (isLayoutColumn($pos.node(depth)) && isLayoutSection($pos.node(depth - 1))) {
8
- return $pos.index(depth - 1);
9
- }
10
- }
11
- return undefined;
12
- };
13
- const getLayoutSectionDepth = selection => {
2
+ import { findChildrenByType, findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
3
+ const findLayoutSectionFromSelection = selection => {
14
4
  const {
15
- $from,
16
- $to
17
- } = selection;
18
- const sharedDepth = $from.sharedDepth($to.pos);
19
- for (let depth = sharedDepth; depth > 0; depth--) {
20
- if (isLayoutSection($from.node(depth))) {
21
- return depth;
22
- }
23
- }
24
- return undefined;
25
- };
26
- export const getSelectedLayoutColumns = selection => {
27
- if (!selection) {
28
- return undefined;
29
- }
30
- if (selection instanceof NodeSelection && isLayoutColumn(selection.node)) {
31
- const {
32
- $from
33
- } = selection;
34
- const layoutSectionNode = $from.parent;
35
- if (!isLayoutSection(layoutSectionNode)) {
36
- return undefined;
37
- }
38
- const selectedColumnIndex = $from.index($from.depth);
5
+ layoutSection
6
+ } = selection.$from.doc.type.schema.nodes;
7
+ // NodeSelection on the layoutSection node itself
8
+ if (selection instanceof NodeSelection && selection.node.type === layoutSection) {
39
9
  return {
40
- layoutSectionNode,
41
- layoutSectionPos: $from.before($from.depth),
42
- selectedColumnIndices: [selectedColumnIndex],
43
- selectedColumns: [{
44
- index: selectedColumnIndex,
45
- node: selection.node,
46
- pos: selection.from
47
- }]
10
+ node: selection.node,
11
+ pos: selection.from
48
12
  };
49
13
  }
50
- if (selection.empty) {
51
- return undefined;
52
- }
53
- if (!editorExperiment('platform_editor_block_menu', true)) {
14
+ return findParentNodeOfType(layoutSection)(selection);
15
+ };
16
+ const findLayoutColumnsFromLayoutSection = (layoutSectionNode, layoutSectionPos = 0) => {
17
+ return findChildrenByType(layoutSectionNode, layoutSectionNode.type.schema.nodes.layoutColumn).map(({
18
+ node,
19
+ pos
20
+ }) => ({
21
+ node,
22
+ pos: pos + layoutSectionPos + 1
23
+ }));
24
+ };
25
+ export const getSelectedLayoutColumnsFromSelection = selection => {
26
+ const layoutSection = findLayoutSectionFromSelection(selection);
27
+ if (!layoutSection) {
54
28
  return undefined;
55
29
  }
56
- const layoutSectionDepth = getLayoutSectionDepth(selection);
57
- if (layoutSectionDepth === undefined) {
30
+ const {
31
+ node: layoutSectionNode,
32
+ pos: layoutSectionPos
33
+ } = layoutSection;
34
+ const allLayoutColumns = findLayoutColumnsFromLayoutSection(layoutSectionNode, layoutSectionPos);
35
+ if (!allLayoutColumns.length) {
58
36
  return undefined;
59
37
  }
60
- const {
61
- $from,
62
- $to
63
- } = selection;
64
- const layoutSectionNode = $from.node(layoutSectionDepth);
65
- const layoutSectionPos = $from.before(layoutSectionDepth);
66
- const selectedColumns = [];
67
- let invalidSelection = false;
68
- layoutSectionNode.forEach((column, offset, index) => {
69
- const columnStart = layoutSectionPos + 1 + offset;
70
- const columnEnd = columnStart + column.nodeSize;
71
- const intersectsColumn = selection.from < columnEnd && selection.to > columnStart;
72
- if (!intersectsColumn) {
73
- return;
74
- }
75
- if (!isLayoutColumn(column)) {
76
- invalidSelection = true;
77
- return;
38
+ let startIndex = -1;
39
+ let endIndex = -1;
40
+ const selectedLayoutColumns = allLayoutColumns.filter(({
41
+ node,
42
+ pos
43
+ }, index) => {
44
+ const isSelected = selection.from <= pos && selection.to >= pos + node.nodeSize;
45
+ if (isSelected) {
46
+ if (startIndex === -1) {
47
+ startIndex = index;
48
+ }
49
+ endIndex = index;
78
50
  }
79
- selectedColumns.push({
80
- index,
81
- node: column,
82
- pos: columnStart
83
- });
51
+ return isSelected;
84
52
  });
85
-
86
- // TextSelection inside a single column is normal text editing, not a selected column set.
87
- if (invalidSelection || selectedColumns.length < 2) {
53
+ return {
54
+ layoutSectionNode,
55
+ layoutSectionPos,
56
+ selectedLayoutColumns,
57
+ startIndex,
58
+ endIndex
59
+ };
60
+ };
61
+ export const getAllLayoutColumnsFromSelection = selection => {
62
+ const layoutSection = findLayoutSectionFromSelection(selection);
63
+ if (!layoutSection) {
88
64
  return undefined;
89
65
  }
90
- const firstColumn = selectedColumns[0];
91
- const lastColumn = selectedColumns[selectedColumns.length - 1];
92
- const startColumnIndex = getLayoutColumnIndexAtPos($from);
93
- const endColumnIndex = getLayoutColumnIndexAtPos($to);
94
- if (startColumnIndex !== undefined && startColumnIndex !== firstColumn.index || endColumnIndex !== undefined && endColumnIndex !== lastColumn.index) {
66
+ const layoutColumns = findLayoutColumnsFromLayoutSection(layoutSection.node, layoutSection.pos);
67
+ if (!(layoutColumns !== null && layoutColumns !== void 0 && layoutColumns.length)) {
95
68
  return undefined;
96
69
  }
97
70
  return {
98
- layoutSectionNode,
99
- layoutSectionPos,
100
- selectedColumnIndices: selectedColumns.map(({
101
- index
102
- }) => index),
103
- selectedColumns
71
+ layoutSectionNode: layoutSection.node,
72
+ layoutSectionPos: layoutSection.pos,
73
+ selectedLayoutColumns: layoutColumns,
74
+ startIndex: 0,
75
+ endIndex: layoutColumns.length - 1
104
76
  };
105
77
  };
106
- export const getLayoutSectionColumnCount = layoutSection => (layoutSection === null || layoutSection === void 0 ? void 0 : layoutSection.type.name) === 'layoutSection' ? layoutSection.childCount : 0;
107
78
  export const getLayoutColumnValign = layoutColumn => {
108
79
  var _ref;
109
80
  return layoutColumn ? (_ref = layoutColumn.attrs.valign) !== null && _ref !== void 0 ? _ref : 'top' : undefined;
110
81
  };
111
82
  export const getLayoutColumnMenuAnchorPos = (selection, anchorPosFromHandle) => {
112
83
  var _clickedSelectedColum, _selectedLayoutColumn;
113
- const selectedLayoutColumns = getSelectedLayoutColumns(selection);
84
+ const selectedLayoutColumns = getSelectedLayoutColumnsFromSelection(selection);
114
85
  if (!selectedLayoutColumns) {
115
86
  return undefined;
116
87
  }
117
- const clickedSelectedColumn = selectedLayoutColumns.selectedColumns.find(({
88
+ const clickedSelectedColumn = selectedLayoutColumns.selectedLayoutColumns.find(({
118
89
  pos
119
90
  }) => pos === anchorPosFromHandle);
120
- return (_clickedSelectedColum = clickedSelectedColumn === null || clickedSelectedColumn === void 0 ? void 0 : clickedSelectedColumn.pos) !== null && _clickedSelectedColum !== void 0 ? _clickedSelectedColum : (_selectedLayoutColumn = selectedLayoutColumns.selectedColumns[0]) === null || _selectedLayoutColumn === void 0 ? void 0 : _selectedLayoutColumn.pos;
91
+ return (_clickedSelectedColum = clickedSelectedColumn === null || clickedSelectedColumn === void 0 ? void 0 : clickedSelectedColumn.pos) !== null && _clickedSelectedColum !== void 0 ? _clickedSelectedColum : (_selectedLayoutColumn = selectedLayoutColumns.selectedLayoutColumns[0]) === null || _selectedLayoutColumn === void 0 ? void 0 : _selectedLayoutColumn.pos;
121
92
  };
@@ -1,7 +1,7 @@
1
1
  import React, { useCallback } from 'react';
2
2
  import { useIntl } from 'react-intl';
3
3
  import { layoutMessages } from '@atlaskit/editor-common/messages';
4
- import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
4
+ import { DeleteIcon, ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
5
  import { useSelectedLayoutColumns } from './useSelectedLayoutColumns';
6
6
  const DeleteColumnDropdownItem = ({
7
7
  api
@@ -30,9 +30,14 @@ const DeleteColumnDropdownItem = ({
30
30
  if (selectedLayoutColumns === undefined) {
31
31
  return null;
32
32
  }
33
- const selectedColumnCount = selectedLayoutColumns.selectedColumns.length;
33
+ const selectedColumnCount = selectedLayoutColumns.selectedLayoutColumns.length;
34
34
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
35
- onClick: onClick
35
+ onClick: onClick,
36
+ elemBefore: /*#__PURE__*/React.createElement(DeleteIcon, {
37
+ color: "currentColor",
38
+ label: "",
39
+ size: "small"
40
+ })
36
41
  }, formatMessage(layoutMessages.deleteColumn, {
37
42
  count: selectedColumnCount
38
43
  }));
@@ -1,7 +1,8 @@
1
1
  import React, { useCallback, useMemo } from 'react';
2
2
  import { useIntl } from 'react-intl';
3
+ import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
3
4
  import { layoutMessages } from '@atlaskit/editor-common/messages';
4
- import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
+ import { TableColumnsDistributeIcon, ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
6
  import { isDistributedUniformly } from '../../pm-plugins/utils/layout-column-distribution';
6
7
  import { useSelectedLayoutColumns } from './useSelectedLayoutColumns';
7
8
  export const DistributeColumnsDropdownItem = ({
@@ -10,12 +11,17 @@ export const DistributeColumnsDropdownItem = ({
10
11
  const {
11
12
  formatMessage
12
13
  } = useIntl();
13
- const selectedLayoutColumns = useSelectedLayoutColumns(api);
14
+ const selectedLayoutColumnsResult = useSelectedLayoutColumns(api);
15
+ const {
16
+ selectedLayoutColumns
17
+ } = selectedLayoutColumnsResult !== null && selectedLayoutColumnsResult !== void 0 ? selectedLayoutColumnsResult : {};
14
18
  const handleClick = useCallback(() => {
15
19
  var _api$core;
16
20
  api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(props => {
17
21
  var _api$layout, _api$layout2;
18
- const tr = api === null || api === void 0 ? void 0 : (_api$layout = api.layout) === null || _api$layout === void 0 ? void 0 : _api$layout.commands.distributeLayoutColumns(props);
22
+ const tr = api === null || api === void 0 ? void 0 : (_api$layout = api.layout) === null || _api$layout === void 0 ? void 0 : _api$layout.commands.distributeLayoutColumns({
23
+ inputMethod: INPUT_METHOD.LAYOUT_COLUMN_MENU
24
+ })(props);
19
25
  if (!tr) {
20
26
  return null;
21
27
  }
@@ -28,17 +34,22 @@ export const DistributeColumnsDropdownItem = ({
28
34
  });
29
35
  }, [api]);
30
36
  const isAlreadyUniform = useMemo(() => {
31
- if (!selectedLayoutColumns || selectedLayoutColumns.selectedColumns.length < 2) {
37
+ if (!selectedLayoutColumns || selectedLayoutColumns.length < 2) {
32
38
  return false;
33
39
  }
34
- const selectedWidths = selectedLayoutColumns.selectedColumns.map(col => col.node.attrs.width);
40
+ const selectedWidths = selectedLayoutColumns.map(col => col.node.attrs.width);
35
41
  return isDistributedUniformly(selectedWidths);
36
42
  }, [selectedLayoutColumns]);
37
- if (selectedLayoutColumns === undefined || selectedLayoutColumns.selectedColumns.length < 2) {
43
+ if (selectedLayoutColumns === undefined || selectedLayoutColumns.length < 2) {
38
44
  return null;
39
45
  }
40
46
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
41
47
  onClick: handleClick,
42
- isDisabled: isAlreadyUniform
48
+ isDisabled: isAlreadyUniform,
49
+ elemBefore: /*#__PURE__*/React.createElement(TableColumnsDistributeIcon, {
50
+ color: "currentColor",
51
+ label: "",
52
+ size: "small"
53
+ })
43
54
  }, formatMessage(layoutMessages.distributeColumns));
44
55
  };
@@ -3,17 +3,16 @@ import { useIntl } from 'react-intl';
3
3
  import { layoutMessages } from '@atlaskit/editor-common/messages';
4
4
  import { TableColumnAddLeftIcon, TableColumnAddRightIcon, ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
5
  import { getEffectiveMaxLayoutColumns } from '../../pm-plugins/actions';
6
- import { getLayoutSectionColumnCount } from '../../pm-plugins/utils/layout-column-selection';
7
6
  import { useSelectedLayoutColumns } from './useSelectedLayoutColumns';
8
7
  const INSERT_COLUMN_OPTIONS = {
9
8
  left: {
10
9
  Icon: TableColumnAddLeftIcon,
11
- label: layoutMessages.insertColumnLeft,
10
+ label: layoutMessages.addColumnLeft,
12
11
  side: 'left'
13
12
  },
14
13
  right: {
15
14
  Icon: TableColumnAddRightIcon,
16
- label: layoutMessages.insertColumnRight,
15
+ label: layoutMessages.addColumnRight,
17
16
  side: 'right'
18
17
  }
19
18
  };
@@ -21,6 +20,7 @@ export const InsertColumnDropdownItem = ({
21
20
  api,
22
21
  side
23
22
  }) => {
23
+ var _selectedLayoutColumn, _selectedLayoutColumn2;
24
24
  const {
25
25
  formatMessage
26
26
  } = useIntl();
@@ -29,7 +29,7 @@ export const InsertColumnDropdownItem = ({
29
29
  label
30
30
  } = INSERT_COLUMN_OPTIONS[side];
31
31
  const selectedLayoutColumns = useSelectedLayoutColumns(api);
32
- const columnCount = getLayoutSectionColumnCount(selectedLayoutColumns === null || selectedLayoutColumns === void 0 ? void 0 : selectedLayoutColumns.layoutSectionNode);
32
+ const columnCount = (_selectedLayoutColumn = selectedLayoutColumns === null || selectedLayoutColumns === void 0 ? void 0 : (_selectedLayoutColumn2 = selectedLayoutColumns.layoutSectionNode) === null || _selectedLayoutColumn2 === void 0 ? void 0 : _selectedLayoutColumn2.childCount) !== null && _selectedLayoutColumn !== void 0 ? _selectedLayoutColumn : 0;
33
33
  const maxColumnCount = getEffectiveMaxLayoutColumns();
34
34
  const canInsertColumn = selectedLayoutColumns !== undefined && columnCount < maxColumnCount;
35
35
  const onClick = useCallback(() => {
@@ -14,7 +14,7 @@ export const VerticalAlignDropdownItem = ({
14
14
  formatMessage
15
15
  } = useIntl();
16
16
  const selectedLayoutColumns = useSelectedLayoutColumns(api);
17
- const isSelected = (_selectedLayoutColumn = selectedLayoutColumns === null || selectedLayoutColumns === void 0 ? void 0 : selectedLayoutColumns.selectedColumns.every(({
17
+ const isSelected = (_selectedLayoutColumn = selectedLayoutColumns === null || selectedLayoutColumns === void 0 ? void 0 : selectedLayoutColumns.selectedLayoutColumns.every(({
18
18
  node
19
19
  }) => getLayoutColumnValign(node) === value)) !== null && _selectedLayoutColumn !== void 0 ? _selectedLayoutColumn : false;
20
20
  const Icon = VERTICAL_ALIGN_ICONS[value];
@@ -14,7 +14,7 @@ export const VerticalAlignNestedMenu = ({
14
14
  } = useIntl();
15
15
  const selectedLayoutColumns = useSelectedLayoutColumns(api);
16
16
  const currentValign = useMemo(() => {
17
- const selectedColumns = selectedLayoutColumns === null || selectedLayoutColumns === void 0 ? void 0 : selectedLayoutColumns.selectedColumns;
17
+ const selectedColumns = selectedLayoutColumns === null || selectedLayoutColumns === void 0 ? void 0 : selectedLayoutColumns.selectedLayoutColumns;
18
18
  const firstColumn = selectedColumns === null || selectedColumns === void 0 ? void 0 : selectedColumns[0];
19
19
  const firstValign = getLayoutColumnValign(firstColumn === null || firstColumn === void 0 ? void 0 : firstColumn.node);
20
20
  if (!firstValign || !(selectedColumns !== null && selectedColumns !== void 0 && selectedColumns.every(({
@@ -24,7 +24,7 @@ export const VerticalAlignNestedMenu = ({
24
24
  }
25
25
  return firstValign;
26
26
  }, [selectedLayoutColumns]);
27
- const TriggerIcon = currentValign ? VERTICAL_ALIGN_ICONS[currentValign] : VERTICAL_ALIGN_ICONS.top;
27
+ const TriggerIcon = currentValign ? VERTICAL_ALIGN_ICONS[currentValign] : VERTICAL_ALIGN_ICONS.middle;
28
28
  return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
29
29
  elemBefore: /*#__PURE__*/React.createElement(TriggerIcon, {
30
30
  label: "",
@@ -6,7 +6,7 @@ import { ToolbarMenuContainer } from '@atlaskit/editor-toolbar/toolbar-menu-cont
6
6
  import { DeleteColumnDropdownItem } from './DeleteColumnDropdownItem';
7
7
  import { DistributeColumnsDropdownItem } from './DistributeColumnsDropdownItem';
8
8
  import { InsertColumnDropdownItem } from './InsertColumnDropdownItem';
9
- import { DELETE_COLUMN_MENU_ITEM, DISTRIBUTE_COLUMNS_MENU_ITEM, INSERT_COLUMN_LEFT_MENU_ITEM, INSERT_COLUMN_RIGHT_MENU_ITEM, LAYOUT_COLUMN_MENU, LAYOUT_COLUMN_MENU_RANK, LAYOUT_COLUMN_MENU_SECTION, LAYOUT_COLUMN_MENU_SECTION_RANK, LAYOUT_COLUMN_VERTICAL_ALIGN_MENU_SECTION, VERTICAL_ALIGN_BOTTOM_MENU_ITEM, VERTICAL_ALIGN_MENU, VERTICAL_ALIGN_MENU_RANK, VERTICAL_ALIGN_MENU_SECTION_RANK, VERTICAL_ALIGN_MIDDLE_MENU_ITEM, VERTICAL_ALIGN_TOP_MENU_ITEM } from './keys';
9
+ import { DELETE_COLUMN_MENU_ITEM, DISTRIBUTE_COLUMNS_MENU_ITEM, INSERT_COLUMN_LEFT_MENU_ITEM, INSERT_COLUMN_RIGHT_MENU_ITEM, LAYOUT_COLUMN_DANGER_SECTION, LAYOUT_COLUMN_DANGER_SECTION_RANK, LAYOUT_COLUMN_MENU, LAYOUT_COLUMN_MENU_RANK, LAYOUT_COLUMN_MENU_SECTION, LAYOUT_COLUMN_MENU_SECTION_RANK, LAYOUT_COLUMN_VERTICAL_ALIGN_MENU_SECTION, VERTICAL_ALIGN_BOTTOM_MENU_ITEM, VERTICAL_ALIGN_MENU, VERTICAL_ALIGN_MENU_RANK, VERTICAL_ALIGN_MENU_SECTION_RANK, VERTICAL_ALIGN_MIDDLE_MENU_ITEM, VERTICAL_ALIGN_TOP_MENU_ITEM } from './keys';
10
10
  import { VerticalAlignDropdownItem } from './VerticalAlignDropdownItem';
11
11
  import { VerticalAlignNestedMenu } from './VerticalAlignNestedMenu';
12
12
  const LayoutColumnMenuContainer = ({
@@ -63,15 +63,6 @@ export const getLayoutColumnMenuComponents = ({
63
63
  ...LAYOUT_COLUMN_MENU_SECTION,
64
64
  rank: LAYOUT_COLUMN_MENU_SECTION_RANK[DISTRIBUTE_COLUMNS_MENU_ITEM.key]
65
65
  }]
66
- }, {
67
- ...DELETE_COLUMN_MENU_ITEM,
68
- component: () => /*#__PURE__*/React.createElement(DeleteColumnDropdownItem, {
69
- api: api
70
- }),
71
- parents: [{
72
- ...LAYOUT_COLUMN_MENU_SECTION,
73
- rank: LAYOUT_COLUMN_MENU_SECTION_RANK[DELETE_COLUMN_MENU_ITEM.key]
74
- }]
75
66
  }, {
76
67
  ...VERTICAL_ALIGN_MENU,
77
68
  component: ({
@@ -122,5 +113,27 @@ export const getLayoutColumnMenuComponents = ({
122
113
  ...LAYOUT_COLUMN_VERTICAL_ALIGN_MENU_SECTION,
123
114
  rank: VERTICAL_ALIGN_MENU_SECTION_RANK[VERTICAL_ALIGN_BOTTOM_MENU_ITEM.key]
124
115
  }]
116
+ },
117
+ // --- Danger section (Delete column) ---
118
+ {
119
+ ...LAYOUT_COLUMN_DANGER_SECTION,
120
+ component: ({
121
+ children
122
+ }) => /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
123
+ hasSeparator: true
124
+ }, children),
125
+ parents: [{
126
+ ...LAYOUT_COLUMN_MENU,
127
+ rank: LAYOUT_COLUMN_MENU_RANK[LAYOUT_COLUMN_DANGER_SECTION.key]
128
+ }]
129
+ }, {
130
+ ...DELETE_COLUMN_MENU_ITEM,
131
+ component: () => /*#__PURE__*/React.createElement(DeleteColumnDropdownItem, {
132
+ api: api
133
+ }),
134
+ parents: [{
135
+ ...LAYOUT_COLUMN_DANGER_SECTION,
136
+ rank: LAYOUT_COLUMN_DANGER_SECTION_RANK[DELETE_COLUMN_MENU_ITEM.key]
137
+ }]
125
138
  }];
126
139
  };
@@ -3,6 +3,7 @@ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'
3
3
  import { DRAG_HANDLE_SELECTOR } from '@atlaskit/editor-common/styles';
4
4
  import { Popup } from '@atlaskit/editor-common/ui';
5
5
  import { withReactEditorViewOuterListeners } from '@atlaskit/editor-common/ui-react';
6
+ import { UserIntentPopupWrapper } from '@atlaskit/editor-common/user-intent';
6
7
  import { akEditorFloatingOverlapPanelZIndex } from '@atlaskit/editor-shared-styles';
7
8
  import { ToolbarDropdownMenuProvider } from '@atlaskit/editor-toolbar';
8
9
  import { SurfaceRenderer } from '@atlaskit/editor-ui-control-model';
@@ -18,7 +19,7 @@ const TOOLBAR_MENU_SELECTOR = '[data-toolbar-component="menu"]';
18
19
  */
19
20
  const getLayoutColumnMenuTarget = (editorView, selection, anchorPosFromHandle) => {
20
21
  var _columnDomRef$parentE;
21
- const anchorPos = getLayoutColumnMenuAnchorPos(selection, anchorPosFromHandle);
22
+ const anchorPos = selection && getLayoutColumnMenuAnchorPos(selection, anchorPosFromHandle);
22
23
  if (anchorPos === undefined) {
23
24
  return null;
24
25
  }
@@ -96,6 +97,9 @@ export const LayoutColumnMenu = /*#__PURE__*/React.memo(function LayoutColumnMen
96
97
  offset: LAYOUT_COLUMN_MENU_POPUP_OFFSET,
97
98
  handleClickOutside: handleClickOutside,
98
99
  handleEscapeKeydown: closeLayoutColumnMenu
100
+ }, /*#__PURE__*/React.createElement(UserIntentPopupWrapper, {
101
+ api: api,
102
+ userIntent: "layoutColumnMenuPopupOpen"
99
103
  }, /*#__PURE__*/React.createElement(ToolbarDropdownMenuProvider, {
100
104
  isOpen: isLayoutColumnMenuOpen,
101
105
  setIsOpen: handleSetIsOpen
@@ -103,5 +107,5 @@ export const LayoutColumnMenu = /*#__PURE__*/React.memo(function LayoutColumnMen
103
107
  components: components,
104
108
  fallbacks: LAYOUT_COLUMN_MENU_FALLBACKS,
105
109
  surface: LAYOUT_COLUMN_MENU
106
- })));
110
+ }))));
107
111
  });
@@ -15,8 +15,13 @@ export const LAYOUT_COLUMN_VERTICAL_ALIGN_MENU_SECTION = {
15
15
  type: 'menu-section',
16
16
  key: 'layout-column-vertical-align-menu-section'
17
17
  };
18
+ export const LAYOUT_COLUMN_DANGER_SECTION = {
19
+ type: 'menu-section',
20
+ key: 'layout-column-danger-section'
21
+ };
18
22
  export const LAYOUT_COLUMN_MENU_RANK = {
19
- [LAYOUT_COLUMN_MENU_SECTION.key]: 100
23
+ [LAYOUT_COLUMN_MENU_SECTION.key]: 100,
24
+ [LAYOUT_COLUMN_DANGER_SECTION.key]: 200
20
25
  };
21
26
 
22
27
  // --- Menus ---
@@ -63,8 +68,10 @@ export const LAYOUT_COLUMN_MENU_SECTION_RANK = {
63
68
  [VERTICAL_ALIGN_MENU.key]: 100,
64
69
  [INSERT_COLUMN_LEFT_MENU_ITEM.key]: 200,
65
70
  [INSERT_COLUMN_RIGHT_MENU_ITEM.key]: 300,
66
- [DISTRIBUTE_COLUMNS_MENU_ITEM.key]: 400,
67
- [DELETE_COLUMN_MENU_ITEM.key]: 500
71
+ [DISTRIBUTE_COLUMNS_MENU_ITEM.key]: 400
72
+ };
73
+ export const LAYOUT_COLUMN_DANGER_SECTION_RANK = {
74
+ [DELETE_COLUMN_MENU_ITEM.key]: 100
68
75
  };
69
76
  export const VERTICAL_ALIGN_MENU_RANK = {
70
77
  [LAYOUT_COLUMN_VERTICAL_ALIGN_MENU_SECTION.key]: 100
@@ -1,6 +1,8 @@
1
1
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
2
- import { getSelectedLayoutColumns } from '../../pm-plugins/utils/layout-column-selection';
3
- export const useSelectedLayoutColumns = api => useSharedPluginStateWithSelector(api, ['selection'], states => {
4
- var _states$selectionStat;
5
- return getSelectedLayoutColumns((_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection);
2
+ import { getSelectedLayoutColumnsFromSelection } from '../../pm-plugins/utils/layout-column-selection';
3
+ export const useSelectedLayoutColumns = api => useSharedPluginStateWithSelector(api, ['selection'], ({
4
+ selectionState
5
+ }) => {
6
+ const selectedLayoutColumns = (selectionState === null || selectionState === void 0 ? void 0 : selectionState.selection) && getSelectedLayoutColumnsFromSelection(selectionState.selection);
7
+ return selectedLayoutColumns !== null && selectedLayoutColumns !== void 0 && selectedLayoutColumns.selectedLayoutColumns.length ? selectedLayoutColumns : undefined;
6
8
  });
@@ -1,11 +1,11 @@
1
1
  // Disable no-re-export here, this is a useful mapping file for icon lookup used in multiple places
2
2
  /* eslint-disable @atlaskit/editor/no-re-export */
3
3
 
4
- import AlignContentBottomIcon from '@atlaskit/icon-lab/core/align-content-bottom';
5
- import AlignContentCenterVerticalIcon from '@atlaskit/icon-lab/core/align-content-center-vertical';
6
- import AlignContentTopIcon from '@atlaskit/icon-lab/core/align-content-top';
4
+ import AlignPositionBottomIcon from '@atlaskit/icon-lab/core/align-position-bottom';
5
+ import AlignPositionCenterVerticalIcon from '@atlaskit/icon-lab/core/align-position-center-vertical';
6
+ import AlignPositionTopIcon from '@atlaskit/icon-lab/core/align-position-top';
7
7
  export const VERTICAL_ALIGN_ICONS = {
8
- top: AlignContentTopIcon,
9
- middle: AlignContentCenterVerticalIcon,
10
- bottom: AlignContentBottomIcon
8
+ top: AlignPositionTopIcon,
9
+ middle: AlignPositionCenterVerticalIcon,
10
+ bottom: AlignPositionBottomIcon
11
11
  };
@@ -12,8 +12,11 @@ import LayoutThreeColumnsSidebarsIcon from '@atlaskit/icon/core/layout-three-col
12
12
  import LayoutTwoColumnsIcon from '@atlaskit/icon/core/layout-two-columns';
13
13
  import LayoutTwoColumnsSidebarLeftIcon from '@atlaskit/icon/core/layout-two-columns-sidebar-left';
14
14
  import LayoutTwoColumnsSidebarRightIcon from '@atlaskit/icon/core/layout-two-columns-sidebar-right';
15
+ import TableColumnsDistributeIcon from '@atlaskit/icon/core/table-columns-distribute';
16
+ import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
15
17
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
16
- import { deleteActiveLayoutNode, getPresetLayout, setPresetLayout } from '../pm-plugins/actions';
18
+ import { deleteActiveLayoutNode, distributeLayoutColumns, getPresetLayout, setPresetLayout } from '../pm-plugins/actions';
19
+ import { isDistributedUniformly } from '../pm-plugins/utils/layout-column-distribution';
17
20
  import { EditorLayoutFiveColumnsIcon, EditorLayoutFourColumnsIcon } from './icons/LayoutColumnsIcon';
18
21
  import { LayoutThreeWithLeftSidebarsIcon } from './icons/LayoutThreeWithLeftSidebars';
19
22
  import { LayoutThreeWithRightSidebarsIcon } from './icons/LayoutThreeWithRightSidebars';
@@ -52,7 +55,7 @@ const SIDEBAR_LAYOUT_TYPES = [{
52
55
  }];
53
56
 
54
57
  // These are used for advanced layout options
55
- const LAYOUT_WITH_TWO_COL_DISTRIBUTION = [{
58
+ const LAYOUT_WITH_TWO_COL_DISTRIBUTION_OLD = [{
56
59
  id: 'editor.layout.twoEquals',
57
60
  type: 'two_equal',
58
61
  title: toolbarMessages.twoColumns,
@@ -68,7 +71,7 @@ const LAYOUT_WITH_TWO_COL_DISTRIBUTION = [{
68
71
  title: toolbarMessages.leftSidebar,
69
72
  icon: LayoutTwoColumnsSidebarLeftIcon
70
73
  }];
71
- const LAYOUT_WITH_THREE_COL_DISTRIBUTION = [{
74
+ const LAYOUT_WITH_THREE_COL_DISTRIBUTION_OLD = [{
72
75
  id: 'editor.layout.threeEquals',
73
76
  type: 'three_equal',
74
77
  title: toolbarMessages.threeColumns,
@@ -91,6 +94,35 @@ const LAYOUT_WITH_THREE_COL_DISTRIBUTION = [{
91
94
  icon: LayoutThreeWithLeftSidebarsIcon,
92
95
  iconFallback: LayoutThreeWithLeftSidebarsIcon
93
96
  }];
97
+ const LAYOUT_WITH_TWO_COL_DISTRIBUTION = [{
98
+ id: 'editor.layout.twoRightSidebar',
99
+ type: 'two_right_sidebar',
100
+ title: toolbarMessages.rightSidebar,
101
+ icon: LayoutTwoColumnsSidebarRightIcon
102
+ }, {
103
+ id: 'editor.layout.twoLeftSidebar',
104
+ type: 'two_left_sidebar',
105
+ title: toolbarMessages.leftSidebar,
106
+ icon: LayoutTwoColumnsSidebarLeftIcon
107
+ }];
108
+ const LAYOUT_WITH_THREE_COL_DISTRIBUTION = [{
109
+ id: 'editor.layout.threeWithSidebars',
110
+ type: 'three_with_sidebars',
111
+ title: toolbarMessages.threeColumnsWithSidebars,
112
+ icon: LayoutThreeColumnsSidebarsIcon
113
+ }, {
114
+ id: 'editor.layout.threeRightSidebars',
115
+ type: 'three_right_sidebars',
116
+ title: toolbarMessages.threeColumnsWithRightSidebars,
117
+ icon: LayoutThreeWithRightSidebarsIcon,
118
+ iconFallback: LayoutThreeWithRightSidebarsIcon
119
+ }, {
120
+ id: 'editor.layout.threeLeftSidebars',
121
+ type: 'three_left_sidebars',
122
+ title: toolbarMessages.threeColumnsWithLeftSidebars,
123
+ icon: LayoutThreeWithLeftSidebarsIcon,
124
+ iconFallback: LayoutThreeWithLeftSidebarsIcon
125
+ }];
94
126
  const buildLayoutButton = (intl, item, currentLayout, editorAnalyticsAPI) => ({
95
127
  id: item.id,
96
128
  type: 'button',
@@ -103,7 +135,9 @@ const buildLayoutButton = (intl, item, currentLayout, editorAnalyticsAPI) => ({
103
135
  tabIndex: null
104
136
  });
105
137
  export const layoutToolbarTitle = 'Layout floating controls';
106
- const iconPlaceholder = LayoutTwoColumnsIcon; // TODO: ED-25466 - Replace with proper icon
138
+ const iconPlaceholder = /*#__PURE__*/React.createElement(LayoutTwoColumnsIcon, {
139
+ label: ""
140
+ }); // TODO: ED-25466 - Replace with proper icon
107
141
 
108
142
  const getLayoutColumnsIcons = colCount => {
109
143
  if (!editorExperiment('single_column_layouts', true) && !editorExperiment('platform_editor_controls', 'variant1')) {
@@ -130,11 +164,13 @@ const getLayoutColumnsIcons = colCount => {
130
164
  return undefined;
131
165
  }
132
166
  };
167
+ const getLayoutColumnWidths = node => {
168
+ return node.children.map(child => child.attrs.width);
169
+ };
133
170
  const getAdvancedLayoutItems = ({
134
171
  addSidebarLayouts,
135
172
  intl,
136
173
  editorAnalyticsAPI,
137
- state,
138
174
  node,
139
175
  nodeType,
140
176
  separator,
@@ -143,7 +179,8 @@ const getAdvancedLayoutItems = ({
143
179
  allowAdvancedSingleColumnLayout
144
180
  }) => {
145
181
  const numberOfColumns = node.content.childCount || 2;
146
- const distributionOptions = numberOfColumns === 2 ? LAYOUT_WITH_TWO_COL_DISTRIBUTION : numberOfColumns === 3 ? LAYOUT_WITH_THREE_COL_DISTRIBUTION : [];
182
+ const isLayoutColumnMenuEnabled = expValEqualsNoExposure('platform_editor_layout_column_menu', 'isEnabled', true);
183
+ const distributionOptions = isLayoutColumnMenuEnabled ? numberOfColumns === 2 ? LAYOUT_WITH_TWO_COL_DISTRIBUTION : numberOfColumns === 3 ? LAYOUT_WITH_THREE_COL_DISTRIBUTION : [] : numberOfColumns === 2 ? LAYOUT_WITH_TWO_COL_DISTRIBUTION_OLD : numberOfColumns === 3 ? LAYOUT_WITH_THREE_COL_DISTRIBUTION_OLD : [];
147
184
  const columnOptions = [{
148
185
  title: intl.formatMessage(layoutMessages.columnOption, {
149
186
  count: 2
@@ -177,7 +214,7 @@ const getAdvancedLayoutItems = ({
177
214
  onClick: setPresetLayout(editorAnalyticsAPI)('five_equal'),
178
215
  selected: numberOfColumns === 5
179
216
  }];
180
- const singleColumnOption = allowAdvancedSingleColumnLayout ? {
217
+ const dropdownOptions = [...(allowAdvancedSingleColumnLayout ? [{
181
218
  title: intl.formatMessage(layoutMessages.columnOption, {
182
219
  count: 1
183
220
  }),
@@ -185,17 +222,37 @@ const getAdvancedLayoutItems = ({
185
222
  icon: getLayoutColumnsIcons(1) || iconPlaceholder,
186
223
  onClick: setPresetLayout(editorAnalyticsAPI)('single'),
187
224
  selected: numberOfColumns === 1
188
- } : [];
225
+ }] : []), ...columnOptions];
226
+ const distributeColumnsButton = isLayoutColumnMenuEnabled && numberOfColumns > 1 ? {
227
+ disabled: isDistributedUniformly(getLayoutColumnWidths(node)),
228
+ icon: TableColumnsDistributeIcon,
229
+ onClick: (editorState, dispatch) => {
230
+ const tr = distributeLayoutColumns(editorAnalyticsAPI)({
231
+ inputMethod: INPUT_METHOD.FLOATING_TB,
232
+ target: 'allColumns'
233
+ })({
234
+ tr: editorState.tr
235
+ });
236
+ if (!tr) {
237
+ return false;
238
+ }
239
+ dispatch === null || dispatch === void 0 ? void 0 : dispatch(tr);
240
+ return true;
241
+ },
242
+ testId: 'layout-distribute-columns',
243
+ title: intl.formatMessage(layoutMessages.distributeColumns),
244
+ type: 'button'
245
+ } : undefined;
189
246
  return [{
190
247
  type: 'dropdown',
191
248
  title: intl.formatMessage(layoutMessages.columnOption, {
192
249
  count: numberOfColumns
193
250
  }),
194
251
  //`${numberOfColumns}-columns`,
195
- options: [singleColumnOption, columnOptions].flat(),
252
+ options: dropdownOptions,
196
253
  showSelected: true,
197
254
  testId: 'column-options-button'
198
- }, ...(distributionOptions.length > 0 ? [separator] : []), ...(addSidebarLayouts ? distributionOptions.map(i => buildLayoutButton(intl, i, currentLayout, editorAnalyticsAPI)) : [])];
255
+ }, ...(distributionOptions.length > 0 || distributeColumnsButton ? [separator] : []), ...(addSidebarLayouts ? distributionOptions.map(i => buildLayoutButton(intl, i, currentLayout, editorAnalyticsAPI)) : []), ...(distributeColumnsButton ? [distributeColumnsButton] : [])];
199
256
  };
200
257
  const fullHeightSeparator = {
201
258
  type: 'separator',
@@ -283,7 +340,6 @@ export const buildToolbar = (state, intl, pos, _allowBreakout, addSidebarLayouts
283
340
  addSidebarLayouts,
284
341
  intl,
285
342
  editorAnalyticsAPI,
286
- state,
287
343
  nodeType,
288
344
  node,
289
345
  separator,