@atlaskit/editor-plugin-block-menu 0.0.11 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 0.0.13
4
+
5
+ ### Patch Changes
6
+
7
+ - [`6dd96d8ae168d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6dd96d8ae168d) -
8
+ [ux] ED-28581 ED-28581: Updated renderer logic to better support nest menu items register from
9
+ outside block menu
10
+ - Updated dependencies
11
+
12
+ ## 0.0.12
13
+
14
+ ### Patch Changes
15
+
16
+ - [`2d45ff8531e21`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/2d45ff8531e21) -
17
+ Update move up and down registration and move blockMenuPlugin up in the fullPagePreset.
18
+
3
19
  ## 0.0.11
4
20
 
5
21
  ### Patch Changes
@@ -50,6 +50,9 @@
50
50
  {
51
51
  "path": "../../../design-system/icon-lab/afm-cc/tsconfig.json"
52
52
  },
53
+ {
54
+ "path": "../../../platform/feature-flags/afm-cc/tsconfig.json"
55
+ },
53
56
  {
54
57
  "path": "../../../design-system/primitives/afm-cc/tsconfig.json"
55
58
  },
@@ -60,4 +63,4 @@
60
63
  "path": "../../editor-common/afm-cc/tsconfig.json"
61
64
  }
62
65
  ]
63
- }
66
+ }
@@ -50,6 +50,9 @@
50
50
  {
51
51
  "path": "../../../design-system/icon-lab/afm-dev-agents/tsconfig.json"
52
52
  },
53
+ {
54
+ "path": "../../../platform/feature-flags/afm-dev-agents/tsconfig.json"
55
+ },
53
56
  {
54
57
  "path": "../../../design-system/primitives/afm-dev-agents/tsconfig.json"
55
58
  },
@@ -50,6 +50,9 @@
50
50
  {
51
51
  "path": "../../../design-system/icon-lab/afm-jira/tsconfig.json"
52
52
  },
53
+ {
54
+ "path": "../../../platform/feature-flags/afm-jira/tsconfig.json"
55
+ },
53
56
  {
54
57
  "path": "../../../design-system/primitives/afm-jira/tsconfig.json"
55
58
  },
@@ -50,6 +50,9 @@
50
50
  {
51
51
  "path": "../../../design-system/icon-lab/afm-passionfruit/tsconfig.json"
52
52
  },
53
+ {
54
+ "path": "../../../platform/feature-flags/afm-passionfruit/tsconfig.json"
55
+ },
53
56
  {
54
57
  "path": "../../../design-system/primitives/afm-passionfruit/tsconfig.json"
55
58
  },
@@ -50,6 +50,9 @@
50
50
  {
51
51
  "path": "../../../design-system/icon-lab/afm-post-office/tsconfig.json"
52
52
  },
53
+ {
54
+ "path": "../../../platform/feature-flags/afm-post-office/tsconfig.json"
55
+ },
53
56
  {
54
57
  "path": "../../../design-system/primitives/afm-post-office/tsconfig.json"
55
58
  },
@@ -50,6 +50,9 @@
50
50
  {
51
51
  "path": "../../../design-system/icon-lab/afm-rovo-extension/tsconfig.json"
52
52
  },
53
+ {
54
+ "path": "../../../platform/feature-flags/afm-rovo-extension/tsconfig.json"
55
+ },
53
56
  {
54
57
  "path": "../../../design-system/primitives/afm-rovo-extension/tsconfig.json"
55
58
  },
@@ -50,6 +50,9 @@
50
50
  {
51
51
  "path": "../../../design-system/icon-lab/afm-townsquare/tsconfig.json"
52
52
  },
53
+ {
54
+ "path": "../../../platform/feature-flags/afm-townsquare/tsconfig.json"
55
+ },
53
56
  {
54
57
  "path": "../../../design-system/primitives/afm-townsquare/tsconfig.json"
55
58
  },
@@ -10,18 +10,13 @@ var _react = _interopRequireDefault(require("react"));
10
10
  var _editorToolbar = require("@atlaskit/editor-toolbar");
11
11
  var _changes = _interopRequireDefault(require("@atlaskit/icon/core/changes"));
12
12
  var _chevronRight = _interopRequireDefault(require("@atlaskit/icon/core/chevron-right"));
13
- var _listBulleted = _interopRequireDefault(require("@atlaskit/icon/core/list-bulleted"));
14
- var _task = _interopRequireDefault(require("@atlaskit/icon/core/task"));
13
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
15
14
  var _copyBlock = _interopRequireDefault(require("./copy-block"));
16
15
  var _copyLink = require("./copy-link");
17
16
  var _deleteButton = require("./delete-button");
18
17
  var _moveDown = require("./move-down");
19
18
  var _moveUp = require("./move-up");
20
19
  var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(api) {
21
- var _api$blockControls;
22
- if (!(api !== null && api !== void 0 && (_api$blockControls = api.blockControls) !== null && _api$blockControls !== void 0 && _api$blockControls.commands.moveNode)) {
23
- return [];
24
- }
25
20
  return [{
26
21
  type: 'block-menu-item',
27
22
  key: 'block-menu-item-move-up',
@@ -50,23 +45,64 @@ var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(a
50
45
  }
51
46
  }];
52
47
  };
53
- var getBlockMenuComponents = exports.getBlockMenuComponents = function getBlockMenuComponents(_ref) {
54
- var api = _ref.api,
55
- config = _ref.config;
48
+ var getFormatMenuComponents = function getFormatMenuComponents() {
56
49
  return [{
50
+ type: 'block-menu-nested',
51
+ key: 'nested-menu-format',
52
+ parent: {
53
+ type: 'block-menu-section',
54
+ key: 'block-menu-section-primary',
55
+ rank: 100
56
+ },
57
+ component: function component() {
58
+ var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
59
+ children: null
60
+ },
61
+ children = _ref.children;
62
+ return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarNestedDropdownMenu, {
63
+ text: "Format",
64
+ elemBefore: /*#__PURE__*/_react.default.createElement(_changes.default, {
65
+ label: ""
66
+ }),
67
+ elemAfter: /*#__PURE__*/_react.default.createElement(_chevronRight.default, {
68
+ label: 'example nested menu'
69
+ })
70
+ }, children);
71
+ }
72
+ }, {
57
73
  type: 'block-menu-section',
58
- key: 'block-menu-section-format',
74
+ key: 'nested-menu-format-section-primary',
75
+ parent: {
76
+ type: 'block-menu-nested',
77
+ key: 'nested-menu-format',
78
+ rank: 100
79
+ },
80
+ component: function component() {
81
+ var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
82
+ children: null
83
+ },
84
+ children = _ref2.children;
85
+ return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, null, children);
86
+ }
87
+ }];
88
+ };
89
+ var getBlockMenuComponents = exports.getBlockMenuComponents = function getBlockMenuComponents(_ref3) {
90
+ var api = _ref3.api,
91
+ config = _ref3.config;
92
+ return [].concat((0, _toConsumableArray2.default)((0, _platformFeatureFlags.fg)('platform_editor_block_menu_format') ? getFormatMenuComponents() : []), [{
93
+ type: 'block-menu-section',
94
+ key: 'block-menu-section-primary',
59
95
  rank: 100,
60
- component: function component(_ref2) {
61
- var children = _ref2.children;
96
+ component: function component(_ref4) {
97
+ var children = _ref4.children;
62
98
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, null, children);
63
99
  }
64
100
  }, {
65
101
  type: 'block-menu-section',
66
102
  key: 'block-menu-section-copy',
67
103
  rank: 200,
68
- component: function component(_ref3) {
69
- var children = _ref3.children;
104
+ component: function component(_ref5) {
105
+ var children = _ref5.children;
70
106
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, {
71
107
  hasSeparator: true
72
108
  }, children);
@@ -102,8 +138,8 @@ var getBlockMenuComponents = exports.getBlockMenuComponents = function getBlockM
102
138
  type: 'block-menu-section',
103
139
  key: 'block-menu-section-move-up-down',
104
140
  rank: 300,
105
- component: function component(_ref4) {
106
- var children = _ref4.children;
141
+ component: function component(_ref6) {
142
+ var children = _ref6.children;
107
143
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, {
108
144
  hasSeparator: true
109
145
  }, children);
@@ -112,40 +148,13 @@ var getBlockMenuComponents = exports.getBlockMenuComponents = function getBlockM
112
148
  type: 'block-menu-section',
113
149
  key: 'block-menu-section-delete',
114
150
  rank: 400,
115
- component: function component(_ref5) {
116
- var children = _ref5.children;
151
+ component: function component(_ref7) {
152
+ var children = _ref7.children;
117
153
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, {
118
154
  hasSeparator: true
119
155
  }, children);
120
156
  }
121
- }, {
122
- type: 'block-menu-nested',
123
- key: 'nested-menu',
124
- parent: {
125
- type: 'block-menu-section',
126
- key: 'block-menu-section-format',
127
- rank: 100
128
- },
129
- component: function component() {
130
- return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarNestedDropdownMenu, {
131
- text: "Format",
132
- elemBefore: /*#__PURE__*/_react.default.createElement(_changes.default, {
133
- label: ""
134
- }),
135
- elemAfter: /*#__PURE__*/_react.default.createElement(_chevronRight.default, {
136
- label: 'example nested menu'
137
- })
138
- }, /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, null, /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
139
- elemBefore: /*#__PURE__*/_react.default.createElement(_task.default, {
140
- label: ""
141
- })
142
- }, "Action item"), /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
143
- elemBefore: /*#__PURE__*/_react.default.createElement(_listBulleted.default, {
144
- label: ""
145
- })
146
- }, "Bullet list")));
147
- }
148
- }].concat((0, _toConsumableArray2.default)(getMoveUpMoveDownMenuComponents(api)), [{
157
+ }], (0, _toConsumableArray2.default)(getMoveUpMoveDownMenuComponents(api)), [{
149
158
  type: 'block-menu-item',
150
159
  key: 'block-menu-item-delete',
151
160
  parent: {
@@ -12,8 +12,8 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
12
12
  var NoOp = function NoOp(props) {
13
13
  return null;
14
14
  };
15
- var isMenuSection = function isMenuSection(component) {
16
- return component.type === 'block-menu-section';
15
+ var isNonNestedMenuSection = function isNonNestedMenuSection(component) {
16
+ return component.type === 'block-menu-section' && !('parent' in component);
17
17
  };
18
18
  var isMenuItem = function isMenuItem(component) {
19
19
  return component.type === 'block-menu-item';
@@ -21,31 +21,68 @@ var isMenuItem = function isMenuItem(component) {
21
21
  var isNestedMenu = function isNestedMenu(component) {
22
22
  return component.type === 'block-menu-nested';
23
23
  };
24
+ var isNestedMenuSection = function isNestedMenuSection(component) {
25
+ return 'parent' in component && component.parent !== undefined && component.parent.type === 'block-menu-nested';
26
+ };
24
27
  var getSortedChildren = function getSortedChildren(components, parentKey) {
25
28
  return components.filter(function (component) {
26
- return component.parent.key === parentKey;
29
+ return 'parent' in component && component.parent !== undefined && component.parent.key === parentKey;
27
30
  }).sort(function (a, b) {
28
31
  return (a.parent.rank || 0) - (b.parent.rank || 0);
29
32
  });
30
33
  };
31
- var getSortedSections = function getSortedSections(components) {
32
- return components.filter(isMenuSection).sort(function (a, b) {
34
+ var getSortedNestedSections = function getSortedNestedSections(components, parentKey) {
35
+ var nestedMenuSections = components.filter(isNestedMenuSection);
36
+ var nestedMenuSectionsWithParent = nestedMenuSections.filter(function (section) {
37
+ return section.parent !== undefined;
38
+ });
39
+ return getSortedChildren(nestedMenuSectionsWithParent, parentKey);
40
+ };
41
+ var getSortedNonNestedSections = function getSortedNonNestedSections(components) {
42
+ return components.filter(isNonNestedMenuSection).sort(function (a, b) {
33
43
  return (a.rank || 0) - (b.rank || 0);
34
44
  });
35
45
  };
36
46
  var BlockMenuRenderer = exports.BlockMenuRenderer = function BlockMenuRenderer(_ref) {
37
47
  var components = _ref.components,
38
48
  fallbacks = _ref.fallbacks;
39
- var menuSections = getSortedSections(components);
49
+ var menuSections = getSortedNonNestedSections(components);
40
50
  var menuItems = components.filter(isMenuItem);
41
51
  var nestedMenus = components.filter(isNestedMenu);
42
52
  return /*#__PURE__*/_react.default.createElement(_react.Fragment, null, menuSections.map(function (section) {
43
- var children = getSortedChildren([].concat((0, _toConsumableArray2.default)(menuItems), (0, _toConsumableArray2.default)(nestedMenus)), section.key).map(function (item) {
44
- var ItemComponent = item.component || fallbacks.item || NoOp;
45
- return /*#__PURE__*/_react.default.createElement(ItemComponent, {
46
- key: item.key
53
+ // Get all items for the current section, including nested menus, and sort them by rank
54
+ var currentSectionItemsSorted = getSortedChildren([].concat((0, _toConsumableArray2.default)(menuItems), (0, _toConsumableArray2.default)(nestedMenus)), section.key);
55
+
56
+ // iterate over the current section items, if it is nested menu, get their children, sort them
57
+ // if they are menu items, just render as they are sorted above
58
+ var getChildrenWithNestedItems = function getChildrenWithNestedItems(items) {
59
+ return items.map(function (item) {
60
+ if (isNestedMenu(item)) {
61
+ var sortedNestedSections = getSortedNestedSections(components, item.key);
62
+ return sortedNestedSections.map(function (section) {
63
+ var sortedNestedMenuItems = getSortedChildren(menuItems, section.key);
64
+ var NestedMenuComponent = item.component || fallbacks.nestedMenu || NoOp;
65
+ var NestedSection = section.component || fallbacks.section || NoOp;
66
+ return /*#__PURE__*/_react.default.createElement(NestedMenuComponent, {
67
+ key: item.key
68
+ }, /*#__PURE__*/_react.default.createElement(NestedSection, {
69
+ key: section.key
70
+ }, sortedNestedMenuItems.map(function (nestedItem) {
71
+ var NestedMenuItemComponent = nestedItem.component || fallbacks.item || NoOp;
72
+ return /*#__PURE__*/_react.default.createElement(NestedMenuItemComponent, {
73
+ key: nestedItem.key
74
+ });
75
+ })));
76
+ });
77
+ } else {
78
+ var ItemComponent = item.component || fallbacks.item || NoOp;
79
+ return /*#__PURE__*/_react.default.createElement(ItemComponent, {
80
+ key: item.key
81
+ });
82
+ }
47
83
  });
48
- });
84
+ };
85
+ var children = getChildrenWithNestedItems(currentSectionItemsSorted);
49
86
  var SectionComponent = section.component || fallbacks.section || NoOp;
50
87
  return /*#__PURE__*/_react.default.createElement(SectionComponent, {
51
88
  key: section.key
@@ -1,19 +1,14 @@
1
1
  import React from 'react';
2
- import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
2
+ import { ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
3
3
  import ChangesIcon from '@atlaskit/icon/core/changes';
4
4
  import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
5
- import ListBulletedIcon from '@atlaskit/icon/core/list-bulleted';
6
- import TaskIcon from '@atlaskit/icon/core/task';
5
+ import { fg } from '@atlaskit/platform-feature-flags';
7
6
  import CopyBlockMenuItem from './copy-block';
8
7
  import { CopyLinkDropdownItem } from './copy-link';
9
8
  import { DeleteDropdownItem } from './delete-button';
10
9
  import { MoveDownDropdownItem } from './move-down';
11
10
  import { MoveUpDropdownItem } from './move-up';
12
11
  const getMoveUpMoveDownMenuComponents = api => {
13
- var _api$blockControls;
14
- if (!(api !== null && api !== void 0 && (_api$blockControls = api.blockControls) !== null && _api$blockControls !== void 0 && _api$blockControls.commands.moveNode)) {
15
- return [];
16
- }
17
12
  return [{
18
13
  type: 'block-menu-item',
19
14
  key: 'block-menu-item-move-up',
@@ -38,13 +33,54 @@ const getMoveUpMoveDownMenuComponents = api => {
38
33
  })
39
34
  }];
40
35
  };
36
+ const getFormatMenuComponents = () => {
37
+ return [{
38
+ type: 'block-menu-nested',
39
+ key: 'nested-menu-format',
40
+ parent: {
41
+ type: 'block-menu-section',
42
+ key: 'block-menu-section-primary',
43
+ rank: 100
44
+ },
45
+ component: ({
46
+ children
47
+ } = {
48
+ children: null
49
+ }) => {
50
+ return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
51
+ text: "Format",
52
+ elemBefore: /*#__PURE__*/React.createElement(ChangesIcon, {
53
+ label: ""
54
+ }),
55
+ elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
56
+ label: 'example nested menu'
57
+ })
58
+ }, children);
59
+ }
60
+ }, {
61
+ type: 'block-menu-section',
62
+ key: 'nested-menu-format-section-primary',
63
+ parent: {
64
+ type: 'block-menu-nested',
65
+ key: 'nested-menu-format',
66
+ rank: 100
67
+ },
68
+ component: ({
69
+ children
70
+ } = {
71
+ children: null
72
+ }) => {
73
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
74
+ }
75
+ }];
76
+ };
41
77
  export const getBlockMenuComponents = ({
42
78
  api,
43
79
  config
44
80
  }) => {
45
- return [{
81
+ return [...(fg('platform_editor_block_menu_format') ? getFormatMenuComponents() : []), {
46
82
  type: 'block-menu-section',
47
- key: 'block-menu-section-format',
83
+ key: 'block-menu-section-primary',
48
84
  rank: 100,
49
85
  component: ({
50
86
  children
@@ -109,33 +145,6 @@ export const getBlockMenuComponents = ({
109
145
  hasSeparator: true
110
146
  }, children);
111
147
  }
112
- }, {
113
- type: 'block-menu-nested',
114
- key: 'nested-menu',
115
- parent: {
116
- type: 'block-menu-section',
117
- key: 'block-menu-section-format',
118
- rank: 100
119
- },
120
- component: () => {
121
- return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
122
- text: "Format",
123
- elemBefore: /*#__PURE__*/React.createElement(ChangesIcon, {
124
- label: ""
125
- }),
126
- elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
127
- label: 'example nested menu'
128
- })
129
- }, /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
130
- elemBefore: /*#__PURE__*/React.createElement(TaskIcon, {
131
- label: ""
132
- })
133
- }, "Action item"), /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
134
- elemBefore: /*#__PURE__*/React.createElement(ListBulletedIcon, {
135
- label: ""
136
- })
137
- }, "Bullet list")));
138
- }
139
148
  }, ...getMoveUpMoveDownMenuComponents(api), {
140
149
  type: 'block-menu-item',
141
150
  key: 'block-menu-item-delete',
@@ -1,7 +1,7 @@
1
1
  import React, { Fragment } from 'react';
2
2
  const NoOp = props => null;
3
- const isMenuSection = component => {
4
- return component.type === 'block-menu-section';
3
+ const isNonNestedMenuSection = component => {
4
+ return component.type === 'block-menu-section' && !('parent' in component);
5
5
  };
6
6
  const isMenuItem = component => {
7
7
  return component.type === 'block-menu-item';
@@ -9,24 +9,59 @@ const isMenuItem = component => {
9
9
  const isNestedMenu = component => {
10
10
  return component.type === 'block-menu-nested';
11
11
  };
12
- const getSortedChildren = (components, parentKey) => components.filter(component => component.parent.key === parentKey).sort((a, b) => (a.parent.rank || 0) - (b.parent.rank || 0));
13
- const getSortedSections = components => {
14
- return components.filter(isMenuSection).sort((a, b) => (a.rank || 0) - (b.rank || 0));
12
+ const isNestedMenuSection = component => {
13
+ return 'parent' in component && component.parent !== undefined && component.parent.type === 'block-menu-nested';
14
+ };
15
+ const getSortedChildren = (components, parentKey) => components.filter(component => 'parent' in component && component.parent !== undefined && component.parent.key === parentKey).sort((a, b) => (a.parent.rank || 0) - (b.parent.rank || 0));
16
+ const getSortedNestedSections = (components, parentKey) => {
17
+ const nestedMenuSections = components.filter(isNestedMenuSection);
18
+ const nestedMenuSectionsWithParent = nestedMenuSections.filter(section => section.parent !== undefined);
19
+ return getSortedChildren(nestedMenuSectionsWithParent, parentKey);
20
+ };
21
+ const getSortedNonNestedSections = components => {
22
+ return components.filter(isNonNestedMenuSection).sort((a, b) => (a.rank || 0) - (b.rank || 0));
15
23
  };
16
24
  export const BlockMenuRenderer = ({
17
25
  components,
18
26
  fallbacks
19
27
  }) => {
20
- const menuSections = getSortedSections(components);
28
+ const menuSections = getSortedNonNestedSections(components);
21
29
  const menuItems = components.filter(isMenuItem);
22
30
  const nestedMenus = components.filter(isNestedMenu);
23
31
  return /*#__PURE__*/React.createElement(Fragment, null, menuSections.map(section => {
24
- const children = getSortedChildren([...menuItems, ...nestedMenus], section.key).map(item => {
25
- const ItemComponent = item.component || fallbacks.item || NoOp;
26
- return /*#__PURE__*/React.createElement(ItemComponent, {
27
- key: item.key
32
+ // Get all items for the current section, including nested menus, and sort them by rank
33
+ const currentSectionItemsSorted = getSortedChildren([...menuItems, ...nestedMenus], section.key);
34
+
35
+ // iterate over the current section items, if it is nested menu, get their children, sort them
36
+ // if they are menu items, just render as they are sorted above
37
+ const getChildrenWithNestedItems = items => {
38
+ return items.map(item => {
39
+ if (isNestedMenu(item)) {
40
+ const sortedNestedSections = getSortedNestedSections(components, item.key);
41
+ return sortedNestedSections.map(section => {
42
+ const sortedNestedMenuItems = getSortedChildren(menuItems, section.key);
43
+ const NestedMenuComponent = item.component || fallbacks.nestedMenu || NoOp;
44
+ const NestedSection = section.component || fallbacks.section || NoOp;
45
+ return /*#__PURE__*/React.createElement(NestedMenuComponent, {
46
+ key: item.key
47
+ }, /*#__PURE__*/React.createElement(NestedSection, {
48
+ key: section.key
49
+ }, sortedNestedMenuItems.map(nestedItem => {
50
+ const NestedMenuItemComponent = nestedItem.component || fallbacks.item || NoOp;
51
+ return /*#__PURE__*/React.createElement(NestedMenuItemComponent, {
52
+ key: nestedItem.key
53
+ });
54
+ })));
55
+ });
56
+ } else {
57
+ const ItemComponent = item.component || fallbacks.item || NoOp;
58
+ return /*#__PURE__*/React.createElement(ItemComponent, {
59
+ key: item.key
60
+ });
61
+ }
28
62
  });
29
- });
63
+ };
64
+ const children = getChildrenWithNestedItems(currentSectionItemsSorted);
30
65
  const SectionComponent = section.component || fallbacks.section || NoOp;
31
66
  return /*#__PURE__*/React.createElement(SectionComponent, {
32
67
  key: section.key
@@ -1,20 +1,15 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
2
  import React from 'react';
3
- import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
3
+ import { ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
4
4
  import ChangesIcon from '@atlaskit/icon/core/changes';
5
5
  import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
6
- import ListBulletedIcon from '@atlaskit/icon/core/list-bulleted';
7
- import TaskIcon from '@atlaskit/icon/core/task';
6
+ import { fg } from '@atlaskit/platform-feature-flags';
8
7
  import CopyBlockMenuItem from './copy-block';
9
8
  import { CopyLinkDropdownItem } from './copy-link';
10
9
  import { DeleteDropdownItem } from './delete-button';
11
10
  import { MoveDownDropdownItem } from './move-down';
12
11
  import { MoveUpDropdownItem } from './move-up';
13
12
  var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(api) {
14
- var _api$blockControls;
15
- if (!(api !== null && api !== void 0 && (_api$blockControls = api.blockControls) !== null && _api$blockControls !== void 0 && _api$blockControls.commands.moveNode)) {
16
- return [];
17
- }
18
13
  return [{
19
14
  type: 'block-menu-item',
20
15
  key: 'block-menu-item-move-up',
@@ -43,23 +38,64 @@ var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(a
43
38
  }
44
39
  }];
45
40
  };
46
- export var getBlockMenuComponents = function getBlockMenuComponents(_ref) {
47
- var api = _ref.api,
48
- config = _ref.config;
41
+ var getFormatMenuComponents = function getFormatMenuComponents() {
49
42
  return [{
43
+ type: 'block-menu-nested',
44
+ key: 'nested-menu-format',
45
+ parent: {
46
+ type: 'block-menu-section',
47
+ key: 'block-menu-section-primary',
48
+ rank: 100
49
+ },
50
+ component: function component() {
51
+ var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
52
+ children: null
53
+ },
54
+ children = _ref.children;
55
+ return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
56
+ text: "Format",
57
+ elemBefore: /*#__PURE__*/React.createElement(ChangesIcon, {
58
+ label: ""
59
+ }),
60
+ elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
61
+ label: 'example nested menu'
62
+ })
63
+ }, children);
64
+ }
65
+ }, {
50
66
  type: 'block-menu-section',
51
- key: 'block-menu-section-format',
67
+ key: 'nested-menu-format-section-primary',
68
+ parent: {
69
+ type: 'block-menu-nested',
70
+ key: 'nested-menu-format',
71
+ rank: 100
72
+ },
73
+ component: function component() {
74
+ var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
75
+ children: null
76
+ },
77
+ children = _ref2.children;
78
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
79
+ }
80
+ }];
81
+ };
82
+ export var getBlockMenuComponents = function getBlockMenuComponents(_ref3) {
83
+ var api = _ref3.api,
84
+ config = _ref3.config;
85
+ return [].concat(_toConsumableArray(fg('platform_editor_block_menu_format') ? getFormatMenuComponents() : []), [{
86
+ type: 'block-menu-section',
87
+ key: 'block-menu-section-primary',
52
88
  rank: 100,
53
- component: function component(_ref2) {
54
- var children = _ref2.children;
89
+ component: function component(_ref4) {
90
+ var children = _ref4.children;
55
91
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
56
92
  }
57
93
  }, {
58
94
  type: 'block-menu-section',
59
95
  key: 'block-menu-section-copy',
60
96
  rank: 200,
61
- component: function component(_ref3) {
62
- var children = _ref3.children;
97
+ component: function component(_ref5) {
98
+ var children = _ref5.children;
63
99
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
64
100
  hasSeparator: true
65
101
  }, children);
@@ -95,8 +131,8 @@ export var getBlockMenuComponents = function getBlockMenuComponents(_ref) {
95
131
  type: 'block-menu-section',
96
132
  key: 'block-menu-section-move-up-down',
97
133
  rank: 300,
98
- component: function component(_ref4) {
99
- var children = _ref4.children;
134
+ component: function component(_ref6) {
135
+ var children = _ref6.children;
100
136
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
101
137
  hasSeparator: true
102
138
  }, children);
@@ -105,40 +141,13 @@ export var getBlockMenuComponents = function getBlockMenuComponents(_ref) {
105
141
  type: 'block-menu-section',
106
142
  key: 'block-menu-section-delete',
107
143
  rank: 400,
108
- component: function component(_ref5) {
109
- var children = _ref5.children;
144
+ component: function component(_ref7) {
145
+ var children = _ref7.children;
110
146
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
111
147
  hasSeparator: true
112
148
  }, children);
113
149
  }
114
- }, {
115
- type: 'block-menu-nested',
116
- key: 'nested-menu',
117
- parent: {
118
- type: 'block-menu-section',
119
- key: 'block-menu-section-format',
120
- rank: 100
121
- },
122
- component: function component() {
123
- return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
124
- text: "Format",
125
- elemBefore: /*#__PURE__*/React.createElement(ChangesIcon, {
126
- label: ""
127
- }),
128
- elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
129
- label: 'example nested menu'
130
- })
131
- }, /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
132
- elemBefore: /*#__PURE__*/React.createElement(TaskIcon, {
133
- label: ""
134
- })
135
- }, "Action item"), /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
136
- elemBefore: /*#__PURE__*/React.createElement(ListBulletedIcon, {
137
- label: ""
138
- })
139
- }, "Bullet list")));
140
- }
141
- }].concat(_toConsumableArray(getMoveUpMoveDownMenuComponents(api)), [{
150
+ }], _toConsumableArray(getMoveUpMoveDownMenuComponents(api)), [{
142
151
  type: 'block-menu-item',
143
152
  key: 'block-menu-item-delete',
144
153
  parent: {
@@ -3,8 +3,8 @@ import React, { Fragment } from 'react';
3
3
  var NoOp = function NoOp(props) {
4
4
  return null;
5
5
  };
6
- var isMenuSection = function isMenuSection(component) {
7
- return component.type === 'block-menu-section';
6
+ var isNonNestedMenuSection = function isNonNestedMenuSection(component) {
7
+ return component.type === 'block-menu-section' && !('parent' in component);
8
8
  };
9
9
  var isMenuItem = function isMenuItem(component) {
10
10
  return component.type === 'block-menu-item';
@@ -12,31 +12,68 @@ var isMenuItem = function isMenuItem(component) {
12
12
  var isNestedMenu = function isNestedMenu(component) {
13
13
  return component.type === 'block-menu-nested';
14
14
  };
15
+ var isNestedMenuSection = function isNestedMenuSection(component) {
16
+ return 'parent' in component && component.parent !== undefined && component.parent.type === 'block-menu-nested';
17
+ };
15
18
  var getSortedChildren = function getSortedChildren(components, parentKey) {
16
19
  return components.filter(function (component) {
17
- return component.parent.key === parentKey;
20
+ return 'parent' in component && component.parent !== undefined && component.parent.key === parentKey;
18
21
  }).sort(function (a, b) {
19
22
  return (a.parent.rank || 0) - (b.parent.rank || 0);
20
23
  });
21
24
  };
22
- var getSortedSections = function getSortedSections(components) {
23
- return components.filter(isMenuSection).sort(function (a, b) {
25
+ var getSortedNestedSections = function getSortedNestedSections(components, parentKey) {
26
+ var nestedMenuSections = components.filter(isNestedMenuSection);
27
+ var nestedMenuSectionsWithParent = nestedMenuSections.filter(function (section) {
28
+ return section.parent !== undefined;
29
+ });
30
+ return getSortedChildren(nestedMenuSectionsWithParent, parentKey);
31
+ };
32
+ var getSortedNonNestedSections = function getSortedNonNestedSections(components) {
33
+ return components.filter(isNonNestedMenuSection).sort(function (a, b) {
24
34
  return (a.rank || 0) - (b.rank || 0);
25
35
  });
26
36
  };
27
37
  export var BlockMenuRenderer = function BlockMenuRenderer(_ref) {
28
38
  var components = _ref.components,
29
39
  fallbacks = _ref.fallbacks;
30
- var menuSections = getSortedSections(components);
40
+ var menuSections = getSortedNonNestedSections(components);
31
41
  var menuItems = components.filter(isMenuItem);
32
42
  var nestedMenus = components.filter(isNestedMenu);
33
43
  return /*#__PURE__*/React.createElement(Fragment, null, menuSections.map(function (section) {
34
- var children = getSortedChildren([].concat(_toConsumableArray(menuItems), _toConsumableArray(nestedMenus)), section.key).map(function (item) {
35
- var ItemComponent = item.component || fallbacks.item || NoOp;
36
- return /*#__PURE__*/React.createElement(ItemComponent, {
37
- key: item.key
44
+ // Get all items for the current section, including nested menus, and sort them by rank
45
+ var currentSectionItemsSorted = getSortedChildren([].concat(_toConsumableArray(menuItems), _toConsumableArray(nestedMenus)), section.key);
46
+
47
+ // iterate over the current section items, if it is nested menu, get their children, sort them
48
+ // if they are menu items, just render as they are sorted above
49
+ var getChildrenWithNestedItems = function getChildrenWithNestedItems(items) {
50
+ return items.map(function (item) {
51
+ if (isNestedMenu(item)) {
52
+ var sortedNestedSections = getSortedNestedSections(components, item.key);
53
+ return sortedNestedSections.map(function (section) {
54
+ var sortedNestedMenuItems = getSortedChildren(menuItems, section.key);
55
+ var NestedMenuComponent = item.component || fallbacks.nestedMenu || NoOp;
56
+ var NestedSection = section.component || fallbacks.section || NoOp;
57
+ return /*#__PURE__*/React.createElement(NestedMenuComponent, {
58
+ key: item.key
59
+ }, /*#__PURE__*/React.createElement(NestedSection, {
60
+ key: section.key
61
+ }, sortedNestedMenuItems.map(function (nestedItem) {
62
+ var NestedMenuItemComponent = nestedItem.component || fallbacks.item || NoOp;
63
+ return /*#__PURE__*/React.createElement(NestedMenuItemComponent, {
64
+ key: nestedItem.key
65
+ });
66
+ })));
67
+ });
68
+ } else {
69
+ var ItemComponent = item.component || fallbacks.item || NoOp;
70
+ return /*#__PURE__*/React.createElement(ItemComponent, {
71
+ key: item.key
72
+ });
73
+ }
38
74
  });
39
- });
75
+ };
76
+ var children = getChildrenWithNestedItems(currentSectionItemsSorted);
40
77
  var SectionComponent = section.component || fallbacks.section || NoOp;
41
78
  return /*#__PURE__*/React.createElement(SectionComponent, {
42
79
  key: section.key
@@ -33,6 +33,19 @@ type WithRank<T> = T & {
33
33
  export type Parent<T> = WithRank<T>;
34
34
  type ComponentType = BlockMenuSection | BlockMenuItem | BlockMenuNested;
35
35
  export type ComponentTypes = Array<ComponentType>;
36
+ /**
37
+ * The relationship between BlockMenuItem, BlockMenuSection, BlockMenuNested
38
+ * BlockMenuSection can have BlockMenuItem or BlockMenuNested as children
39
+ * BlockMenuNested can have BlockMenuSection as children,
40
+ * BlockMenuNested, with BlockMenuSection and BlockMenuItem, is a nested menu
41
+ * _______________________________________
42
+ * | Block menu (no typing)
43
+ * | |BlockMenuSection
44
+ * | | |BlockMenuItem
45
+ * | | |BlockMenuNested
46
+ * | | | |BlockMenuSection
47
+ * | | | | |BlockMenuItem
48
+ */
36
49
  type BlockMenuItem = {
37
50
  key: string;
38
51
  type: 'block-menu-item';
@@ -45,10 +58,15 @@ type BlockMenuNested = {
45
58
  key: string;
46
59
  type: 'block-menu-nested';
47
60
  };
48
- export type BlockMenuNestedComponent = () => React.ReactNode;
61
+ export type BlockMenuNestedComponent = (props?: {
62
+ children: React.ReactNode;
63
+ }) => React.ReactNode;
49
64
  export type BlockMenuSectionComponent = (props: {
50
65
  children: React.ReactNode;
51
66
  }) => React.ReactNode;
67
+ export type BlockMenuNestedSectionComponent = (props: {
68
+ children: React.ReactNode;
69
+ }) => React.ReactNode;
52
70
  export type BlockMenuItemComponent = () => React.ReactNode;
53
71
  export type RegisterBlockMenuNested = BlockMenuNested & {
54
72
  component?: BlockMenuNestedComponent;
@@ -56,7 +74,8 @@ export type RegisterBlockMenuNested = BlockMenuNested & {
56
74
  };
57
75
  export type RegisterBlockMenuSection = BlockMenuSection & {
58
76
  component?: BlockMenuSectionComponent;
59
- rank: number;
77
+ parent?: Parent<BlockMenuNested>;
78
+ rank?: number;
60
79
  };
61
80
  export type RegisterBlockMenuItem = BlockMenuItem & {
62
81
  component?: BlockMenuItemComponent;
@@ -3,7 +3,7 @@ import type { WrappedComponentProps } from 'react-intl-next';
3
3
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
4
  import type { BlockMenuPlugin } from '../blockMenuPluginType';
5
5
  type Props = {
6
- api: ExtractInjectionAPI<BlockMenuPlugin>;
6
+ api: ExtractInjectionAPI<BlockMenuPlugin> | undefined;
7
7
  };
8
8
  export declare const MoveDownDropdownItem: React.FC<import("react-intl-next").WithIntlProps<Props & WrappedComponentProps>> & {
9
9
  WrappedComponent: React.ComponentType<Props & WrappedComponentProps>;
@@ -3,7 +3,7 @@ import type { WrappedComponentProps } from 'react-intl-next';
3
3
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
4
  import type { BlockMenuPlugin } from '../blockMenuPluginType';
5
5
  type Props = {
6
- api: ExtractInjectionAPI<BlockMenuPlugin>;
6
+ api: ExtractInjectionAPI<BlockMenuPlugin> | undefined;
7
7
  };
8
8
  export declare const MoveUpDropdownItem: React.FC<import("react-intl-next").WithIntlProps<Props & WrappedComponentProps>> & {
9
9
  WrappedComponent: React.ComponentType<Props & WrappedComponentProps>;
@@ -33,6 +33,19 @@ type WithRank<T> = T & {
33
33
  export type Parent<T> = WithRank<T>;
34
34
  type ComponentType = BlockMenuSection | BlockMenuItem | BlockMenuNested;
35
35
  export type ComponentTypes = Array<ComponentType>;
36
+ /**
37
+ * The relationship between BlockMenuItem, BlockMenuSection, BlockMenuNested
38
+ * BlockMenuSection can have BlockMenuItem or BlockMenuNested as children
39
+ * BlockMenuNested can have BlockMenuSection as children,
40
+ * BlockMenuNested, with BlockMenuSection and BlockMenuItem, is a nested menu
41
+ * _______________________________________
42
+ * | Block menu (no typing)
43
+ * | |BlockMenuSection
44
+ * | | |BlockMenuItem
45
+ * | | |BlockMenuNested
46
+ * | | | |BlockMenuSection
47
+ * | | | | |BlockMenuItem
48
+ */
36
49
  type BlockMenuItem = {
37
50
  key: string;
38
51
  type: 'block-menu-item';
@@ -45,10 +58,15 @@ type BlockMenuNested = {
45
58
  key: string;
46
59
  type: 'block-menu-nested';
47
60
  };
48
- export type BlockMenuNestedComponent = () => React.ReactNode;
61
+ export type BlockMenuNestedComponent = (props?: {
62
+ children: React.ReactNode;
63
+ }) => React.ReactNode;
49
64
  export type BlockMenuSectionComponent = (props: {
50
65
  children: React.ReactNode;
51
66
  }) => React.ReactNode;
67
+ export type BlockMenuNestedSectionComponent = (props: {
68
+ children: React.ReactNode;
69
+ }) => React.ReactNode;
52
70
  export type BlockMenuItemComponent = () => React.ReactNode;
53
71
  export type RegisterBlockMenuNested = BlockMenuNested & {
54
72
  component?: BlockMenuNestedComponent;
@@ -56,7 +74,8 @@ export type RegisterBlockMenuNested = BlockMenuNested & {
56
74
  };
57
75
  export type RegisterBlockMenuSection = BlockMenuSection & {
58
76
  component?: BlockMenuSectionComponent;
59
- rank: number;
77
+ parent?: Parent<BlockMenuNested>;
78
+ rank?: number;
60
79
  };
61
80
  export type RegisterBlockMenuItem = BlockMenuItem & {
62
81
  component?: BlockMenuItemComponent;
@@ -3,7 +3,7 @@ import type { WrappedComponentProps } from 'react-intl-next';
3
3
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
4
  import type { BlockMenuPlugin } from '../blockMenuPluginType';
5
5
  type Props = {
6
- api: ExtractInjectionAPI<BlockMenuPlugin>;
6
+ api: ExtractInjectionAPI<BlockMenuPlugin> | undefined;
7
7
  };
8
8
  export declare const MoveDownDropdownItem: React.FC<import("react-intl-next").WithIntlProps<Props & WrappedComponentProps>> & {
9
9
  WrappedComponent: React.ComponentType<Props & WrappedComponentProps>;
@@ -3,7 +3,7 @@ import type { WrappedComponentProps } from 'react-intl-next';
3
3
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
4
  import type { BlockMenuPlugin } from '../blockMenuPluginType';
5
5
  type Props = {
6
- api: ExtractInjectionAPI<BlockMenuPlugin>;
6
+ api: ExtractInjectionAPI<BlockMenuPlugin> | undefined;
7
7
  };
8
8
  export declare const MoveUpDropdownItem: React.FC<import("react-intl-next").WithIntlProps<Props & WrappedComponentProps>> & {
9
9
  WrappedComponent: React.ComponentType<Props & WrappedComponentProps>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-menu",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "BlockMenu plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -41,14 +41,15 @@
41
41
  "@atlaskit/editor-shared-styles": "^3.6.0",
42
42
  "@atlaskit/editor-tables": "^2.9.0",
43
43
  "@atlaskit/editor-toolbar": "^0.3.0",
44
- "@atlaskit/icon": "^28.0.0",
45
- "@atlaskit/icon-lab": "^5.6.0",
44
+ "@atlaskit/icon": "^28.1.0",
45
+ "@atlaskit/icon-lab": "^5.7.0",
46
+ "@atlaskit/platform-feature-flags": "^1.1.0",
46
47
  "@atlaskit/primitives": "^14.11.0",
47
48
  "@atlaskit/tokens": "^6.0.0",
48
49
  "@babel/runtime": "^7.0.0"
49
50
  },
50
51
  "peerDependencies": {
51
- "@atlaskit/editor-common": "^107.29.0",
52
+ "@atlaskit/editor-common": "^107.31.0",
52
53
  "react": "^18.2.0",
53
54
  "react-intl-next": "npm:react-intl@^5.18.1"
54
55
  },
@@ -87,5 +88,10 @@
87
88
  "import-no-extraneous-disable-for-examples-and-docs"
88
89
  ]
89
90
  }
91
+ },
92
+ "platform-feature-flags": {
93
+ "platform_editor_block_menu_format": {
94
+ "type": "boolean"
95
+ }
90
96
  }
91
97
  }