@atlaskit/editor-plugin-block-menu 0.0.12 → 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,14 @@
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
+
3
12
  ## 0.0.12
4
13
 
5
14
  ### 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,8 +10,7 @@ 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");
@@ -46,23 +45,64 @@ var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(a
46
45
  }
47
46
  }];
48
47
  };
49
- var getBlockMenuComponents = exports.getBlockMenuComponents = function getBlockMenuComponents(_ref) {
50
- var api = _ref.api,
51
- config = _ref.config;
48
+ var getFormatMenuComponents = function getFormatMenuComponents() {
52
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
+ }, {
53
73
  type: 'block-menu-section',
54
- 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',
55
95
  rank: 100,
56
- component: function component(_ref2) {
57
- var children = _ref2.children;
96
+ component: function component(_ref4) {
97
+ var children = _ref4.children;
58
98
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, null, children);
59
99
  }
60
100
  }, {
61
101
  type: 'block-menu-section',
62
102
  key: 'block-menu-section-copy',
63
103
  rank: 200,
64
- component: function component(_ref3) {
65
- var children = _ref3.children;
104
+ component: function component(_ref5) {
105
+ var children = _ref5.children;
66
106
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, {
67
107
  hasSeparator: true
68
108
  }, children);
@@ -98,8 +138,8 @@ var getBlockMenuComponents = exports.getBlockMenuComponents = function getBlockM
98
138
  type: 'block-menu-section',
99
139
  key: 'block-menu-section-move-up-down',
100
140
  rank: 300,
101
- component: function component(_ref4) {
102
- var children = _ref4.children;
141
+ component: function component(_ref6) {
142
+ var children = _ref6.children;
103
143
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, {
104
144
  hasSeparator: true
105
145
  }, children);
@@ -108,40 +148,13 @@ var getBlockMenuComponents = exports.getBlockMenuComponents = function getBlockM
108
148
  type: 'block-menu-section',
109
149
  key: 'block-menu-section-delete',
110
150
  rank: 400,
111
- component: function component(_ref5) {
112
- var children = _ref5.children;
151
+ component: function component(_ref7) {
152
+ var children = _ref7.children;
113
153
  return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, {
114
154
  hasSeparator: true
115
155
  }, children);
116
156
  }
117
- }, {
118
- type: 'block-menu-nested',
119
- key: 'nested-menu',
120
- parent: {
121
- type: 'block-menu-section',
122
- key: 'block-menu-section-format',
123
- rank: 100
124
- },
125
- component: function component() {
126
- return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarNestedDropdownMenu, {
127
- text: "Format",
128
- elemBefore: /*#__PURE__*/_react.default.createElement(_changes.default, {
129
- label: ""
130
- }),
131
- elemAfter: /*#__PURE__*/_react.default.createElement(_chevronRight.default, {
132
- label: 'example nested menu'
133
- })
134
- }, /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, null, /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
135
- elemBefore: /*#__PURE__*/_react.default.createElement(_task.default, {
136
- label: ""
137
- })
138
- }, "Action item"), /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
139
- elemBefore: /*#__PURE__*/_react.default.createElement(_listBulleted.default, {
140
- label: ""
141
- })
142
- }, "Bullet list")));
143
- }
144
- }].concat((0, _toConsumableArray2.default)(getMoveUpMoveDownMenuComponents(api)), [{
157
+ }], (0, _toConsumableArray2.default)(getMoveUpMoveDownMenuComponents(api)), [{
145
158
  type: 'block-menu-item',
146
159
  key: 'block-menu-item-delete',
147
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,9 +1,8 @@
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';
@@ -34,13 +33,54 @@ const getMoveUpMoveDownMenuComponents = api => {
34
33
  })
35
34
  }];
36
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
+ };
37
77
  export const getBlockMenuComponents = ({
38
78
  api,
39
79
  config
40
80
  }) => {
41
- return [{
81
+ return [...(fg('platform_editor_block_menu_format') ? getFormatMenuComponents() : []), {
42
82
  type: 'block-menu-section',
43
- key: 'block-menu-section-format',
83
+ key: 'block-menu-section-primary',
44
84
  rank: 100,
45
85
  component: ({
46
86
  children
@@ -105,33 +145,6 @@ export const getBlockMenuComponents = ({
105
145
  hasSeparator: true
106
146
  }, children);
107
147
  }
108
- }, {
109
- type: 'block-menu-nested',
110
- key: 'nested-menu',
111
- parent: {
112
- type: 'block-menu-section',
113
- key: 'block-menu-section-format',
114
- rank: 100
115
- },
116
- component: () => {
117
- return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
118
- text: "Format",
119
- elemBefore: /*#__PURE__*/React.createElement(ChangesIcon, {
120
- label: ""
121
- }),
122
- elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
123
- label: 'example nested menu'
124
- })
125
- }, /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
126
- elemBefore: /*#__PURE__*/React.createElement(TaskIcon, {
127
- label: ""
128
- })
129
- }, "Action item"), /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
130
- elemBefore: /*#__PURE__*/React.createElement(ListBulletedIcon, {
131
- label: ""
132
- })
133
- }, "Bullet list")));
134
- }
135
148
  }, ...getMoveUpMoveDownMenuComponents(api), {
136
149
  type: 'block-menu-item',
137
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,10 +1,9 @@
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';
@@ -39,23 +38,64 @@ var getMoveUpMoveDownMenuComponents = function getMoveUpMoveDownMenuComponents(a
39
38
  }
40
39
  }];
41
40
  };
42
- export var getBlockMenuComponents = function getBlockMenuComponents(_ref) {
43
- var api = _ref.api,
44
- config = _ref.config;
41
+ var getFormatMenuComponents = function getFormatMenuComponents() {
45
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
+ }, {
46
66
  type: 'block-menu-section',
47
- 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',
48
88
  rank: 100,
49
- component: function component(_ref2) {
50
- var children = _ref2.children;
89
+ component: function component(_ref4) {
90
+ var children = _ref4.children;
51
91
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
52
92
  }
53
93
  }, {
54
94
  type: 'block-menu-section',
55
95
  key: 'block-menu-section-copy',
56
96
  rank: 200,
57
- component: function component(_ref3) {
58
- var children = _ref3.children;
97
+ component: function component(_ref5) {
98
+ var children = _ref5.children;
59
99
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
60
100
  hasSeparator: true
61
101
  }, children);
@@ -91,8 +131,8 @@ export var getBlockMenuComponents = function getBlockMenuComponents(_ref) {
91
131
  type: 'block-menu-section',
92
132
  key: 'block-menu-section-move-up-down',
93
133
  rank: 300,
94
- component: function component(_ref4) {
95
- var children = _ref4.children;
134
+ component: function component(_ref6) {
135
+ var children = _ref6.children;
96
136
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
97
137
  hasSeparator: true
98
138
  }, children);
@@ -101,40 +141,13 @@ export var getBlockMenuComponents = function getBlockMenuComponents(_ref) {
101
141
  type: 'block-menu-section',
102
142
  key: 'block-menu-section-delete',
103
143
  rank: 400,
104
- component: function component(_ref5) {
105
- var children = _ref5.children;
144
+ component: function component(_ref7) {
145
+ var children = _ref7.children;
106
146
  return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
107
147
  hasSeparator: true
108
148
  }, children);
109
149
  }
110
- }, {
111
- type: 'block-menu-nested',
112
- key: 'nested-menu',
113
- parent: {
114
- type: 'block-menu-section',
115
- key: 'block-menu-section-format',
116
- rank: 100
117
- },
118
- component: function component() {
119
- return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
120
- text: "Format",
121
- elemBefore: /*#__PURE__*/React.createElement(ChangesIcon, {
122
- label: ""
123
- }),
124
- elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
125
- label: 'example nested menu'
126
- })
127
- }, /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
128
- elemBefore: /*#__PURE__*/React.createElement(TaskIcon, {
129
- label: ""
130
- })
131
- }, "Action item"), /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
132
- elemBefore: /*#__PURE__*/React.createElement(ListBulletedIcon, {
133
- label: ""
134
- })
135
- }, "Bullet list")));
136
- }
137
- }].concat(_toConsumableArray(getMoveUpMoveDownMenuComponents(api)), [{
150
+ }], _toConsumableArray(getMoveUpMoveDownMenuComponents(api)), [{
138
151
  type: 'block-menu-item',
139
152
  key: 'block-menu-item-delete',
140
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;
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-menu",
3
- "version": "0.0.12",
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,8 +41,9 @@
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"
@@ -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
  }