@atlaskit/editor-plugin-layout 10.3.4 → 10.4.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 (67) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/layoutPlugin.js +8 -0
  3. package/dist/cjs/pm-plugins/actions.js +158 -8
  4. package/dist/cjs/pm-plugins/column-resize-divider.js +7 -9
  5. package/dist/cjs/pm-plugins/consts.js +4 -1
  6. package/dist/cjs/pm-plugins/utils/redistribute-proportionally.js +141 -0
  7. package/dist/cjs/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +42 -0
  8. package/dist/cjs/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +69 -0
  9. package/dist/cjs/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +7 -9
  10. package/dist/cjs/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +11 -10
  11. package/dist/cjs/ui/LayoutColumnMenu/components.js +31 -0
  12. package/dist/cjs/ui/LayoutColumnMenu/index.js +39 -11
  13. package/dist/cjs/ui/LayoutColumnMenu/keys.js +14 -2
  14. package/dist/cjs/ui/LayoutColumnMenu/layoutColumnSelection.js +21 -0
  15. package/dist/cjs/ui/LayoutColumnMenu/useCurrentLayoutColumn.js +20 -0
  16. package/dist/es2019/layoutPlugin.js +9 -1
  17. package/dist/es2019/pm-plugins/actions.js +152 -1
  18. package/dist/es2019/pm-plugins/column-resize-divider.js +8 -9
  19. package/dist/es2019/pm-plugins/consts.js +3 -0
  20. package/dist/es2019/pm-plugins/utils/redistribute-proportionally.js +113 -0
  21. package/dist/es2019/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +37 -0
  22. package/dist/es2019/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +64 -0
  23. package/dist/es2019/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +6 -11
  24. package/dist/es2019/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +7 -10
  25. package/dist/es2019/ui/LayoutColumnMenu/components.js +32 -1
  26. package/dist/es2019/ui/LayoutColumnMenu/index.js +34 -13
  27. package/dist/es2019/ui/LayoutColumnMenu/keys.js +17 -2
  28. package/dist/es2019/ui/LayoutColumnMenu/layoutColumnSelection.js +9 -0
  29. package/dist/es2019/ui/LayoutColumnMenu/useCurrentLayoutColumn.js +10 -0
  30. package/dist/esm/layoutPlugin.js +9 -1
  31. package/dist/esm/pm-plugins/actions.js +156 -7
  32. package/dist/esm/pm-plugins/column-resize-divider.js +8 -9
  33. package/dist/esm/pm-plugins/consts.js +3 -0
  34. package/dist/esm/pm-plugins/utils/redistribute-proportionally.js +134 -0
  35. package/dist/esm/ui/LayoutColumnMenu/DeleteColumnDropdownItem.js +35 -0
  36. package/dist/esm/ui/LayoutColumnMenu/InsertColumnDropdownItem.js +61 -0
  37. package/dist/esm/ui/LayoutColumnMenu/VerticalAlignDropdownItem.js +8 -10
  38. package/dist/esm/ui/LayoutColumnMenu/VerticalAlignNestedMenu.js +9 -9
  39. package/dist/esm/ui/LayoutColumnMenu/components.js +32 -1
  40. package/dist/esm/ui/LayoutColumnMenu/index.js +40 -13
  41. package/dist/esm/ui/LayoutColumnMenu/keys.js +13 -1
  42. package/dist/esm/ui/LayoutColumnMenu/layoutColumnSelection.js +15 -0
  43. package/dist/esm/ui/LayoutColumnMenu/useCurrentLayoutColumn.js +14 -0
  44. package/dist/types/layoutPluginType.d.ts +4 -2
  45. package/dist/types/pm-plugins/actions.d.ts +7 -0
  46. package/dist/types/pm-plugins/consts.d.ts +3 -0
  47. package/dist/types/pm-plugins/utils/redistribute-proportionally.d.ts +2 -0
  48. package/dist/types/ui/LayoutColumnMenu/DeleteColumnDropdownItem.d.ts +8 -0
  49. package/dist/types/ui/LayoutColumnMenu/InsertColumnDropdownItem.d.ts +10 -0
  50. package/dist/types/ui/LayoutColumnMenu/keys.d.ts +3 -0
  51. package/dist/types/ui/LayoutColumnMenu/layoutColumnSelection.d.ts +7 -0
  52. package/dist/types/ui/LayoutColumnMenu/useCurrentLayoutColumn.d.ts +5 -0
  53. package/dist/types-ts4.5/layoutPluginType.d.ts +4 -2
  54. package/dist/types-ts4.5/pm-plugins/actions.d.ts +7 -0
  55. package/dist/types-ts4.5/pm-plugins/consts.d.ts +3 -0
  56. package/dist/types-ts4.5/pm-plugins/utils/redistribute-proportionally.d.ts +2 -0
  57. package/dist/types-ts4.5/ui/LayoutColumnMenu/DeleteColumnDropdownItem.d.ts +8 -0
  58. package/dist/types-ts4.5/ui/LayoutColumnMenu/InsertColumnDropdownItem.d.ts +10 -0
  59. package/dist/types-ts4.5/ui/LayoutColumnMenu/keys.d.ts +3 -0
  60. package/dist/types-ts4.5/ui/LayoutColumnMenu/layoutColumnSelection.d.ts +7 -0
  61. package/dist/types-ts4.5/ui/LayoutColumnMenu/useCurrentLayoutColumn.d.ts +5 -0
  62. package/package.json +4 -4
  63. package/dist/cjs/ui/LayoutColumnMenu/useCurrentLayoutColumnValign.js +0 -22
  64. package/dist/es2019/ui/LayoutColumnMenu/useCurrentLayoutColumnValign.js +0 -14
  65. package/dist/esm/ui/LayoutColumnMenu/useCurrentLayoutColumnValign.js +0 -16
  66. package/dist/types/ui/LayoutColumnMenu/useCurrentLayoutColumnValign.d.ts +0 -11
  67. package/dist/types-ts4.5/ui/LayoutColumnMenu/useCurrentLayoutColumnValign.d.ts +0 -11
@@ -10,7 +10,9 @@ var _react = _interopRequireDefault(require("react"));
10
10
  var _messages = require("@atlaskit/editor-common/messages");
11
11
  var _editorToolbar = require("@atlaskit/editor-toolbar");
12
12
  var _toolbarMenuContainer = require("@atlaskit/editor-toolbar/toolbar-menu-container");
13
+ var _DeleteColumnDropdownItem = require("./DeleteColumnDropdownItem");
13
14
  var _DistributeColumnsDropdownItem = require("./DistributeColumnsDropdownItem");
15
+ var _InsertColumnDropdownItem = require("./InsertColumnDropdownItem");
14
16
  var _keys = require("./keys");
15
17
  var _VerticalAlignDropdownItem = require("./VerticalAlignDropdownItem");
16
18
  var _VerticalAlignNestedMenu = require("./VerticalAlignNestedMenu");
@@ -30,11 +32,40 @@ var getLayoutColumnMenuComponents = exports.getLayoutColumnMenuComponents = func
30
32
  parents: [_objectSpread(_objectSpread({}, _keys.LAYOUT_COLUMN_MENU), {}, {
31
33
  rank: _keys.LAYOUT_COLUMN_MENU_RANK[_keys.LAYOUT_COLUMN_MENU_SECTION.key]
32
34
  })]
35
+ }), _objectSpread(_objectSpread({}, _keys.INSERT_COLUMN_LEFT_MENU_ITEM), {}, {
36
+ component: function component() {
37
+ return /*#__PURE__*/_react.default.createElement(_InsertColumnDropdownItem.InsertColumnDropdownItem, {
38
+ api: api,
39
+ side: "left"
40
+ });
41
+ },
42
+ parents: [_objectSpread(_objectSpread({}, _keys.LAYOUT_COLUMN_MENU_SECTION), {}, {
43
+ rank: _keys.LAYOUT_COLUMN_MENU_SECTION_RANK[_keys.INSERT_COLUMN_LEFT_MENU_ITEM.key]
44
+ })]
45
+ }), _objectSpread(_objectSpread({}, _keys.INSERT_COLUMN_RIGHT_MENU_ITEM), {}, {
46
+ component: function component() {
47
+ return /*#__PURE__*/_react.default.createElement(_InsertColumnDropdownItem.InsertColumnDropdownItem, {
48
+ api: api,
49
+ side: "right"
50
+ });
51
+ },
52
+ parents: [_objectSpread(_objectSpread({}, _keys.LAYOUT_COLUMN_MENU_SECTION), {}, {
53
+ rank: _keys.LAYOUT_COLUMN_MENU_SECTION_RANK[_keys.INSERT_COLUMN_RIGHT_MENU_ITEM.key]
54
+ })]
33
55
  }), _objectSpread(_objectSpread({}, _keys.DISTRIBUTE_COLUMNS_MENU_ITEM), {}, {
34
56
  component: (0, _DistributeColumnsDropdownItem.createDistributeColumnsDropdownItem)(api),
35
57
  parents: [_objectSpread(_objectSpread({}, _keys.LAYOUT_COLUMN_MENU_SECTION), {}, {
36
58
  rank: _keys.LAYOUT_COLUMN_MENU_SECTION_RANK[_keys.DISTRIBUTE_COLUMNS_MENU_ITEM.key]
37
59
  })]
60
+ }), _objectSpread(_objectSpread({}, _keys.DELETE_COLUMN_MENU_ITEM), {}, {
61
+ component: function component() {
62
+ return /*#__PURE__*/_react.default.createElement(_DeleteColumnDropdownItem.DeleteColumnDropdownItem, {
63
+ api: api
64
+ });
65
+ },
66
+ parents: [_objectSpread(_objectSpread({}, _keys.LAYOUT_COLUMN_MENU_SECTION), {}, {
67
+ rank: _keys.LAYOUT_COLUMN_MENU_SECTION_RANK[_keys.DELETE_COLUMN_MENU_ITEM.key]
68
+ })]
38
69
  }), _objectSpread(_objectSpread({}, _keys.VERTICAL_ALIGN_MENU), {}, {
39
70
  component: function component(_ref3) {
40
71
  var children = _ref3.children;
@@ -1,33 +1,43 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  var _typeof = require("@babel/runtime/helpers/typeof");
4
5
  Object.defineProperty(exports, "__esModule", {
5
6
  value: true
6
7
  });
7
8
  exports.LayoutColumnMenu = void 0;
9
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
8
10
  var _react = _interopRequireWildcard(require("react"));
9
11
  var _hooks = require("@atlaskit/editor-common/hooks");
12
+ var _styles = require("@atlaskit/editor-common/styles");
10
13
  var _toolbar = require("@atlaskit/editor-common/toolbar");
11
14
  var _ui = require("@atlaskit/editor-common/ui");
12
15
  var _uiReact = require("@atlaskit/editor-common/ui-react");
13
- var _utils = require("@atlaskit/editor-prosemirror/utils");
14
16
  var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
15
17
  var _editorToolbar = require("@atlaskit/editor-toolbar");
16
18
  var _editorUiControlModel = require("@atlaskit/editor-ui-control-model");
17
19
  var _components = require("./components");
18
20
  var _keys = require("./keys");
21
+ var _layoutColumnSelection = require("./layoutColumnSelection");
19
22
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
20
23
  var PopupWithListeners = (0, _uiReact.withReactEditorViewOuterListeners)(_ui.Popup);
21
- var LAYOUT_COLUMN_MENU_POPUP_OFFSET = [0, 10];
22
- var getLayoutColumnMenuTarget = function getLayoutColumnMenuTarget(editorView, selectionAnchorPos) {
23
- if (selectionAnchorPos === undefined) {
24
+ var FALLBACK_MENU_HEIGHT = 300;
25
+ var LAYOUT_COLUMN_MENU_POPUP_OFFSET = [0, 4];
26
+
27
+ /**
28
+ * Returns the drag handle button for the selected layout column.
29
+ */
30
+ var getLayoutColumnMenuTarget = function getLayoutColumnMenuTarget(editorView, selection) {
31
+ var _columnDomRef$parentE;
32
+ if (!(0, _layoutColumnSelection.getLayoutColumnAtSelection)(selection) || (selection === null || selection === void 0 ? void 0 : selection.from) === undefined) {
24
33
  return null;
25
34
  }
26
- var selectionNode = editorView.state.doc.nodeAt(selectionAnchorPos);
27
- if ((selectionNode === null || selectionNode === void 0 ? void 0 : selectionNode.type.name) !== 'layoutColumn') {
35
+ var columnDomRef = editorView.nodeDOM(selection.from);
36
+ if (!(columnDomRef instanceof HTMLElement)) {
28
37
  return null;
29
38
  }
30
- return (0, _utils.findDomRefAtPos)(selectionAnchorPos, editorView.domAtPos.bind(editorView));
39
+ var dragHandleContainer = (_columnDomRef$parentE = columnDomRef.parentElement) === null || _columnDomRef$parentE === void 0 ? void 0 : _columnDomRef$parentE.querySelector(':scope > [data-blocks-drag-handle-container]');
40
+ return dragHandleContainer === null || dragHandleContainer === void 0 ? void 0 : dragHandleContainer.querySelector(_styles.DRAG_HANDLE_SELECTOR);
31
41
  };
32
42
  var LayoutColumnMenu = exports.LayoutColumnMenu = /*#__PURE__*/_react.default.memo(function LayoutColumnMenu(_ref) {
33
43
  var _api$uiControlRegistr, _api$uiControlRegistr2;
@@ -47,6 +57,18 @@ var LayoutColumnMenu = exports.LayoutColumnMenu = /*#__PURE__*/_react.default.me
47
57
  selection = _useSharedPluginState.selection;
48
58
  var setOutsideClickTargetRef = (0, _react.useContext)(_uiReact.OutsideClickTargetRefContext);
49
59
  var menuRef = (0, _react.useRef)(null);
60
+ var popupRef = (0, _react.useRef)(undefined);
61
+ var _React$useState = _react.default.useState(FALLBACK_MENU_HEIGHT),
62
+ _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
63
+ menuHeight = _React$useState2[0],
64
+ setMenuHeight = _React$useState2[1];
65
+ (0, _react.useLayoutEffect)(function () {
66
+ var _popupRef$current;
67
+ if (!isLayoutColumnMenuOpen) {
68
+ return;
69
+ }
70
+ setMenuHeight(((_popupRef$current = popupRef.current) === null || _popupRef$current === void 0 ? void 0 : _popupRef$current.clientHeight) || FALLBACK_MENU_HEIGHT);
71
+ }, [isLayoutColumnMenuOpen]);
50
72
  var closeLayoutColumnMenu = (0, _react.useCallback)(function () {
51
73
  var _api$core, _api$layout;
52
74
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$layout = api.layout) === null || _api$layout === void 0 ? void 0 : _api$layout.commands.toggleLayoutColumnMenu({
@@ -71,9 +93,14 @@ var LayoutColumnMenu = exports.LayoutColumnMenu = /*#__PURE__*/_react.default.me
71
93
  var handleMenuRef = (0, _react.useCallback)(function (el) {
72
94
  setOutsideClickTargetRef === null || setOutsideClickTargetRef === void 0 || setOutsideClickTargetRef(el);
73
95
  menuRef.current = el;
96
+ if (el) {
97
+ popupRef.current = el;
98
+ }
74
99
  }, [setOutsideClickTargetRef]);
75
100
  var components = (_api$uiControlRegistr = api === null || api === void 0 || (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(_keys.LAYOUT_COLUMN_MENU.key)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [];
76
- var target = isLayoutColumnMenuOpen ? getLayoutColumnMenuTarget(editorView, selection === null || selection === void 0 ? void 0 : selection.from) : null;
101
+ var target = (0, _react.useMemo)(function () {
102
+ return isLayoutColumnMenuOpen ? getLayoutColumnMenuTarget(editorView, selection) : null;
103
+ }, [editorView, isLayoutColumnMenuOpen, selection]);
77
104
  var hasValidTarget = target instanceof HTMLElement;
78
105
  (0, _react.useEffect)(function () {
79
106
  if (isLayoutColumnMenuOpen && (!hasValidTarget || components.length === 0)) {
@@ -88,10 +115,11 @@ var LayoutColumnMenu = exports.LayoutColumnMenu = /*#__PURE__*/_react.default.me
88
115
  mountTo: mountTo,
89
116
  boundariesElement: boundariesElement,
90
117
  scrollableElement: scrollableElement,
91
- zIndex: _editorSharedStyles.akEditorFloatingPanelZIndex,
118
+ zIndex: _editorSharedStyles.akEditorFloatingOverlapPanelZIndex,
92
119
  alignX: "center",
93
- alignY: "top",
94
- forcePlacement: true,
120
+ fitHeight: menuHeight,
121
+ preventOverflow: true,
122
+ stick: true,
95
123
  offset: LAYOUT_COLUMN_MENU_POPUP_OFFSET,
96
124
  handleClickOutside: handleClickOutside,
97
125
  handleEscapeKeydown: closeLayoutColumnMenu
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.VERTICAL_ALIGN_TOP_MENU_ITEM = exports.VERTICAL_ALIGN_MIDDLE_MENU_ITEM = exports.VERTICAL_ALIGN_MENU_SECTION_RANK = exports.VERTICAL_ALIGN_MENU_RANK = exports.VERTICAL_ALIGN_MENU = exports.VERTICAL_ALIGN_BOTTOM_MENU_ITEM = exports.LAYOUT_COLUMN_VERTICAL_ALIGN_MENU_SECTION = exports.LAYOUT_COLUMN_MENU_SECTION_RANK = exports.LAYOUT_COLUMN_MENU_SECTION = exports.LAYOUT_COLUMN_MENU_RANK = exports.LAYOUT_COLUMN_MENU = exports.DISTRIBUTE_COLUMNS_MENU_ITEM = void 0;
7
+ exports.VERTICAL_ALIGN_TOP_MENU_ITEM = exports.VERTICAL_ALIGN_MIDDLE_MENU_ITEM = exports.VERTICAL_ALIGN_MENU_SECTION_RANK = exports.VERTICAL_ALIGN_MENU_RANK = exports.VERTICAL_ALIGN_MENU = exports.VERTICAL_ALIGN_BOTTOM_MENU_ITEM = exports.LAYOUT_COLUMN_VERTICAL_ALIGN_MENU_SECTION = exports.LAYOUT_COLUMN_MENU_SECTION_RANK = exports.LAYOUT_COLUMN_MENU_SECTION = exports.LAYOUT_COLUMN_MENU_RANK = exports.LAYOUT_COLUMN_MENU = exports.INSERT_COLUMN_RIGHT_MENU_ITEM = exports.INSERT_COLUMN_LEFT_MENU_ITEM = exports.DISTRIBUTE_COLUMNS_MENU_ITEM = exports.DELETE_COLUMN_MENU_ITEM = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  // --- Menu surface ---
10
10
 
@@ -34,6 +34,14 @@ var VERTICAL_ALIGN_MENU = exports.VERTICAL_ALIGN_MENU = {
34
34
 
35
35
  // --- Items ---
36
36
 
37
+ var INSERT_COLUMN_LEFT_MENU_ITEM = exports.INSERT_COLUMN_LEFT_MENU_ITEM = {
38
+ type: 'menu-item',
39
+ key: 'layout-column-menu-insert-left-item'
40
+ };
41
+ var INSERT_COLUMN_RIGHT_MENU_ITEM = exports.INSERT_COLUMN_RIGHT_MENU_ITEM = {
42
+ type: 'menu-item',
43
+ key: 'layout-column-menu-insert-right-item'
44
+ };
37
45
  var DISTRIBUTE_COLUMNS_MENU_ITEM = exports.DISTRIBUTE_COLUMNS_MENU_ITEM = {
38
46
  type: 'menu-item',
39
47
  key: 'layout-column-menu-distribute-columns-item'
@@ -50,9 +58,13 @@ var VERTICAL_ALIGN_BOTTOM_MENU_ITEM = exports.VERTICAL_ALIGN_BOTTOM_MENU_ITEM =
50
58
  type: 'menu-item',
51
59
  key: 'layout-column-menu-vertical-align-bottom-item'
52
60
  };
61
+ var DELETE_COLUMN_MENU_ITEM = exports.DELETE_COLUMN_MENU_ITEM = {
62
+ type: 'menu-item',
63
+ key: 'layout-column-menu-delete-item'
64
+ };
53
65
 
54
66
  // --- Item ranks within sections ---
55
67
 
56
- var LAYOUT_COLUMN_MENU_SECTION_RANK = exports.LAYOUT_COLUMN_MENU_SECTION_RANK = (0, _defineProperty2.default)((0, _defineProperty2.default)({}, DISTRIBUTE_COLUMNS_MENU_ITEM.key, 100), VERTICAL_ALIGN_MENU.key, 200);
68
+ var LAYOUT_COLUMN_MENU_SECTION_RANK = exports.LAYOUT_COLUMN_MENU_SECTION_RANK = (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, VERTICAL_ALIGN_MENU.key, 100), INSERT_COLUMN_LEFT_MENU_ITEM.key, 200), INSERT_COLUMN_RIGHT_MENU_ITEM.key, 300), DISTRIBUTE_COLUMNS_MENU_ITEM.key, 400), DELETE_COLUMN_MENU_ITEM.key, 500);
57
69
  var VERTICAL_ALIGN_MENU_RANK = exports.VERTICAL_ALIGN_MENU_RANK = (0, _defineProperty2.default)({}, LAYOUT_COLUMN_VERTICAL_ALIGN_MENU_SECTION.key, 100);
58
70
  var VERTICAL_ALIGN_MENU_SECTION_RANK = exports.VERTICAL_ALIGN_MENU_SECTION_RANK = (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, VERTICAL_ALIGN_TOP_MENU_ITEM.key, 100), VERTICAL_ALIGN_MIDDLE_MENU_ITEM.key, 200), VERTICAL_ALIGN_BOTTOM_MENU_ITEM.key, 300);
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getLayoutSectionColumnCount = exports.getLayoutSectionAtSelection = exports.getLayoutColumnValign = exports.getLayoutColumnAtSelection = void 0;
7
+ var _state = require("@atlaskit/editor-prosemirror/state");
8
+ var getLayoutColumnAtSelection = exports.getLayoutColumnAtSelection = function getLayoutColumnAtSelection(selection) {
9
+ return selection instanceof _state.NodeSelection && selection.node.type.name === 'layoutColumn' ? selection.node : undefined;
10
+ };
11
+ var getLayoutSectionAtSelection = exports.getLayoutSectionAtSelection = function getLayoutSectionAtSelection(selection) {
12
+ var selectedColumn = getLayoutColumnAtSelection(selection);
13
+ var parent = selectedColumn ? selection === null || selection === void 0 ? void 0 : selection.$from.parent : undefined;
14
+ return (parent === null || parent === void 0 ? void 0 : parent.type.name) === 'layoutSection' ? parent : undefined;
15
+ };
16
+ var getLayoutSectionColumnCount = exports.getLayoutSectionColumnCount = function getLayoutSectionColumnCount(layoutSection) {
17
+ return (layoutSection === null || layoutSection === void 0 ? void 0 : layoutSection.type.name) === 'layoutSection' ? layoutSection.childCount : 0;
18
+ };
19
+ var getLayoutColumnValign = exports.getLayoutColumnValign = function getLayoutColumnValign(layoutColumn) {
20
+ return layoutColumn === null || layoutColumn === void 0 ? void 0 : layoutColumn.attrs.valign;
21
+ };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useCurrentLayoutSection = exports.useCurrentLayoutColumn = void 0;
7
+ var _hooks = require("@atlaskit/editor-common/hooks");
8
+ var _layoutColumnSelection = require("./layoutColumnSelection");
9
+ var useCurrentLayoutColumn = exports.useCurrentLayoutColumn = function useCurrentLayoutColumn(api) {
10
+ return (0, _hooks.useSharedPluginStateWithSelector)(api, ['selection'], function (states) {
11
+ var _states$selectionStat;
12
+ return (0, _layoutColumnSelection.getLayoutColumnAtSelection)((_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection);
13
+ });
14
+ };
15
+ var useCurrentLayoutSection = exports.useCurrentLayoutSection = function useCurrentLayoutSection(api) {
16
+ return (0, _hooks.useSharedPluginStateWithSelector)(api, ['selection'], function (states) {
17
+ var _states$selectionStat2;
18
+ return (0, _layoutColumnSelection.getLayoutSectionAtSelection)((_states$selectionStat2 = states.selectionState) === null || _states$selectionStat2 === void 0 ? void 0 : _states$selectionStat2.selection);
19
+ });
20
+ };
@@ -10,7 +10,7 @@ import { findParentNode } from '@atlaskit/editor-prosemirror/utils';
10
10
  import { fg } from '@atlaskit/platform-feature-flags';
11
11
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
12
12
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
13
- import { createDefaultLayoutSection, createMultiColumnLayoutSection, insertLayoutColumnsWithAnalytics, setLayoutColumnValign, toggleLayoutColumnMenu } from './pm-plugins/actions';
13
+ import { createDefaultLayoutSection, createMultiColumnLayoutSection, deleteLayoutColumn, insertLayoutColumn, insertLayoutColumnsWithAnalytics, setLayoutColumnValign, toggleLayoutColumnMenu } from './pm-plugins/actions';
14
14
  import { default as createLayoutPlugin } from './pm-plugins/main';
15
15
  import { pluginKey } from './pm-plugins/plugin-key';
16
16
  import { default as createLayoutResizingPlugin } from './pm-plugins/resizing';
@@ -290,6 +290,14 @@ export const layoutPlugin = ({
290
290
  return pluginKey.getState(editorState);
291
291
  },
292
292
  commands: {
293
+ deleteLayoutColumn: props => {
294
+ var _api$analytics4;
295
+ return deleteLayoutColumn(api === null || api === void 0 ? void 0 : (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 ? void 0 : _api$analytics4.actions)(props);
296
+ },
297
+ insertLayoutColumn: side => {
298
+ var _api$analytics5;
299
+ return insertLayoutColumn(side, api === null || api === void 0 ? void 0 : (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 ? void 0 : _api$analytics5.actions);
300
+ },
293
301
  setLayoutColumnValign,
294
302
  toggleLayoutColumnMenu
295
303
  }
@@ -7,8 +7,9 @@ import { safeInsert } from '@atlaskit/editor-prosemirror/utils';
7
7
  import { fg } from '@atlaskit/platform-feature-flags';
8
8
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
9
9
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
10
- import { EVEN_DISTRIBUTED_COL_WIDTHS } from './consts';
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
+ import { redistributeAfterDeletion, redistributeProportionally } from './utils/redistribute-proportionally';
12
13
  export const ONE_COL_LAYOUTS = ['single'];
13
14
  export const TWO_COL_LAYOUTS = ['two_equal', 'two_left_sidebar', 'two_right_sidebar'];
14
15
  export const THREE_COL_LAYOUTS = ['three_equal', 'three_with_sidebars'];
@@ -526,6 +527,102 @@ const formatLayoutName = layout => {
526
527
  return LAYOUT_TYPE.THREE_WITH_SIDEBARS;
527
528
  }
528
529
  };
530
+ /**
531
+ * Returns the active maximum layout column count for the current advanced layouts experiment state.
532
+ */
533
+ export function getEffectiveMaxLayoutColumns() {
534
+ return editorExperiment('advanced_layouts', true) ? MAX_LAYOUT_COLUMNS : MAX_STANDARD_LAYOUT_COLUMNS;
535
+ }
536
+ const getSelectedLayoutColumnInSection = ({
537
+ doc,
538
+ selection
539
+ }) => {
540
+ const {
541
+ layoutColumn,
542
+ layoutSection
543
+ } = doc.type.schema.nodes;
544
+ if (!(selection instanceof NodeSelection) || selection.node.type !== layoutColumn) {
545
+ return;
546
+ }
547
+ const {
548
+ $from
549
+ } = selection;
550
+ if ($from.parent.type !== layoutSection) {
551
+ return;
552
+ }
553
+ const selectedColumnIndex = $from.index($from.depth);
554
+ const selectedColumnNode = selection.node;
555
+ const selectedColumnPos = selection.from;
556
+ const layoutSectionPos = $from.before($from.depth);
557
+ return {
558
+ layoutSectionNode: $from.parent,
559
+ layoutSectionPos,
560
+ selectedColumnIndex,
561
+ selectedColumnNode,
562
+ selectedColumnPos
563
+ };
564
+ };
565
+ const insertLayoutColumnAt = (side, editorAnalyticsAPI) => ({
566
+ tr
567
+ }) => {
568
+ if (!expValEqualsNoExposure('platform_editor_layout_column_menu', 'isEnabled', true)) {
569
+ return null;
570
+ }
571
+ const selectedColumn = getSelectedLayoutColumnInSection(tr);
572
+ if (!selectedColumn) {
573
+ return null;
574
+ }
575
+ const {
576
+ layoutSectionNode,
577
+ layoutSectionPos,
578
+ selectedColumnIndex
579
+ } = selectedColumn;
580
+ if (layoutSectionNode.childCount >= getEffectiveMaxLayoutColumns()) {
581
+ return null;
582
+ }
583
+ const insertIndex = side === 'left' ? selectedColumnIndex : selectedColumnIndex + 1;
584
+ const existingWidths = mapChildren(layoutSectionNode, column => column.attrs.width);
585
+ const redistributedWidths = redistributeProportionally(existingWidths, insertIndex, getEffectiveMaxLayoutColumns(), MIN_LAYOUT_COLUMN_WIDTH_PERCENT);
586
+ if (redistributedWidths === existingWidths) {
587
+ return null;
588
+ }
589
+ const {
590
+ layoutColumn
591
+ } = tr.doc.type.schema.nodes;
592
+ const newColumn = layoutColumn.createAndFill({
593
+ width: redistributedWidths[insertIndex]
594
+ });
595
+ if (!newColumn) {
596
+ return null;
597
+ }
598
+ const updatedColumns = [];
599
+ layoutSectionNode.forEach((column, _offset, index) => {
600
+ if (index === insertIndex) {
601
+ updatedColumns.push(newColumn);
602
+ }
603
+ updatedColumns.push(column);
604
+ });
605
+ if (insertIndex === layoutSectionNode.childCount) {
606
+ updatedColumns.push(newColumn);
607
+ }
608
+ const updatedLayoutSectionNode = layoutSectionNode.copy(Fragment.fromArray(updatedColumns));
609
+ tr.replaceWith(layoutSectionPos + 1, layoutSectionPos + layoutSectionNode.nodeSize - 1, columnWidth(updatedLayoutSectionNode, tr.doc.type.schema, redistributedWidths));
610
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
611
+ action: ACTION.INSERTED,
612
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
613
+ actionSubjectId: ACTION_SUBJECT_ID.LAYOUT_COLUMN,
614
+ attributes: {
615
+ columnCount: redistributedWidths.length,
616
+ inputMethod: INPUT_METHOD.LAYOUT_COLUMN_MENU,
617
+ selectedIndex: selectedColumnIndex,
618
+ side
619
+ },
620
+ eventType: EVENT_TYPE.TRACK
621
+ })(tr);
622
+ tr.setMeta('scrollIntoView', false);
623
+ return tr;
624
+ };
625
+ export const insertLayoutColumn = (side, editorAnalyticsAPI) => insertLayoutColumnAt(side, editorAnalyticsAPI);
529
626
  export const setLayoutColumnValign = valign => ({
530
627
  tr
531
628
  }) => {
@@ -562,4 +659,58 @@ export const toggleLayoutColumnMenu = ({
562
659
  });
563
660
  tr.setMeta('scrollIntoView', false);
564
661
  return tr;
662
+ };
663
+ export const deleteLayoutColumn = editorAnalyticsAPI => ({
664
+ tr
665
+ }) => {
666
+ if (!expValEqualsNoExposure('platform_editor_layout_column_menu', 'isEnabled', true)) {
667
+ return null;
668
+ }
669
+ const selectedColumn = getSelectedLayoutColumnInSection(tr);
670
+ if (!selectedColumn) {
671
+ return null;
672
+ }
673
+ const {
674
+ layoutSectionNode,
675
+ layoutSectionPos,
676
+ selectedColumnIndex
677
+ } = selectedColumn;
678
+ const emitDeleteColumnAnalytics = columnCount => {
679
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
680
+ action: ACTION.DELETED,
681
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
682
+ actionSubjectId: ACTION_SUBJECT_ID.LAYOUT_COLUMN,
683
+ attributes: {
684
+ columnCount,
685
+ inputMethod: INPUT_METHOD.LAYOUT_COLUMN_MENU,
686
+ selectedIndex: selectedColumnIndex
687
+ },
688
+ eventType: EVENT_TYPE.TRACK
689
+ })(tr);
690
+ };
691
+
692
+ // If only one column remains, remove the entire layoutSection
693
+ if (layoutSectionNode.childCount === 1) {
694
+ tr.delete(layoutSectionPos, layoutSectionPos + layoutSectionNode.nodeSize);
695
+ emitDeleteColumnAnalytics(0);
696
+ tr.setMeta('scrollIntoView', false);
697
+ return tr;
698
+ }
699
+
700
+ // Build new column list without the selected column
701
+ const remainingColumns = [];
702
+ layoutSectionNode.forEach((column, _offset, index) => {
703
+ if (index !== selectedColumnIndex) {
704
+ remainingColumns.push(column);
705
+ }
706
+ });
707
+
708
+ // Redistribute widths proportionally among remaining columns using shared utility
709
+ const existingWidths = mapChildren(layoutSectionNode, column => column.attrs.width);
710
+ const redistributed = redistributeAfterDeletion(existingWidths, selectedColumnIndex, MIN_LAYOUT_COLUMN_WIDTH_PERCENT);
711
+ const updatedLayoutSectionNode = layoutSectionNode.copy(Fragment.fromArray(remainingColumns));
712
+ tr.replaceWith(layoutSectionPos + 1, layoutSectionPos + layoutSectionNode.nodeSize - 1, columnWidth(updatedLayoutSectionNode, tr.doc.type.schema, redistributed));
713
+ emitDeleteColumnAnalytics(redistributed.length);
714
+ tr.setMeta('scrollIntoView', false);
715
+ return tr;
565
716
  };
@@ -1,14 +1,13 @@
1
1
  import { bind } from 'bind-event-listener';
2
2
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
3
3
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
4
+ import { MIN_LAYOUT_COLUMN_WIDTH_PERCENT } from './consts';
5
+
4
6
  // Class names for the column resize divider widget — must stay in sync with layout.ts in editor-core
5
7
  const layoutColumnDividerClassName = 'layout-column-divider';
6
8
  const layoutColumnDividerRailClassName = 'layout-column-divider-rail';
7
9
  const layoutColumnDividerThumbClassName = 'layout-column-divider-thumb';
8
10
 
9
- // Minimum column width percentage to prevent columns from collapsing
10
- const MIN_COLUMN_WIDTH_PERCENT = 5;
11
-
12
11
  // Module-level drag state so it survives widget DOM recreation during transactions.
13
12
  let dragState = null;
14
13
 
@@ -75,12 +74,12 @@ const calcDragWidths = clientX => {
75
74
  const deltaPercent = deltaX / columnsWidth * 100;
76
75
  let leftWidth = dragState.startLeftWidth + deltaPercent;
77
76
  let rightWidth = dragState.startRightWidth - deltaPercent;
78
- if (leftWidth < MIN_COLUMN_WIDTH_PERCENT) {
79
- leftWidth = MIN_COLUMN_WIDTH_PERCENT;
80
- rightWidth = combinedWidth - MIN_COLUMN_WIDTH_PERCENT;
81
- } else if (rightWidth < MIN_COLUMN_WIDTH_PERCENT) {
82
- rightWidth = MIN_COLUMN_WIDTH_PERCENT;
83
- leftWidth = combinedWidth - MIN_COLUMN_WIDTH_PERCENT;
77
+ if (leftWidth < MIN_LAYOUT_COLUMN_WIDTH_PERCENT) {
78
+ leftWidth = MIN_LAYOUT_COLUMN_WIDTH_PERCENT;
79
+ rightWidth = combinedWidth - MIN_LAYOUT_COLUMN_WIDTH_PERCENT;
80
+ } else if (rightWidth < MIN_LAYOUT_COLUMN_WIDTH_PERCENT) {
81
+ rightWidth = MIN_LAYOUT_COLUMN_WIDTH_PERCENT;
82
+ leftWidth = combinedWidth - MIN_LAYOUT_COLUMN_WIDTH_PERCENT;
84
83
  }
85
84
  return {
86
85
  leftWidth,
@@ -1,3 +1,6 @@
1
+ export const MAX_STANDARD_LAYOUT_COLUMNS = 3;
2
+ export const MAX_LAYOUT_COLUMNS = 5;
3
+ export const MIN_LAYOUT_COLUMN_WIDTH_PERCENT = 5;
1
4
  export const EVEN_DISTRIBUTED_COL_WIDTHS = {
2
5
  1: 100,
3
6
  2: 50,
@@ -0,0 +1,113 @@
1
+ const roundLayoutColumnWidth = width => Number(width.toFixed(2));
2
+ const sumWidths = widths => widths.reduce((sum, width) => sum + width, 0);
3
+ const isValidWidth = width => Number.isFinite(width) && width > 0;
4
+ const normaliseWidthsTotal = (widths, totalWidth, minWidth) => {
5
+ const roundedWidths = widths.map(roundLayoutColumnWidth);
6
+ const remainder = roundLayoutColumnWidth(totalWidth - sumWidths(roundedWidths));
7
+ if (remainder === 0 || roundedWidths.length === 0) {
8
+ return roundedWidths;
9
+ }
10
+ let adjustmentIndex = 0;
11
+ roundedWidths.forEach((width, index) => {
12
+ if (width > roundedWidths[adjustmentIndex]) {
13
+ adjustmentIndex = index;
14
+ }
15
+ });
16
+ const adjustedWidth = roundLayoutColumnWidth(roundedWidths[adjustmentIndex] + remainder);
17
+ if (adjustedWidth < minWidth) {
18
+ return roundedWidths;
19
+ }
20
+ return roundedWidths.map((width, index) => index === adjustmentIndex ? adjustedWidth : width);
21
+ };
22
+ const redistributeWithMinimumWidth = ({
23
+ minWidth,
24
+ totalWidth,
25
+ weights
26
+ }) => {
27
+ if (weights.length * minWidth > totalWidth) {
28
+ return;
29
+ }
30
+ const widths = Array(weights.length).fill(0);
31
+ const clampedIndexes = new Set();
32
+ let remainingWidth = totalWidth;
33
+ let remainingWeight = sumWidths(weights);
34
+ while (clampedIndexes.size < weights.length) {
35
+ const remainingWidthForPass = remainingWidth;
36
+ const remainingWeightForPass = remainingWeight;
37
+ const indexesToClamp = [];
38
+ weights.forEach((weight, index) => {
39
+ if (clampedIndexes.has(index)) {
40
+ return;
41
+ }
42
+ const proportionalWidth = remainingWeightForPass > 0 ? weight / remainingWeightForPass * remainingWidthForPass : 0;
43
+ if (proportionalWidth < minWidth) {
44
+ indexesToClamp.push(index);
45
+ }
46
+ });
47
+ if (indexesToClamp.length === 0) {
48
+ break;
49
+ }
50
+ indexesToClamp.forEach(index => {
51
+ widths[index] = minWidth;
52
+ clampedIndexes.add(index);
53
+ remainingWidth -= minWidth;
54
+ remainingWeight -= weights[index];
55
+ });
56
+ }
57
+ weights.forEach((weight, index) => {
58
+ if (!clampedIndexes.has(index)) {
59
+ widths[index] = remainingWeight > 0 ? weight / remainingWeight * remainingWidth : minWidth;
60
+ }
61
+ });
62
+ return widths;
63
+ };
64
+ export const redistributeAfterDeletion = (currentWidths, removeIndex, minWidth) => {
65
+ if (currentWidths.length === 0 || removeIndex < 0 || removeIndex >= currentWidths.length || !isValidWidth(minWidth)) {
66
+ return currentWidths;
67
+ }
68
+ if (currentWidths.some(width => !isValidWidth(width))) {
69
+ return currentWidths.filter((_, i) => i !== removeIndex);
70
+ }
71
+ const remainingWidths = currentWidths.filter((_, i) => i !== removeIndex);
72
+ if (remainingWidths.length === 0) {
73
+ return remainingWidths;
74
+ }
75
+ const currentTotalWidth = sumWidths(currentWidths);
76
+ const targetTotalWidth = Math.round(currentTotalWidth) === 100 ? 100 : currentTotalWidth;
77
+ const redistributed = redistributeWithMinimumWidth({
78
+ weights: remainingWidths,
79
+ totalWidth: targetTotalWidth,
80
+ minWidth
81
+ });
82
+ if (!redistributed) {
83
+ const equalWidth = roundLayoutColumnWidth(targetTotalWidth / remainingWidths.length);
84
+ return normaliseWidthsTotal(Array(remainingWidths.length).fill(equalWidth), targetTotalWidth, minWidth);
85
+ }
86
+ return normaliseWidthsTotal(redistributed, targetTotalWidth, minWidth);
87
+ };
88
+ export const redistributeProportionally = (currentWidths, insertIndex, maxColumns, minWidth) => {
89
+ if (currentWidths.length === 0 || !Number.isInteger(maxColumns) || maxColumns <= 0 || currentWidths.length >= maxColumns || insertIndex < 0 || insertIndex > currentWidths.length || !isValidWidth(minWidth) || currentWidths.some(width => !isValidWidth(width))) {
90
+ return currentWidths;
91
+ }
92
+ const currentTotalWidth = sumWidths(currentWidths);
93
+ if (!isValidWidth(currentTotalWidth)) {
94
+ return currentWidths;
95
+ }
96
+ const targetTotalWidth = Math.round(currentTotalWidth) === 100 ? 100 : currentTotalWidth;
97
+ const newColumnWidth = Math.max(minWidth, roundLayoutColumnWidth(targetTotalWidth / (currentWidths.length + 1)));
98
+ const existingColumnsTotalWidth = targetTotalWidth - newColumnWidth;
99
+ if (existingColumnsTotalWidth < currentWidths.length * minWidth) {
100
+ return currentWidths;
101
+ }
102
+ const redistributedExistingWidths = redistributeWithMinimumWidth({
103
+ weights: currentWidths,
104
+ totalWidth: existingColumnsTotalWidth,
105
+ minWidth
106
+ });
107
+ if (!redistributedExistingWidths) {
108
+ return currentWidths;
109
+ }
110
+ const nextWidths = [...redistributedExistingWidths];
111
+ nextWidths.splice(insertIndex, 0, newColumnWidth);
112
+ return normaliseWidthsTotal(nextWidths, targetTotalWidth, minWidth);
113
+ };
@@ -0,0 +1,37 @@
1
+ import React, { useCallback } from 'react';
2
+ import { useIntl } from 'react-intl';
3
+ import { layoutMessages } from '@atlaskit/editor-common/messages';
4
+ import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
5
+ import { useCurrentLayoutColumn } from './useCurrentLayoutColumn';
6
+ const DeleteColumnDropdownItem = ({
7
+ api
8
+ }) => {
9
+ const {
10
+ formatMessage
11
+ } = useIntl();
12
+ const currentColumn = useCurrentLayoutColumn(api);
13
+ const onClick = useCallback(() => {
14
+ var _api$layout, _api$core;
15
+ const deleteCommand = api === null || api === void 0 ? void 0 : (_api$layout = api.layout) === null || _api$layout === void 0 ? void 0 : _api$layout.commands.deleteLayoutColumn;
16
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(props => {
17
+ var _api$layout2;
18
+ const tr = deleteCommand === null || deleteCommand === void 0 ? void 0 : deleteCommand(props);
19
+ if (!tr) {
20
+ return tr !== null && tr !== void 0 ? tr : null;
21
+ }
22
+ api === null || api === void 0 ? void 0 : (_api$layout2 = api.layout) === null || _api$layout2 === void 0 ? void 0 : _api$layout2.commands.toggleLayoutColumnMenu({
23
+ isOpen: false
24
+ })({
25
+ tr
26
+ });
27
+ return tr;
28
+ });
29
+ }, [api]);
30
+ if (currentColumn === undefined) {
31
+ return null;
32
+ }
33
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
34
+ onClick: onClick
35
+ }, formatMessage(layoutMessages.deleteColumn));
36
+ };
37
+ export { DeleteColumnDropdownItem };