@atlaskit/editor-plugin-layout 10.8.1 → 10.9.0

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 (41) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/cjs/layoutPlugin.js +2 -5
  3. package/dist/cjs/pm-plugins/actions.js +71 -67
  4. package/dist/cjs/pm-plugins/utils/layout-column-selection.js +56 -98
  5. package/dist/cjs/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +1 -1
  6. package/dist/cjs/ui/LayoutColumnMenu/DistributeColumnsDropdownItem.js +10 -5
  7. package/dist/cjs/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +2 -2
  8. package/dist/cjs/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +1 -1
  9. package/dist/cjs/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +1 -1
  10. package/dist/cjs/ui/LayoutColumnMenu/index.js +1 -1
  11. package/dist/cjs/ui/LayoutColumnMenu/useSelectedLayoutColumns.js +4 -3
  12. package/dist/cjs/ui/toolbar.js +70 -11
  13. package/dist/es2019/layoutPlugin.js +3 -6
  14. package/dist/es2019/pm-plugins/actions.js +50 -51
  15. package/dist/es2019/pm-plugins/utils/layout-column-selection.js +54 -94
  16. package/dist/es2019/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +1 -1
  17. package/dist/es2019/ui/LayoutColumnMenu/DistributeColumnsDropdownItem.js +11 -5
  18. package/dist/es2019/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +2 -2
  19. package/dist/es2019/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +1 -1
  20. package/dist/es2019/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +1 -1
  21. package/dist/es2019/ui/LayoutColumnMenu/index.js +1 -1
  22. package/dist/es2019/ui/LayoutColumnMenu/useSelectedLayoutColumns.js +6 -4
  23. package/dist/es2019/ui/toolbar.js +68 -11
  24. package/dist/esm/layoutPlugin.js +3 -6
  25. package/dist/esm/pm-plugins/actions.js +71 -67
  26. package/dist/esm/pm-plugins/utils/layout-column-selection.js +55 -97
  27. package/dist/esm/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +1 -1
  28. package/dist/esm/ui/LayoutColumnMenu/DistributeColumnsDropdownItem.js +10 -5
  29. package/dist/esm/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +2 -2
  30. package/dist/esm/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +1 -1
  31. package/dist/esm/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +1 -1
  32. package/dist/esm/ui/LayoutColumnMenu/index.js +1 -1
  33. package/dist/esm/ui/LayoutColumnMenu/useSelectedLayoutColumns.js +5 -4
  34. package/dist/esm/ui/toolbar.js +71 -12
  35. package/dist/types/layoutPluginType.d.ts +2 -2
  36. package/dist/types/pm-plugins/actions.d.ts +9 -1
  37. package/dist/types/pm-plugins/utils/layout-column-selection.d.ts +8 -7
  38. package/dist/types-ts4.5/layoutPluginType.d.ts +2 -2
  39. package/dist/types-ts4.5/pm-plugins/actions.d.ts +9 -1
  40. package/dist/types-ts4.5/pm-plugins/utils/layout-column-selection.d.ts +8 -7
  41. package/package.json +3 -3
@@ -22,8 +22,11 @@ var _layoutThreeColumnsSidebars = _interopRequireDefault(require("@atlaskit/icon
22
22
  var _layoutTwoColumns = _interopRequireDefault(require("@atlaskit/icon/core/layout-two-columns"));
23
23
  var _layoutTwoColumnsSidebarLeft = _interopRequireDefault(require("@atlaskit/icon/core/layout-two-columns-sidebar-left"));
24
24
  var _layoutTwoColumnsSidebarRight = _interopRequireDefault(require("@atlaskit/icon/core/layout-two-columns-sidebar-right"));
25
+ var _tableColumnsDistribute = _interopRequireDefault(require("@atlaskit/icon/core/table-columns-distribute"));
26
+ var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
25
27
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
26
28
  var _actions = require("../pm-plugins/actions");
29
+ var _layoutColumnDistribution = require("../pm-plugins/utils/layout-column-distribution");
27
30
  var _LayoutColumnsIcon = require("./icons/LayoutColumnsIcon");
28
31
  var _LayoutThreeWithLeftSidebars = require("./icons/LayoutThreeWithLeftSidebars");
29
32
  var _LayoutThreeWithRightSidebars = require("./icons/LayoutThreeWithRightSidebars");
@@ -65,7 +68,7 @@ var SIDEBAR_LAYOUT_TYPES = [{
65
68
  }];
66
69
 
67
70
  // These are used for advanced layout options
68
- var LAYOUT_WITH_TWO_COL_DISTRIBUTION = [{
71
+ var LAYOUT_WITH_TWO_COL_DISTRIBUTION_OLD = [{
69
72
  id: 'editor.layout.twoEquals',
70
73
  type: 'two_equal',
71
74
  title: _messages.layoutMessages.twoColumns,
@@ -81,7 +84,7 @@ var LAYOUT_WITH_TWO_COL_DISTRIBUTION = [{
81
84
  title: _messages.layoutMessages.leftSidebar,
82
85
  icon: _layoutTwoColumnsSidebarLeft.default
83
86
  }];
84
- var LAYOUT_WITH_THREE_COL_DISTRIBUTION = [{
87
+ var LAYOUT_WITH_THREE_COL_DISTRIBUTION_OLD = [{
85
88
  id: 'editor.layout.threeEquals',
86
89
  type: 'three_equal',
87
90
  title: _messages.layoutMessages.threeColumns,
@@ -104,6 +107,35 @@ var LAYOUT_WITH_THREE_COL_DISTRIBUTION = [{
104
107
  icon: _LayoutThreeWithLeftSidebars.LayoutThreeWithLeftSidebarsIcon,
105
108
  iconFallback: _LayoutThreeWithLeftSidebars.LayoutThreeWithLeftSidebarsIcon
106
109
  }];
110
+ var LAYOUT_WITH_TWO_COL_DISTRIBUTION = [{
111
+ id: 'editor.layout.twoRightSidebar',
112
+ type: 'two_right_sidebar',
113
+ title: _messages.layoutMessages.rightSidebar,
114
+ icon: _layoutTwoColumnsSidebarRight.default
115
+ }, {
116
+ id: 'editor.layout.twoLeftSidebar',
117
+ type: 'two_left_sidebar',
118
+ title: _messages.layoutMessages.leftSidebar,
119
+ icon: _layoutTwoColumnsSidebarLeft.default
120
+ }];
121
+ var LAYOUT_WITH_THREE_COL_DISTRIBUTION = [{
122
+ id: 'editor.layout.threeWithSidebars',
123
+ type: 'three_with_sidebars',
124
+ title: _messages.layoutMessages.threeColumnsWithSidebars,
125
+ icon: _layoutThreeColumnsSidebars.default
126
+ }, {
127
+ id: 'editor.layout.threeRightSidebars',
128
+ type: 'three_right_sidebars',
129
+ title: _messages.layoutMessages.threeColumnsWithRightSidebars,
130
+ icon: _LayoutThreeWithRightSidebars.LayoutThreeWithRightSidebarsIcon,
131
+ iconFallback: _LayoutThreeWithRightSidebars.LayoutThreeWithRightSidebarsIcon
132
+ }, {
133
+ id: 'editor.layout.threeLeftSidebars',
134
+ type: 'three_left_sidebars',
135
+ title: _messages.layoutMessages.threeColumnsWithLeftSidebars,
136
+ icon: _LayoutThreeWithLeftSidebars.LayoutThreeWithLeftSidebarsIcon,
137
+ iconFallback: _LayoutThreeWithLeftSidebars.LayoutThreeWithLeftSidebarsIcon
138
+ }];
107
139
  var buildLayoutButton = function buildLayoutButton(intl, item, currentLayout, editorAnalyticsAPI) {
108
140
  return {
109
141
  id: item.id,
@@ -118,7 +150,9 @@ var buildLayoutButton = function buildLayoutButton(intl, item, currentLayout, ed
118
150
  };
119
151
  };
120
152
  var layoutToolbarTitle = exports.layoutToolbarTitle = 'Layout floating controls';
121
- var iconPlaceholder = _layoutTwoColumns.default; // TODO: ED-25466 - Replace with proper icon
153
+ var iconPlaceholder = /*#__PURE__*/_react.default.createElement(_layoutTwoColumns.default, {
154
+ label: ""
155
+ }); // TODO: ED-25466 - Replace with proper icon
122
156
 
123
157
  var getLayoutColumnsIcons = function getLayoutColumnsIcons(colCount) {
124
158
  if (!(0, _experiments.editorExperiment)('single_column_layouts', true) && !(0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) {
@@ -145,11 +179,15 @@ var getLayoutColumnsIcons = function getLayoutColumnsIcons(colCount) {
145
179
  return undefined;
146
180
  }
147
181
  };
182
+ var getLayoutColumnWidths = function getLayoutColumnWidths(node) {
183
+ return node.children.map(function (child) {
184
+ return child.attrs.width;
185
+ });
186
+ };
148
187
  var getAdvancedLayoutItems = function getAdvancedLayoutItems(_ref) {
149
188
  var addSidebarLayouts = _ref.addSidebarLayouts,
150
189
  intl = _ref.intl,
151
190
  editorAnalyticsAPI = _ref.editorAnalyticsAPI,
152
- state = _ref.state,
153
191
  node = _ref.node,
154
192
  nodeType = _ref.nodeType,
155
193
  separator = _ref.separator,
@@ -157,7 +195,8 @@ var getAdvancedLayoutItems = function getAdvancedLayoutItems(_ref) {
157
195
  currentLayout = _ref.currentLayout,
158
196
  allowAdvancedSingleColumnLayout = _ref.allowAdvancedSingleColumnLayout;
159
197
  var numberOfColumns = node.content.childCount || 2;
160
- var distributionOptions = numberOfColumns === 2 ? LAYOUT_WITH_TWO_COL_DISTRIBUTION : numberOfColumns === 3 ? LAYOUT_WITH_THREE_COL_DISTRIBUTION : [];
198
+ var isLayoutColumnMenuEnabled = (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_layout_column_menu', 'isEnabled', true);
199
+ var 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 : [];
161
200
  var columnOptions = [{
162
201
  title: intl.formatMessage(_messages.layoutMessages.columnOption, {
163
202
  count: 2
@@ -191,7 +230,7 @@ var getAdvancedLayoutItems = function getAdvancedLayoutItems(_ref) {
191
230
  onClick: (0, _actions.setPresetLayout)(editorAnalyticsAPI)('five_equal'),
192
231
  selected: numberOfColumns === 5
193
232
  }];
194
- var singleColumnOption = allowAdvancedSingleColumnLayout ? {
233
+ var dropdownOptions = [].concat((0, _toConsumableArray2.default)(allowAdvancedSingleColumnLayout ? [{
195
234
  title: intl.formatMessage(_messages.layoutMessages.columnOption, {
196
235
  count: 1
197
236
  }),
@@ -199,19 +238,40 @@ var getAdvancedLayoutItems = function getAdvancedLayoutItems(_ref) {
199
238
  icon: getLayoutColumnsIcons(1) || iconPlaceholder,
200
239
  onClick: (0, _actions.setPresetLayout)(editorAnalyticsAPI)('single'),
201
240
  selected: numberOfColumns === 1
202
- } : [];
241
+ }] : []), columnOptions);
242
+ var distributeColumnsButton = isLayoutColumnMenuEnabled && numberOfColumns > 1 ? {
243
+ disabled: (0, _layoutColumnDistribution.isDistributedUniformly)(getLayoutColumnWidths(node)),
244
+ icon: _tableColumnsDistribute.default,
245
+ onClick: function onClick(editorState, dispatch) {
246
+ var tr = (0, _actions.distributeLayoutColumns)({
247
+ editorAnalyticsAPI: editorAnalyticsAPI,
248
+ inputMethod: _analytics.INPUT_METHOD.FLOATING_TB,
249
+ target: 'allColumns'
250
+ })({
251
+ tr: editorState.tr
252
+ });
253
+ if (!tr) {
254
+ return false;
255
+ }
256
+ dispatch === null || dispatch === void 0 || dispatch(tr);
257
+ return true;
258
+ },
259
+ testId: 'layout-distribute-columns',
260
+ title: intl.formatMessage(_messages.layoutMessages.distributeColumns),
261
+ type: 'button'
262
+ } : undefined;
203
263
  return [{
204
264
  type: 'dropdown',
205
265
  title: intl.formatMessage(_messages.layoutMessages.columnOption, {
206
266
  count: numberOfColumns
207
267
  }),
208
268
  //`${numberOfColumns}-columns`,
209
- options: [singleColumnOption, columnOptions].flat(),
269
+ options: dropdownOptions,
210
270
  showSelected: true,
211
271
  testId: 'column-options-button'
212
- }].concat((0, _toConsumableArray2.default)(distributionOptions.length > 0 ? [separator] : []), (0, _toConsumableArray2.default)(addSidebarLayouts ? distributionOptions.map(function (i) {
272
+ }].concat((0, _toConsumableArray2.default)(distributionOptions.length > 0 || distributeColumnsButton ? [separator] : []), (0, _toConsumableArray2.default)(addSidebarLayouts ? distributionOptions.map(function (i) {
213
273
  return buildLayoutButton(intl, i, currentLayout, editorAnalyticsAPI);
214
- }) : []));
274
+ }) : []), (0, _toConsumableArray2.default)(distributeColumnsButton ? [distributeColumnsButton] : []));
215
275
  };
216
276
  var fullHeightSeparator = {
217
277
  type: 'separator',
@@ -300,7 +360,6 @@ var buildToolbar = exports.buildToolbar = function buildToolbar(state, intl, pos
300
360
  addSidebarLayouts: addSidebarLayouts,
301
361
  intl: intl,
302
362
  editorAnalyticsAPI: editorAnalyticsAPI,
303
- state: state,
304
363
  nodeType: nodeType,
305
364
  node: node,
306
365
  separator: separator,
@@ -11,7 +11,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
11
11
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
12
12
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
13
13
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
14
- import { createDefaultLayoutSection, createMultiColumnLayoutSection, deleteLayoutColumn, distributeLayoutColumns, insertLayoutColumn, insertLayoutColumnsWithAnalytics, setLayoutColumnValign, toggleLayoutColumnMenu } from './pm-plugins/actions';
14
+ import { createDefaultLayoutSection, createDistributeLayoutColumnsCommand, createMultiColumnLayoutSection, deleteLayoutColumn, insertLayoutColumn, insertLayoutColumnsWithAnalytics, setLayoutColumnValign, toggleLayoutColumnMenu } from './pm-plugins/actions';
15
15
  import { default as createLayoutPlugin } from './pm-plugins/main';
16
16
  import { pluginKey } from './pm-plugins/plugin-key';
17
17
  import { default as createLayoutResizingPlugin } from './pm-plugins/resizing';
@@ -52,7 +52,7 @@ export const layoutPlugin = ({
52
52
  config: options = {},
53
53
  api
54
54
  }) => {
55
- var _api$analytics;
55
+ var _api$analytics, _api$analytics5;
56
56
  const allowAdvancedSingleColumnLayout = editorExperiment('advanced_layouts', true) && editorExperiment('single_column_layouts', true, {
57
57
  exposure: true
58
58
  });
@@ -353,10 +353,7 @@ export const layoutPlugin = ({
353
353
  var _api$analytics4;
354
354
  return deleteLayoutColumn(api === null || api === void 0 ? void 0 : (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 ? void 0 : _api$analytics4.actions)(props);
355
355
  },
356
- distributeLayoutColumns: props => {
357
- var _api$analytics5;
358
- return distributeLayoutColumns(api === null || api === void 0 ? void 0 : (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 ? void 0 : _api$analytics5.actions)(props);
359
- },
356
+ distributeLayoutColumns: createDistributeLayoutColumnsCommand(api === null || api === void 0 ? void 0 : (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 ? void 0 : _api$analytics5.actions),
360
357
  insertLayoutColumn: side => {
361
358
  var _api$analytics6;
362
359
  return insertLayoutColumn(side, api === null || api === void 0 ? void 0 : (_api$analytics6 = api.analytics) === null || _api$analytics6 === void 0 ? void 0 : _api$analytics6.actions);
@@ -10,7 +10,7 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
10
10
  import { EVEN_DISTRIBUTED_COL_WIDTHS, MAX_LAYOUT_COLUMNS, MAX_STANDARD_LAYOUT_COLUMNS, MIN_LAYOUT_COLUMN_WIDTH_PERCENT } from './consts';
11
11
  import { pluginKey } from './plugin-key';
12
12
  import { calculateDistribution, isDistributedUniformly, redistributeAfterDeletion, redistributeProportionally } from './utils/layout-column-distribution';
13
- import { getSelectedLayoutColumns } from './utils/layout-column-selection';
13
+ import { getAllLayoutColumnsFromSelection, getSelectedLayoutColumnsFromSelection } from './utils/layout-column-selection';
14
14
  export const ONE_COL_LAYOUTS = ['single'];
15
15
  export const TWO_COL_LAYOUTS = ['two_equal', 'two_left_sidebar', 'two_right_sidebar'];
16
16
  export const THREE_COL_LAYOUTS = ['three_equal', 'three_with_sidebars'];
@@ -540,20 +540,19 @@ const insertLayoutColumnAt = (side, editorAnalyticsAPI) => ({
540
540
  if (!expValEqualsNoExposure('platform_editor_layout_column_menu', 'isEnabled', true)) {
541
541
  return null;
542
542
  }
543
- const selectedLayoutColumns = getSelectedLayoutColumns(tr.selection);
544
- if (!selectedLayoutColumns) {
543
+ const selectedLayoutColumnsResult = getSelectedLayoutColumnsFromSelection(tr.selection);
544
+ if (!selectedLayoutColumnsResult || selectedLayoutColumnsResult.selectedLayoutColumns.length === 0) {
545
545
  return null;
546
546
  }
547
547
  const {
548
548
  layoutSectionNode,
549
549
  layoutSectionPos,
550
- selectedColumnIndices,
551
- selectedColumns
552
- } = selectedLayoutColumns;
553
- const startIndex = selectedColumnIndices[0];
554
- const endIndex = selectedColumnIndices[selectedColumnIndices.length - 1];
550
+ startIndex,
551
+ endIndex,
552
+ selectedLayoutColumns
553
+ } = selectedLayoutColumnsResult;
555
554
  const selectedColumnIndex = side === 'left' ? startIndex : endIndex;
556
- const selectedColumnCount = selectedColumns.length;
555
+ const selectedColumnCount = selectedLayoutColumns.length;
557
556
  if (layoutSectionNode.childCount >= getEffectiveMaxLayoutColumns()) {
558
557
  return null;
559
558
  }
@@ -608,23 +607,21 @@ export const setLayoutColumnValign = (valign, editorAnalyticsAPI) => ({
608
607
  if (!expValEqualsNoExposure('platform_editor_layout_column_menu', 'isEnabled', true)) {
609
608
  return null;
610
609
  }
611
- const selectedLayoutColumns = getSelectedLayoutColumns(tr.selection);
612
- if (!selectedLayoutColumns) {
610
+ const selectedLayoutColumnsResult = getSelectedLayoutColumnsFromSelection(tr.selection);
611
+ if (!selectedLayoutColumnsResult) {
613
612
  return null;
614
613
  }
615
614
  const {
616
- selectedColumnIndices,
617
- selectedColumns
618
- } = selectedLayoutColumns;
619
- const columnsToUpdate = selectedColumns.filter(({
615
+ startIndex,
616
+ endIndex,
617
+ selectedLayoutColumns
618
+ } = selectedLayoutColumnsResult;
619
+ const columnsToUpdate = selectedLayoutColumns.filter(({
620
620
  node
621
621
  }) => node.attrs.valign !== valign);
622
622
  if (columnsToUpdate.length === 0) {
623
623
  return null;
624
624
  }
625
- const startIndex = selectedColumnIndices[0];
626
- const endIndex = selectedColumnIndices[selectedColumnIndices.length - 1];
627
- const selectedColumnCount = selectedColumns.length;
628
625
  const updatedColumnCount = columnsToUpdate.length;
629
626
  columnsToUpdate.forEach(({
630
627
  node,
@@ -642,7 +639,7 @@ export const setLayoutColumnValign = (valign, editorAnalyticsAPI) => ({
642
639
  attributes: {
643
640
  endIndex,
644
641
  inputMethod: INPUT_METHOD.LAYOUT_COLUMN_MENU,
645
- selectedCount: selectedColumnCount,
642
+ selectedCount: selectedLayoutColumns.length,
646
643
  startIndex,
647
644
  updatedCount: updatedColumnCount,
648
645
  valign
@@ -652,26 +649,28 @@ export const setLayoutColumnValign = (valign, editorAnalyticsAPI) => ({
652
649
  tr.setMeta('scrollIntoView', false);
653
650
  return tr;
654
651
  };
655
- export const distributeLayoutColumns = (editorAnalyticsAPI, inputMethod = INPUT_METHOD.LAYOUT_COLUMN_MENU) => ({
652
+ export const distributeLayoutColumns = ({
653
+ editorAnalyticsAPI,
654
+ inputMethod = INPUT_METHOD.LAYOUT_COLUMN_MENU,
655
+ target = 'selectedColumns'
656
+ } = {}) => ({
656
657
  tr
657
658
  }) => {
658
659
  if (!expValEqualsNoExposure('platform_editor_layout_column_menu', 'isEnabled', true)) {
659
660
  return null;
660
661
  }
661
- const selectedLayoutColumns = getSelectedLayoutColumns(tr.selection);
662
- if (!selectedLayoutColumns || selectedLayoutColumns.selectedColumns.length < 2) {
662
+ const selectedLayoutColumnsResult = target === 'allColumns' ? getAllLayoutColumnsFromSelection(tr.selection) : getSelectedLayoutColumnsFromSelection(tr.selection);
663
+ if (!selectedLayoutColumnsResult || selectedLayoutColumnsResult.selectedLayoutColumns.length < 2) {
663
664
  return null;
664
665
  }
665
666
  const {
666
667
  layoutSectionNode,
667
- selectedColumnIndices,
668
- selectedColumns
669
- } = selectedLayoutColumns;
670
- const endIndex = selectedColumnIndices[selectedColumnIndices.length - 1];
671
- const selectedColumnCount = selectedColumns.length;
672
- const totalColumnCount = layoutSectionNode.childCount;
668
+ startIndex,
669
+ endIndex,
670
+ selectedLayoutColumns
671
+ } = selectedLayoutColumnsResult;
673
672
  const existingWidths = mapChildren(layoutSectionNode, column => column.attrs.width);
674
- const selectedWidths = selectedColumns.map(({
673
+ const selectedWidths = selectedLayoutColumns.map(({
675
674
  node
676
675
  }) => node.attrs.width);
677
676
  const distribution = calculateDistribution(selectedWidths);
@@ -689,15 +688,14 @@ export const distributeLayoutColumns = (editorAnalyticsAPI, inputMethod = INPUT_
689
688
  // Build new widths array: selected columns get equal share, unselected unchanged.
690
689
  // Assign rounded (2dp) equal widths to all selected cols except the last, which absorbs
691
690
  // the rounding remainder so the sum of selected widths equals selectedTotal exactly.
692
- const selectedIndexSet = new Set(selectedColumnIndices);
693
691
  let assignedToSelected = 0;
694
692
  let selectedAssignedCount = 0;
695
693
  const newWidths = existingWidths.map((w, idx) => {
696
- if (!selectedIndexSet.has(idx)) {
694
+ if (idx < startIndex || idx > endIndex) {
697
695
  return w;
698
696
  }
699
697
  selectedAssignedCount += 1;
700
- if (selectedAssignedCount < selectedColumnCount) {
698
+ if (selectedAssignedCount < selectedLayoutColumns.length) {
701
699
  assignedToSelected += equalWidth;
702
700
  return equalWidth;
703
701
  }
@@ -706,11 +704,11 @@ export const distributeLayoutColumns = (editorAnalyticsAPI, inputMethod = INPUT_
706
704
  });
707
705
 
708
706
  // Apply widths via setNodeMarkup per selected column — keeps nodes in place (preserves identity, marks, decorations)
709
- selectedColumns.forEach(({
707
+ selectedLayoutColumns.forEach(({
710
708
  node,
711
709
  pos
712
710
  }, i) => {
713
- const colIdx = selectedColumnIndices[i];
711
+ const colIdx = startIndex + i;
714
712
  tr.setNodeMarkup(pos, node.type, {
715
713
  ...node.attrs,
716
714
  width: newWidths[colIdx]
@@ -721,17 +719,21 @@ export const distributeLayoutColumns = (editorAnalyticsAPI, inputMethod = INPUT_
721
719
  actionSubject: ACTION_SUBJECT.DOCUMENT,
722
720
  actionSubjectId: ACTION_SUBJECT_ID.LAYOUT_COLUMN,
723
721
  attributes: {
724
- columnCount: totalColumnCount,
722
+ columnCount: layoutSectionNode.childCount,
725
723
  endIndex,
726
724
  inputMethod,
727
- selectedCount: selectedColumnCount,
728
- startIndex: selectedColumnIndices[0]
725
+ selectedCount: selectedLayoutColumns.length,
726
+ startIndex
729
727
  },
730
728
  eventType: EVENT_TYPE.TRACK
731
729
  })(tr);
732
730
  tr.setMeta('scrollIntoView', false);
733
731
  return tr;
734
732
  };
733
+ export const createDistributeLayoutColumnsCommand = editorAnalyticsAPI => (options = {}) => distributeLayoutColumns({
734
+ ...options,
735
+ editorAnalyticsAPI
736
+ });
735
737
  export const toggleLayoutColumnMenu = ({
736
738
  anchorPos,
737
739
  isOpen
@@ -751,20 +753,17 @@ export const deleteLayoutColumn = editorAnalyticsAPI => ({
751
753
  if (!expValEqualsNoExposure('platform_editor_layout_column_menu', 'isEnabled', true)) {
752
754
  return null;
753
755
  }
754
- const selectedLayoutColumns = getSelectedLayoutColumns(tr.selection);
755
- if (!selectedLayoutColumns) {
756
+ const selectedLayoutColumnsResult = getSelectedLayoutColumnsFromSelection(tr.selection);
757
+ if (!selectedLayoutColumnsResult || selectedLayoutColumnsResult.selectedLayoutColumns.length === 0) {
756
758
  return null;
757
759
  }
758
760
  const {
759
761
  layoutSectionNode,
760
762
  layoutSectionPos,
761
- selectedColumnIndices,
762
- selectedColumns
763
- } = selectedLayoutColumns;
764
- const startIndex = selectedColumnIndices[0];
765
- const endIndex = selectedColumnIndices[selectedColumnIndices.length - 1];
766
- const selectedColumnCount = selectedColumns.length;
767
- const selectedColumnIndexSet = new Set(selectedColumnIndices);
763
+ selectedLayoutColumns,
764
+ startIndex,
765
+ endIndex
766
+ } = selectedLayoutColumnsResult;
768
767
  const emitDeleteColumnAnalytics = columnCount => {
769
768
  editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
770
769
  action: ACTION.DELETED,
@@ -774,7 +773,7 @@ export const deleteLayoutColumn = editorAnalyticsAPI => ({
774
773
  columnCount,
775
774
  endIndex,
776
775
  inputMethod: INPUT_METHOD.LAYOUT_COLUMN_MENU,
777
- selectedCount: selectedColumnCount,
776
+ selectedCount: selectedLayoutColumns.length,
778
777
  startIndex
779
778
  },
780
779
  eventType: EVENT_TYPE.TRACK
@@ -782,7 +781,7 @@ export const deleteLayoutColumn = editorAnalyticsAPI => ({
782
781
  };
783
782
 
784
783
  // If all columns are selected, remove the entire layoutSection
785
- if (selectedColumnCount === layoutSectionNode.childCount) {
784
+ if (selectedLayoutColumns.length === layoutSectionNode.childCount) {
786
785
  tr.delete(layoutSectionPos, layoutSectionPos + layoutSectionNode.nodeSize);
787
786
  emitDeleteColumnAnalytics(0);
788
787
  tr.setMeta('scrollIntoView', false);
@@ -792,17 +791,17 @@ export const deleteLayoutColumn = editorAnalyticsAPI => ({
792
791
  // Build new column list without the selected columns
793
792
  const remainingColumns = [];
794
793
  layoutSectionNode.forEach((column, _offset, index) => {
795
- if (!selectedColumnIndexSet.has(index)) {
794
+ if (index < startIndex || index > endIndex) {
796
795
  remainingColumns.push(column);
797
796
  }
798
797
  });
799
798
 
800
799
  // Redistribute widths proportionally among remaining columns using shared utility
801
800
  const existingWidths = mapChildren(layoutSectionNode, column => column.attrs.width);
802
- const redistributed = selectedColumnIndices.slice()
801
+ const redistributed = selectedLayoutColumns.map((_, i) => startIndex + i)
803
802
  // Delete highest indices first so lower original indices still point at the same columns
804
803
  // as each redistribution step shrinks the widths array.
805
- .sort((a, b) => b - a).reduce((widths, selectedIndex) => redistributeAfterDeletion(widths, selectedIndex, MIN_LAYOUT_COLUMN_WIDTH_PERCENT), existingWidths);
804
+ .reverse().reduce((widths, selectedIndex) => redistributeAfterDeletion(widths, selectedIndex, MIN_LAYOUT_COLUMN_WIDTH_PERCENT), existingWidths);
806
805
  const updatedLayoutSectionNode = layoutSectionNode.copy(Fragment.fromArray(remainingColumns));
807
806
  tr.replaceWith(layoutSectionPos + 1, layoutSectionPos + layoutSectionNode.nodeSize - 1, columnWidth(updatedLayoutSectionNode, tr.doc.type.schema, redistributed));
808
807
  emitDeleteColumnAnalytics(redistributed.length);
@@ -1,121 +1,81 @@
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;
1
+ import { findChildrenByType, findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
2
+ const findLayoutSectionFromSelection = selection => {
3
+ return findParentNodeOfType(selection.$from.doc.type.schema.nodes.layoutSection)(selection);
12
4
  };
13
- const getLayoutSectionDepth = selection => {
14
- 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;
5
+ const findLayoutColumnsFromLayoutSection = (layoutSectionNode, layoutSectionPos = 0) => {
6
+ return findChildrenByType(layoutSectionNode, layoutSectionNode.type.schema.nodes.layoutColumn).map(({
7
+ node,
8
+ pos
9
+ }) => ({
10
+ node,
11
+ pos: pos + layoutSectionPos + 1
12
+ }));
25
13
  };
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);
39
- 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
- }]
48
- };
49
- }
50
- if (selection.empty) {
51
- return undefined;
52
- }
53
- if (!editorExperiment('platform_editor_block_menu', true)) {
14
+ export const getSelectedLayoutColumnsFromSelection = selection => {
15
+ const layoutSection = findLayoutSectionFromSelection(selection);
16
+ if (!layoutSection) {
54
17
  return undefined;
55
18
  }
56
- const layoutSectionDepth = getLayoutSectionDepth(selection);
57
- if (layoutSectionDepth === undefined) {
19
+ const {
20
+ node: layoutSectionNode,
21
+ pos: layoutSectionPos
22
+ } = layoutSection;
23
+ const allLayoutColumns = findLayoutColumnsFromLayoutSection(layoutSectionNode, layoutSectionPos);
24
+ if (!allLayoutColumns.length) {
58
25
  return undefined;
59
26
  }
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;
27
+ let startIndex = -1;
28
+ let endIndex = -1;
29
+ const selectedLayoutColumns = allLayoutColumns.filter(({
30
+ node,
31
+ pos
32
+ }, index) => {
33
+ const isSelected = selection.from <= pos && selection.to >= pos + node.nodeSize;
34
+ if (isSelected) {
35
+ if (startIndex === -1) {
36
+ startIndex = index;
37
+ }
38
+ endIndex = index;
78
39
  }
79
- selectedColumns.push({
80
- index,
81
- node: column,
82
- pos: columnStart
83
- });
40
+ return isSelected;
84
41
  });
85
-
86
- // TextSelection inside a single column is normal text editing, not a selected column set.
87
- if (invalidSelection || selectedColumns.length < 2) {
42
+ return {
43
+ layoutSectionNode,
44
+ layoutSectionPos,
45
+ selectedLayoutColumns,
46
+ startIndex,
47
+ endIndex
48
+ };
49
+ };
50
+ export const getAllLayoutColumnsFromSelection = selection => {
51
+ const layoutSection = findLayoutSectionFromSelection(selection);
52
+ if (!layoutSection) {
88
53
  return undefined;
89
54
  }
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) {
55
+ const layoutColumns = findLayoutColumnsFromLayoutSection(layoutSection.node, layoutSection.pos);
56
+ if (!(layoutColumns !== null && layoutColumns !== void 0 && layoutColumns.length)) {
95
57
  return undefined;
96
58
  }
97
59
  return {
98
- layoutSectionNode,
99
- layoutSectionPos,
100
- selectedColumnIndices: selectedColumns.map(({
101
- index
102
- }) => index),
103
- selectedColumns
60
+ layoutSectionNode: layoutSection.node,
61
+ layoutSectionPos: layoutSection.pos,
62
+ selectedLayoutColumns: layoutColumns,
63
+ startIndex: 0,
64
+ endIndex: layoutColumns.length - 1
104
65
  };
105
66
  };
106
- export const getLayoutSectionColumnCount = layoutSection => (layoutSection === null || layoutSection === void 0 ? void 0 : layoutSection.type.name) === 'layoutSection' ? layoutSection.childCount : 0;
107
67
  export const getLayoutColumnValign = layoutColumn => {
108
68
  var _ref;
109
69
  return layoutColumn ? (_ref = layoutColumn.attrs.valign) !== null && _ref !== void 0 ? _ref : 'top' : undefined;
110
70
  };
111
71
  export const getLayoutColumnMenuAnchorPos = (selection, anchorPosFromHandle) => {
112
72
  var _clickedSelectedColum, _selectedLayoutColumn;
113
- const selectedLayoutColumns = getSelectedLayoutColumns(selection);
73
+ const selectedLayoutColumns = getSelectedLayoutColumnsFromSelection(selection);
114
74
  if (!selectedLayoutColumns) {
115
75
  return undefined;
116
76
  }
117
- const clickedSelectedColumn = selectedLayoutColumns.selectedColumns.find(({
77
+ const clickedSelectedColumn = selectedLayoutColumns.selectedLayoutColumns.find(({
118
78
  pos
119
79
  }) => 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;
80
+ 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
81
  };
@@ -30,7 +30,7 @@ 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
35
  onClick: onClick
36
36
  }, formatMessage(layoutMessages.deleteColumn, {
@@ -1,5 +1,6 @@
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
5
  import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
6
  import { isDistributedUniformly } from '../../pm-plugins/utils/layout-column-distribution';
@@ -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,13 +34,13 @@ 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, {