@atlaskit/editor-plugin-block-menu 5.2.11 → 5.2.12

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 (42) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cjs/ui/block-menu-renderer/BlockMenuComponent.js +37 -0
  3. package/dist/cjs/ui/block-menu-renderer/BlockMenuComponents.js +29 -0
  4. package/dist/cjs/ui/block-menu-renderer/BlockMenuRenderer.js +33 -0
  5. package/dist/cjs/ui/block-menu-renderer/fallbacks.js +32 -0
  6. package/dist/cjs/ui/block-menu-renderer/types.js +5 -0
  7. package/dist/cjs/ui/block-menu-renderer/utils.js +127 -0
  8. package/dist/cjs/ui/block-menu.js +7 -20
  9. package/dist/es2019/ui/block-menu-renderer/BlockMenuComponent.js +31 -0
  10. package/dist/es2019/ui/block-menu-renderer/BlockMenuComponents.js +21 -0
  11. package/dist/es2019/ui/block-menu-renderer/BlockMenuRenderer.js +24 -0
  12. package/dist/es2019/ui/block-menu-renderer/fallbacks.js +21 -0
  13. package/dist/es2019/ui/block-menu-renderer/types.js +1 -0
  14. package/dist/es2019/ui/block-menu-renderer/utils.js +93 -0
  15. package/dist/es2019/ui/block-menu.js +6 -13
  16. package/dist/esm/ui/block-menu-renderer/BlockMenuComponent.js +30 -0
  17. package/dist/esm/ui/block-menu-renderer/BlockMenuComponents.js +22 -0
  18. package/dist/esm/ui/block-menu-renderer/BlockMenuRenderer.js +25 -0
  19. package/dist/esm/ui/block-menu-renderer/fallbacks.js +25 -0
  20. package/dist/esm/ui/block-menu-renderer/types.js +1 -0
  21. package/dist/esm/ui/block-menu-renderer/utils.js +121 -0
  22. package/dist/esm/ui/block-menu.js +6 -19
  23. package/dist/types/blockMenuPluginType.d.ts +3 -2
  24. package/dist/types/ui/block-menu-renderer/BlockMenuComponent.d.ts +11 -0
  25. package/dist/types/ui/block-menu-renderer/BlockMenuComponents.d.ts +12 -0
  26. package/dist/types/ui/block-menu-renderer/BlockMenuRenderer.d.ts +12 -0
  27. package/dist/types/ui/block-menu-renderer/fallbacks.d.ts +2 -0
  28. package/dist/types/ui/block-menu-renderer/types.d.ts +27 -0
  29. package/dist/types/ui/block-menu-renderer/utils.d.ts +37 -0
  30. package/dist/types-ts4.5/blockMenuPluginType.d.ts +3 -2
  31. package/dist/types-ts4.5/ui/block-menu-renderer/BlockMenuComponent.d.ts +11 -0
  32. package/dist/types-ts4.5/ui/block-menu-renderer/BlockMenuComponents.d.ts +12 -0
  33. package/dist/types-ts4.5/ui/block-menu-renderer/BlockMenuRenderer.d.ts +12 -0
  34. package/dist/types-ts4.5/ui/block-menu-renderer/fallbacks.d.ts +2 -0
  35. package/dist/types-ts4.5/ui/block-menu-renderer/types.d.ts +27 -0
  36. package/dist/types-ts4.5/ui/block-menu-renderer/utils.d.ts +37 -0
  37. package/package.json +1 -1
  38. package/dist/cjs/ui/block-menu-renderer.js +0 -104
  39. package/dist/es2019/ui/block-menu-renderer.js +0 -83
  40. package/dist/esm/ui/block-menu-renderer.js +0 -95
  41. package/dist/types/ui/block-menu-renderer.d.ts +0 -18
  42. package/dist/types-ts4.5/ui/block-menu-renderer.d.ts +0 -18
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
3
+ import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
4
+ export var BLOCK_MENU_FALLBACKS = {
5
+ 'block-menu-nested': function blockMenuNested(_ref) {
6
+ var children = _ref.children;
7
+ return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
8
+ elemBefore: undefined,
9
+ elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
10
+ label: ""
11
+ }),
12
+ text: "Nested Menu",
13
+ enableMaxHeight: true,
14
+ shouldFitContainer: true
15
+ }, children);
16
+ },
17
+ 'block-menu-section': function blockMenuSection(_ref2) {
18
+ var children = _ref2.children;
19
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, children);
20
+ },
21
+ // eslint-disable-next-line @atlassian/i18n/no-literal-string-in-jsx
22
+ 'block-menu-item': function blockMenuItem() {
23
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItem, null, "Block Menu Item");
24
+ }
25
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,121 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
3
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
4
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
+ /**
6
+ * Type guard to check if a component has a parent
7
+ *
8
+ * @param component The block menu component to check
9
+ * @returns True if the component has a parent, false otherwise
10
+ */
11
+ var hasParent = function hasParent(component) {
12
+ return 'parent' in component && !!component.parent;
13
+ };
14
+
15
+ /**
16
+ * Type guard to identify top-level sections (sections without a parent)
17
+ *
18
+ * @param component The block menu component to check
19
+ * @returns True if the component is a top-level section, false otherwise
20
+ */
21
+ var isTopLevelSection = function isTopLevelSection(component) {
22
+ return component.type === 'block-menu-section' && !hasParent(component);
23
+ };
24
+
25
+ /**
26
+ * Gets all top-level sections (those without a parent) sorted by rank
27
+ *
28
+ * @param components All registered block menu components
29
+ * @returns Sorted array of top-level sections
30
+ */
31
+ export var getSortedTopLevelSections = function getSortedTopLevelSections(components) {
32
+ return components.filter(isTopLevelSection).sort(function (a, b) {
33
+ return (a.rank || 0) - (b.rank || 0);
34
+ });
35
+ };
36
+
37
+ /**
38
+ * Generates a unique key from a key and type
39
+ * Used to lookup children in the childrenMap
40
+ *
41
+ * @param key The component's key
42
+ * @param type The component's type
43
+ * @returns A unique string key combining type and key
44
+ */
45
+ export var getChildrenMapKey = function getChildrenMapKey(key, type) {
46
+ return "".concat(type, ":").concat(key);
47
+ };
48
+
49
+ /**
50
+ * Builds a map of parent keys to their sorted children
51
+ * This enables efficient hierarchical rendering of the menu structure
52
+ *
53
+ * @param components All registered block menu components
54
+ * @returns Map where keys are parent identifiers and values are sorted child components
55
+ */
56
+ export var buildChildrenMap = function buildChildrenMap(components) {
57
+ var childrenMap = new Map();
58
+ var _iterator = _createForOfIteratorHelper(components),
59
+ _step;
60
+ try {
61
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
62
+ var component = _step.value;
63
+ // Only components with parents can be children
64
+ if ('parent' in component && !!component.parent) {
65
+ var childrenMapKey = getChildrenMapKey(component.parent.key, component.parent.type);
66
+ var existing = childrenMap.get(childrenMapKey) || [];
67
+ existing.push(component);
68
+ childrenMap.set(childrenMapKey, existing);
69
+ }
70
+ }
71
+
72
+ // Sort children by their rank within their parent
73
+ } catch (err) {
74
+ _iterator.e(err);
75
+ } finally {
76
+ _iterator.f();
77
+ }
78
+ var _iterator2 = _createForOfIteratorHelper(childrenMap.entries()),
79
+ _step2;
80
+ try {
81
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
82
+ var _step2$value = _slicedToArray(_step2.value, 2),
83
+ children = _step2$value[1];
84
+ children.sort(function (a, b) {
85
+ var rankA = hasParent(a) ? a.parent.rank || 0 : 0;
86
+ var rankB = hasParent(b) ? b.parent.rank || 0 : 0;
87
+ return rankA - rankB;
88
+ });
89
+ }
90
+ } catch (err) {
91
+ _iterator2.e(err);
92
+ } finally {
93
+ _iterator2.f();
94
+ }
95
+ return childrenMap;
96
+ };
97
+
98
+ /**
99
+ * Determines whether a component will render based on its type and children
100
+ *
101
+ * Rules:
102
+ * - An item will not render if has a component that returns null
103
+ * - A nested menu will render if it has at least one registered child component
104
+ * - A section will render if it has at least one registered child component that will render
105
+ *
106
+ * NOTE: This requires invoking each item's component function to check for null return
107
+ */
108
+ var _willComponentRender = function willComponentRender(registeredComponent, childrenMap) {
109
+ if (registeredComponent.type === 'block-menu-item') {
110
+ return registeredComponent.component ? registeredComponent.component() !== null : true;
111
+ }
112
+ var childrenMapKey = getChildrenMapKey(registeredComponent.key, registeredComponent.type);
113
+ var registeredComponents = childrenMap.get(childrenMapKey) || [];
114
+ if (registeredComponent.type === 'block-menu-nested') {
115
+ return registeredComponents.length > 0;
116
+ }
117
+ return registeredComponents.some(function (childComponent) {
118
+ return _willComponentRender(childComponent, childrenMap);
119
+ });
120
+ };
121
+ export { _willComponentRender as willComponentRender };
@@ -11,15 +11,15 @@ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'
11
11
  import { deleteSelectedRange } from '@atlaskit/editor-common/selection';
12
12
  import { DRAG_HANDLE_SELECTOR, DRAG_HANDLE_WIDTH } from '@atlaskit/editor-common/styles';
13
13
  import { Popup } from '@atlaskit/editor-common/ui';
14
+ import { ArrowKeyNavigationProvider, ArrowKeyNavigationType } from '@atlaskit/editor-common/ui-menu';
14
15
  import { OutsideClickTargetRefContext, withReactEditorViewOuterListeners } from '@atlaskit/editor-common/ui-react';
15
16
  import { akEditorFloatingOverlapPanelZIndex } from '@atlaskit/editor-shared-styles';
16
- import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
17
17
  import { fg } from '@atlaskit/platform-feature-flags';
18
18
  import { conditionalHooksFactory } from '@atlaskit/platform-feature-flags-react';
19
19
  import { Box } from '@atlaskit/primitives/compiled';
20
20
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
21
21
  import { useBlockMenu } from './block-menu-provider';
22
- import { BlockMenuRenderer } from './block-menu-renderer';
22
+ import { BlockMenuRenderer } from './block-menu-renderer/BlockMenuRenderer';
23
23
  var styles = {
24
24
  base: "_2rko12b0 _bfhk1bhr _16qs130s",
25
25
  emptyMenuSectionStyles: "_1cc0glyw _1k2yglyw"
@@ -111,24 +111,11 @@ var BlockMenuContent = function BlockMenuContent(_ref3) {
111
111
  testId: "editor-block-menu",
112
112
  ref: ref,
113
113
  xcss: cx(styles.base, editorExperiment('platform_synced_block', true) && styles.emptyMenuSectionStyles)
114
+ }, /*#__PURE__*/React.createElement(ArrowKeyNavigationProvider, {
115
+ type: ArrowKeyNavigationType.MENU
114
116
  }, /*#__PURE__*/React.createElement(BlockMenuRenderer, {
115
- components: blockMenuComponents || [],
116
- fallbacks: {
117
- nestedMenu: function nestedMenu() {
118
- return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
119
- elemBefore: undefined,
120
- elemAfter: undefined
121
- }, /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, /*#__PURE__*/React.createElement(ToolbarDropdownItem, null, "Block Menu Item")));
122
- },
123
- section: function section() {
124
- return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, null, /*#__PURE__*/React.createElement(ToolbarDropdownItem, null, "Block Menu Item"));
125
- },
126
- // eslint-disable-next-line @atlassian/i18n/no-literal-string-in-jsx
127
- item: function item() {
128
- return /*#__PURE__*/React.createElement(ToolbarDropdownItem, null, "Block Menu Item");
129
- }
130
- }
131
- }));
117
+ allRegisteredComponents: blockMenuComponents || []
118
+ })));
132
119
  };
133
120
  var BlockMenu = function BlockMenu(_ref4) {
134
121
  var _editorView$dom, _ref5;
@@ -1,4 +1,4 @@
1
- import type { NextEditorPlugin, OptionalPlugin, EditorCommand } from '@atlaskit/editor-common/types';
1
+ import type { EditorCommand, NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/types';
2
2
  import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
3
3
  import type { BlockControlsPlugin } from '@atlaskit/editor-plugin-block-controls';
4
4
  import type { DecorationsPlugin } from '@atlaskit/editor-plugin-decorations';
@@ -84,7 +84,7 @@ type BlockMenuNested = {
84
84
  key: string;
85
85
  type: 'block-menu-nested';
86
86
  };
87
- export type BlockMenuNestedComponent = (props?: {
87
+ export type BlockMenuNestedComponent = (props: {
88
88
  children: React.ReactNode;
89
89
  }) => React.ReactNode;
90
90
  export type BlockMenuSectionComponent = (props: {
@@ -108,4 +108,5 @@ export type RegisterBlockMenuItem = BlockMenuItem & {
108
108
  parent: Parent<BlockMenuSection>;
109
109
  };
110
110
  export type RegisterBlockMenuComponent = RegisterBlockMenuNested | RegisterBlockMenuSection | RegisterBlockMenuItem;
111
+ export type RegisterBlockMenuComponentType = RegisterBlockMenuComponent['type'];
111
112
  export {};
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { RegisterBlockMenuComponent } from '../../blockMenuPluginType';
3
+ import type { BlockMenuRenderingContext } from './types';
4
+ type BlockMenuComponentProps = BlockMenuRenderingContext & {
5
+ registeredComponent: RegisterBlockMenuComponent;
6
+ };
7
+ /**
8
+ * Renders the given registered component based on its type
9
+ */
10
+ export declare const BlockMenuComponent: ({ registeredComponent, childrenMap, fallbacks, }: BlockMenuComponentProps) => React.JSX.Element | null;
11
+ export {};
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { RegisterBlockMenuComponent } from '../../blockMenuPluginType';
3
+ import type { BlockMenuRenderingContext } from './types';
4
+ type BlockMenuComponentsProps = BlockMenuRenderingContext & {
5
+ registeredComponents?: RegisterBlockMenuComponent[];
6
+ };
7
+ /**
8
+ * Renders the given registered components
9
+ * Returns null if no components are rendered
10
+ */
11
+ export declare const BlockMenuComponents: ({ registeredComponents, childrenMap, fallbacks, }: BlockMenuComponentsProps) => React.JSX.Element | null;
12
+ export {};
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { RegisterBlockMenuComponent } from '../../blockMenuPluginType';
3
+ import type { BlockMenuFallbacks } from './types';
4
+ type BlockMenuProps = {
5
+ allRegisteredComponents: RegisterBlockMenuComponent[];
6
+ fallbacks?: BlockMenuFallbacks;
7
+ };
8
+ /**
9
+ * BlockMenuRenderer orchestrates the rendering of the entire block menu hierarchy
10
+ */
11
+ export declare const BlockMenuRenderer: ({ allRegisteredComponents, fallbacks, }: BlockMenuProps) => React.JSX.Element;
12
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { BlockMenuFallbacks } from './types';
2
+ export declare const BLOCK_MENU_FALLBACKS: BlockMenuFallbacks;
@@ -0,0 +1,27 @@
1
+ import type { BlockMenuItemComponent, BlockMenuNestedComponent, BlockMenuSectionComponent, RegisterBlockMenuComponent } from '../../blockMenuPluginType';
2
+ /**
3
+ * Fallback components used as defaults when specific components aren't provided
4
+ */
5
+ export type BlockMenuFallbacks = {
6
+ 'block-menu-item': BlockMenuItemComponent;
7
+ 'block-menu-nested': BlockMenuNestedComponent;
8
+ 'block-menu-section': BlockMenuSectionComponent;
9
+ };
10
+ /**
11
+ * Map of parent keys to their sorted children components
12
+ * Used to efficiently organize and render hierarchical menu structures
13
+ */
14
+ export type ChildrenMap = Map<string, RegisterBlockMenuComponent[]>;
15
+ /**
16
+ * Props shared across multiple block menu rendering components
17
+ */
18
+ export type BlockMenuRenderingContext = {
19
+ /**
20
+ * Lookup map for child components organized by parent key
21
+ */
22
+ childrenMap: ChildrenMap;
23
+ /**
24
+ * Fallback components when specific components aren't registered
25
+ */
26
+ fallbacks: BlockMenuFallbacks;
27
+ };
@@ -0,0 +1,37 @@
1
+ import type { RegisterBlockMenuComponent, RegisterBlockMenuComponentType, RegisterBlockMenuSection } from '../../blockMenuPluginType';
2
+ import type { ChildrenMap } from './types';
3
+ /**
4
+ * Gets all top-level sections (those without a parent) sorted by rank
5
+ *
6
+ * @param components All registered block menu components
7
+ * @returns Sorted array of top-level sections
8
+ */
9
+ export declare const getSortedTopLevelSections: (components: RegisterBlockMenuComponent[]) => RegisterBlockMenuSection[];
10
+ /**
11
+ * Generates a unique key from a key and type
12
+ * Used to lookup children in the childrenMap
13
+ *
14
+ * @param key The component's key
15
+ * @param type The component's type
16
+ * @returns A unique string key combining type and key
17
+ */
18
+ export declare const getChildrenMapKey: (key: string, type: Omit<RegisterBlockMenuComponentType, "block-menu-item">) => string;
19
+ /**
20
+ * Builds a map of parent keys to their sorted children
21
+ * This enables efficient hierarchical rendering of the menu structure
22
+ *
23
+ * @param components All registered block menu components
24
+ * @returns Map where keys are parent identifiers and values are sorted child components
25
+ */
26
+ export declare const buildChildrenMap: (components: RegisterBlockMenuComponent[]) => ChildrenMap;
27
+ /**
28
+ * Determines whether a component will render based on its type and children
29
+ *
30
+ * Rules:
31
+ * - An item will not render if has a component that returns null
32
+ * - A nested menu will render if it has at least one registered child component
33
+ * - A section will render if it has at least one registered child component that will render
34
+ *
35
+ * NOTE: This requires invoking each item's component function to check for null return
36
+ */
37
+ export declare const willComponentRender: (registeredComponent: RegisterBlockMenuComponent, childrenMap: ChildrenMap) => boolean;
@@ -1,4 +1,4 @@
1
- import type { NextEditorPlugin, OptionalPlugin, EditorCommand } from '@atlaskit/editor-common/types';
1
+ import type { EditorCommand, NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/types';
2
2
  import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
3
3
  import type { BlockControlsPlugin } from '@atlaskit/editor-plugin-block-controls';
4
4
  import type { DecorationsPlugin } from '@atlaskit/editor-plugin-decorations';
@@ -84,7 +84,7 @@ type BlockMenuNested = {
84
84
  key: string;
85
85
  type: 'block-menu-nested';
86
86
  };
87
- export type BlockMenuNestedComponent = (props?: {
87
+ export type BlockMenuNestedComponent = (props: {
88
88
  children: React.ReactNode;
89
89
  }) => React.ReactNode;
90
90
  export type BlockMenuSectionComponent = (props: {
@@ -108,4 +108,5 @@ export type RegisterBlockMenuItem = BlockMenuItem & {
108
108
  parent: Parent<BlockMenuSection>;
109
109
  };
110
110
  export type RegisterBlockMenuComponent = RegisterBlockMenuNested | RegisterBlockMenuSection | RegisterBlockMenuItem;
111
+ export type RegisterBlockMenuComponentType = RegisterBlockMenuComponent['type'];
111
112
  export {};
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { RegisterBlockMenuComponent } from '../../blockMenuPluginType';
3
+ import type { BlockMenuRenderingContext } from './types';
4
+ type BlockMenuComponentProps = BlockMenuRenderingContext & {
5
+ registeredComponent: RegisterBlockMenuComponent;
6
+ };
7
+ /**
8
+ * Renders the given registered component based on its type
9
+ */
10
+ export declare const BlockMenuComponent: ({ registeredComponent, childrenMap, fallbacks, }: BlockMenuComponentProps) => React.JSX.Element | null;
11
+ export {};
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { RegisterBlockMenuComponent } from '../../blockMenuPluginType';
3
+ import type { BlockMenuRenderingContext } from './types';
4
+ type BlockMenuComponentsProps = BlockMenuRenderingContext & {
5
+ registeredComponents?: RegisterBlockMenuComponent[];
6
+ };
7
+ /**
8
+ * Renders the given registered components
9
+ * Returns null if no components are rendered
10
+ */
11
+ export declare const BlockMenuComponents: ({ registeredComponents, childrenMap, fallbacks, }: BlockMenuComponentsProps) => React.JSX.Element | null;
12
+ export {};
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { RegisterBlockMenuComponent } from '../../blockMenuPluginType';
3
+ import type { BlockMenuFallbacks } from './types';
4
+ type BlockMenuProps = {
5
+ allRegisteredComponents: RegisterBlockMenuComponent[];
6
+ fallbacks?: BlockMenuFallbacks;
7
+ };
8
+ /**
9
+ * BlockMenuRenderer orchestrates the rendering of the entire block menu hierarchy
10
+ */
11
+ export declare const BlockMenuRenderer: ({ allRegisteredComponents, fallbacks, }: BlockMenuProps) => React.JSX.Element;
12
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { BlockMenuFallbacks } from './types';
2
+ export declare const BLOCK_MENU_FALLBACKS: BlockMenuFallbacks;
@@ -0,0 +1,27 @@
1
+ import type { BlockMenuItemComponent, BlockMenuNestedComponent, BlockMenuSectionComponent, RegisterBlockMenuComponent } from '../../blockMenuPluginType';
2
+ /**
3
+ * Fallback components used as defaults when specific components aren't provided
4
+ */
5
+ export type BlockMenuFallbacks = {
6
+ 'block-menu-item': BlockMenuItemComponent;
7
+ 'block-menu-nested': BlockMenuNestedComponent;
8
+ 'block-menu-section': BlockMenuSectionComponent;
9
+ };
10
+ /**
11
+ * Map of parent keys to their sorted children components
12
+ * Used to efficiently organize and render hierarchical menu structures
13
+ */
14
+ export type ChildrenMap = Map<string, RegisterBlockMenuComponent[]>;
15
+ /**
16
+ * Props shared across multiple block menu rendering components
17
+ */
18
+ export type BlockMenuRenderingContext = {
19
+ /**
20
+ * Lookup map for child components organized by parent key
21
+ */
22
+ childrenMap: ChildrenMap;
23
+ /**
24
+ * Fallback components when specific components aren't registered
25
+ */
26
+ fallbacks: BlockMenuFallbacks;
27
+ };
@@ -0,0 +1,37 @@
1
+ import type { RegisterBlockMenuComponent, RegisterBlockMenuComponentType, RegisterBlockMenuSection } from '../../blockMenuPluginType';
2
+ import type { ChildrenMap } from './types';
3
+ /**
4
+ * Gets all top-level sections (those without a parent) sorted by rank
5
+ *
6
+ * @param components All registered block menu components
7
+ * @returns Sorted array of top-level sections
8
+ */
9
+ export declare const getSortedTopLevelSections: (components: RegisterBlockMenuComponent[]) => RegisterBlockMenuSection[];
10
+ /**
11
+ * Generates a unique key from a key and type
12
+ * Used to lookup children in the childrenMap
13
+ *
14
+ * @param key The component's key
15
+ * @param type The component's type
16
+ * @returns A unique string key combining type and key
17
+ */
18
+ export declare const getChildrenMapKey: (key: string, type: Omit<RegisterBlockMenuComponentType, "block-menu-item">) => string;
19
+ /**
20
+ * Builds a map of parent keys to their sorted children
21
+ * This enables efficient hierarchical rendering of the menu structure
22
+ *
23
+ * @param components All registered block menu components
24
+ * @returns Map where keys are parent identifiers and values are sorted child components
25
+ */
26
+ export declare const buildChildrenMap: (components: RegisterBlockMenuComponent[]) => ChildrenMap;
27
+ /**
28
+ * Determines whether a component will render based on its type and children
29
+ *
30
+ * Rules:
31
+ * - An item will not render if has a component that returns null
32
+ * - A nested menu will render if it has at least one registered child component
33
+ * - A section will render if it has at least one registered child component that will render
34
+ *
35
+ * NOTE: This requires invoking each item's component function to check for null return
36
+ */
37
+ export declare const willComponentRender: (registeredComponent: RegisterBlockMenuComponent, childrenMap: ChildrenMap) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-menu",
3
- "version": "5.2.11",
3
+ "version": "5.2.12",
4
4
  "description": "BlockMenu plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -1,104 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- var _typeof = require("@babel/runtime/helpers/typeof");
5
- Object.defineProperty(exports, "__esModule", {
6
- value: true
7
- });
8
- exports.BlockMenuRenderer = void 0;
9
- var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
10
- var _react = _interopRequireWildcard(require("react"));
11
- var _uiMenu = require("@atlaskit/editor-common/ui-menu");
12
- 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); }
13
- var NoOp = function NoOp() {
14
- return null;
15
- };
16
- var isNonNestedMenuSection = function isNonNestedMenuSection(component) {
17
- return component.type === 'block-menu-section' && !('parent' in component);
18
- };
19
- var isMenuItem = function isMenuItem(component) {
20
- return component.type === 'block-menu-item';
21
- };
22
- var isNestedMenu = function isNestedMenu(component) {
23
- return component.type === 'block-menu-nested';
24
- };
25
- var isNestedMenuSection = function isNestedMenuSection(component) {
26
- return 'parent' in component && component.parent !== undefined && component.parent.type === 'block-menu-nested';
27
- };
28
- var getSortedChildren = function getSortedChildren(components, parentKey) {
29
- return components.filter(function (component) {
30
- return 'parent' in component && component.parent !== undefined && component.parent.key === parentKey;
31
- }).sort(function (a, b) {
32
- return (a.parent.rank || 0) - (b.parent.rank || 0);
33
- });
34
- };
35
- var getSortedNestedSections = function getSortedNestedSections(components, parentKey) {
36
- var nestedMenuSections = components.filter(isNestedMenuSection);
37
- var nestedMenuSectionsWithParent = nestedMenuSections.filter(function (section) {
38
- return section.parent !== undefined;
39
- });
40
- return getSortedChildren(nestedMenuSectionsWithParent, parentKey);
41
- };
42
- var getSortedNonNestedSections = function getSortedNonNestedSections(components) {
43
- return components.filter(isNonNestedMenuSection).sort(function (a, b) {
44
- return (a.rank || 0) - (b.rank || 0);
45
- });
46
- };
47
- var BlockMenuRenderer = exports.BlockMenuRenderer = function BlockMenuRenderer(_ref) {
48
- var components = _ref.components,
49
- fallbacks = _ref.fallbacks;
50
- var menuSections = getSortedNonNestedSections(components);
51
- var menuItems = components.filter(isMenuItem);
52
- var nestedMenus = components.filter(isNestedMenu);
53
- var renderMenu = function renderMenu() {
54
- return /*#__PURE__*/_react.default.createElement(_react.Fragment, null, menuSections.map(function (section) {
55
- // Get all items for the current section, including nested menus, and sort them by rank
56
- var currentSectionItemsSorted = getSortedChildren([].concat((0, _toConsumableArray2.default)(menuItems), (0, _toConsumableArray2.default)(nestedMenus)), section.key);
57
- if (currentSectionItemsSorted.length === 0) {
58
- return null;
59
- }
60
-
61
- // iterate over the current section items, if it is nested menu, get their children, sort them
62
- // if they are menu items, just render as they are sorted above
63
- var getChildrenWithNestedItems = function getChildrenWithNestedItems(items) {
64
- return items.map(function (item) {
65
- if (isNestedMenu(item)) {
66
- var sortedNestedSections = getSortedNestedSections(components, item.key);
67
- var sections = sortedNestedSections.map(function (section) {
68
- var sortedNestedMenuItems = getSortedChildren(menuItems, section.key);
69
- if (sortedNestedMenuItems.length === 0) {
70
- return null;
71
- }
72
- var NestedSection = section.component || fallbacks.section || NoOp;
73
- return /*#__PURE__*/_react.default.createElement(NestedSection, {
74
- key: section.key
75
- }, sortedNestedMenuItems.map(function (nestedItem) {
76
- var NestedMenuItemComponent = nestedItem.component || fallbacks.item || NoOp;
77
- return /*#__PURE__*/_react.default.createElement(NestedMenuItemComponent, {
78
- key: nestedItem.key
79
- });
80
- }));
81
- });
82
- var NestedMenuComponent = item.component || fallbacks.nestedMenu || NoOp;
83
- return /*#__PURE__*/_react.default.createElement(NestedMenuComponent, {
84
- key: item.key
85
- }, sections);
86
- } else {
87
- var ItemComponent = item.component || fallbacks.item || NoOp;
88
- return /*#__PURE__*/_react.default.createElement(ItemComponent, {
89
- key: item.key
90
- });
91
- }
92
- });
93
- };
94
- var children = getChildrenWithNestedItems(currentSectionItemsSorted);
95
- var SectionComponent = section.component || fallbacks.section || NoOp;
96
- return /*#__PURE__*/_react.default.createElement(SectionComponent, {
97
- key: section.key
98
- }, children);
99
- }));
100
- };
101
- return /*#__PURE__*/_react.default.createElement(_uiMenu.ArrowKeyNavigationProvider, {
102
- type: _uiMenu.ArrowKeyNavigationType.MENU
103
- }, renderMenu());
104
- };