@atlaskit/editor-plugin-selection-extension 3.4.0 → 3.4.2

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 (31) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/selectionExtensionPlugin.js +75 -35
  3. package/dist/cjs/ui/LegacyToolbarComponent.js +120 -0
  4. package/dist/cjs/ui/extensions.js +60 -0
  5. package/dist/cjs/ui/getBoundingBoxFromSelection.js +7 -0
  6. package/dist/cjs/ui/selectionToolbar.js +32 -5
  7. package/dist/es2019/selectionExtensionPlugin.js +63 -27
  8. package/dist/es2019/ui/LegacyToolbarComponent.js +109 -0
  9. package/dist/es2019/ui/extensions.js +54 -0
  10. package/dist/es2019/ui/getBoundingBoxFromSelection.js +7 -1
  11. package/dist/es2019/ui/selectionToolbar.js +38 -14
  12. package/dist/esm/selectionExtensionPlugin.js +75 -35
  13. package/dist/esm/ui/LegacyToolbarComponent.js +111 -0
  14. package/dist/esm/ui/extensions.js +54 -0
  15. package/dist/esm/ui/getBoundingBoxFromSelection.js +7 -0
  16. package/dist/esm/ui/selectionToolbar.js +31 -5
  17. package/dist/types/index.d.ts +1 -1
  18. package/dist/types/selectionExtensionPluginType.d.ts +4 -0
  19. package/dist/types/types/index.d.ts +41 -1
  20. package/dist/types/ui/LegacyToolbarComponent.d.ts +16 -0
  21. package/dist/types/ui/extensions.d.ts +27 -0
  22. package/dist/types/ui/getBoundingBoxFromSelection.d.ts +3 -2
  23. package/dist/types/ui/selectionToolbar.d.ts +7 -17
  24. package/dist/types-ts4.5/index.d.ts +1 -1
  25. package/dist/types-ts4.5/selectionExtensionPluginType.d.ts +4 -0
  26. package/dist/types-ts4.5/types/index.d.ts +41 -1
  27. package/dist/types-ts4.5/ui/LegacyToolbarComponent.d.ts +16 -0
  28. package/dist/types-ts4.5/ui/extensions.d.ts +27 -0
  29. package/dist/types-ts4.5/ui/getBoundingBoxFromSelection.d.ts +3 -2
  30. package/dist/types-ts4.5/ui/selectionToolbar.d.ts +7 -17
  31. package/package.json +10 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @atlaskit/editor-plugin-selection-extension
2
2
 
3
+ ## 3.4.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`373e833d95d52`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/373e833d95d52) -
8
+ [ux] COMMIT-19456:Fix forge app coords bug
9
+ - Updated dependencies
10
+
11
+ ## 3.4.1
12
+
13
+ ### Patch Changes
14
+
15
+ - [#192343](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/192343)
16
+ [`9cb0878241016`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/9cb0878241016) -
17
+ ED-28736 more extensible selection extensions API
18
+ - Updated dependencies
19
+
3
20
  ## 3.4.0
4
21
 
5
22
  ### Minor Changes
@@ -9,6 +9,7 @@ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers
9
9
  var _react = _interopRequireDefault(require("react"));
10
10
  var _messages = require("@atlaskit/editor-common/messages");
11
11
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
12
+ var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
12
13
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
13
14
  var _actions = require("./pm-plugins/actions");
14
15
  var _insertAdfAtEndOfDoc2 = require("./pm-plugins/actions/insertAdfAtEndOfDoc");
@@ -17,7 +18,9 @@ var _main = require("./pm-plugins/main");
17
18
  var _utils = require("./pm-plugins/utils");
18
19
  var _types = require("./types");
19
20
  var _SelectionExtensionComponentWrapper = require("./ui/extension/SelectionExtensionComponentWrapper");
21
+ var _extensions = require("./ui/extensions");
20
22
  var _getBoundingBoxFromSelection = require("./ui/getBoundingBoxFromSelection");
23
+ var _LegacyToolbarComponent = require("./ui/LegacyToolbarComponent");
21
24
  var _selectionToolbar2 = require("./ui/selectionToolbar");
22
25
  var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selectionExtensionPlugin(_ref) {
23
26
  var api = _ref.api,
@@ -27,6 +30,30 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
27
30
  };
28
31
  var cachedSelection;
29
32
  var cachedOverflowMenuOptions;
33
+ var _ref2 = config || {},
34
+ _ref2$extensionList = _ref2.extensionList,
35
+ extensionList = _ref2$extensionList === void 0 ? [] : _ref2$extensionList,
36
+ _ref2$extensions = _ref2.extensions,
37
+ extensions = _ref2$extensions === void 0 ? {} : _ref2$extensions;
38
+ var _ref3 = extensions || {},
39
+ _ref3$firstParty = _ref3.firstParty,
40
+ firstParty = _ref3$firstParty === void 0 ? [] : _ref3$firstParty,
41
+ _ref3$external = _ref3.external,
42
+ external = _ref3$external === void 0 ? [] : _ref3$external;
43
+ if ((0, _platformFeatureFlags.fg)('platform_editor_selection_extension_api_v2')) {
44
+ var primaryToolbarItemExtensions = (0, _extensions.getToolbarItemExtensions)(extensionList, 'primaryToolbar');
45
+ if (primaryToolbarItemExtensions !== null && primaryToolbarItemExtensions !== void 0 && primaryToolbarItemExtensions.length) {
46
+ var _api$primaryToolbar;
47
+ api === null || api === void 0 || (_api$primaryToolbar = api.primaryToolbar) === null || _api$primaryToolbar === void 0 || (_api$primaryToolbar = _api$primaryToolbar.actions) === null || _api$primaryToolbar === void 0 || _api$primaryToolbar.registerComponent({
48
+ name: 'selectionExtension',
49
+ component: function component() {
50
+ return /*#__PURE__*/_react.default.createElement(_LegacyToolbarComponent.LegacyPrimaryToolbarComponent, {
51
+ primaryToolbarItemExtensions: primaryToolbarItemExtensions
52
+ });
53
+ }
54
+ });
55
+ }
56
+ }
30
57
  return {
31
58
  name: 'selectionExtension',
32
59
  getSharedState: function getSharedState(editorState) {
@@ -37,8 +64,8 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
37
64
  },
38
65
  commands: {
39
66
  setActiveExtension: function setActiveExtension(extension) {
40
- return function (_ref2) {
41
- var tr = _ref2.tr;
67
+ return function (_ref4) {
68
+ var tr = _ref4.tr;
42
69
  return tr.setMeta(_main.selectionExtensionPluginKey, {
43
70
  type: 'set-active-extension',
44
71
  extension: extension
@@ -46,8 +73,8 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
46
73
  };
47
74
  },
48
75
  clearActiveExtension: function clearActiveExtension() {
49
- return function (_ref3) {
50
- var tr = _ref3.tr;
76
+ return function (_ref5) {
77
+ var tr = _ref5.tr;
51
78
  return tr.setMeta(_main.selectionExtensionPluginKey, {
52
79
  type: 'clear-active-extension'
53
80
  });
@@ -89,10 +116,14 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
89
116
  dispatch = _editorViewRef$curren3.dispatch;
90
117
  return (0, _insertAdfAtEndOfDoc2.insertAdfAtEndOfDoc)(nodeAdf)(state, dispatch);
91
118
  }
119
+ // NEXT PR: Implement this to return selectedNodeAdf, selectionRanges
120
+ // getSelectionAdf: () => {},
121
+ // NEXT PR: Implement this to return text, coords
122
+ // getSelectionText: () => {},
92
123
  },
93
- contentComponent: function contentComponent(_ref4) {
124
+ contentComponent: function contentComponent(_ref6) {
94
125
  var _api$analytics;
95
- var editorView = _ref4.editorView;
126
+ var editorView = _ref6.editorView;
96
127
  return /*#__PURE__*/_react.default.createElement(_SelectionExtensionComponentWrapper.SelectionExtensionComponentWrapper, {
97
128
  editorView: editorView,
98
129
  api: api,
@@ -105,25 +136,17 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
105
136
  if (!config) {
106
137
  return;
107
138
  }
108
- var pageModes = config.pageModes,
109
- extensions = config.extensions;
139
+ var pageModes = config.pageModes;
110
140
 
111
- /**
112
- * Extensions Config Validation
113
- *
114
- * Check whether plugin contains any selection extensions
115
- */
116
- if ((!(extensions !== null && extensions !== void 0 && extensions.firstParty) || extensions.firstParty.length === 0) && (!(extensions !== null && extensions !== void 0 && extensions.external) || extensions.external.length === 0)) {
141
+ // Extensions Config Validation
142
+ // Check whether plugin contains any selection extensions
143
+ if (!(firstParty !== null && firstParty !== void 0 && firstParty.length) && !(external !== null && external !== void 0 && external.length) && !(extensionList !== null && extensionList !== void 0 && extensionList.length)) {
117
144
  return;
118
145
  }
119
146
 
120
- /**
121
- * Content Mode Validation
122
- *
123
- * Check if pageModes is provided and matches against current content mode
124
- *
125
- * TODO: This will eventially transition from mode to contentMode
126
- */
147
+ // Content Mode Validation
148
+ // Check if pageModes is provided and matches against current content mode
149
+ // This will eventially transition from mode to contentMode
127
150
  var editorContentMode = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode;
128
151
  if (pageModes) {
129
152
  // Early Exit: consumer has set pageModes but editorContentMode is undefined
@@ -140,22 +163,26 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
140
163
  }
141
164
  }
142
165
 
143
- /**
144
- * Active Extension
145
- *
146
- * Check if there is an active extension and hide the selection extension dropdown
147
- */
166
+ // Active Extension
167
+ // Check if there is an active extension and hide the selection extension dropdown
148
168
  var selectionExtensionState = _main.selectionExtensionPluginKey.getState(state);
149
169
  if (selectionExtensionState !== null && selectionExtensionState !== void 0 && selectionExtensionState.activeExtension) {
150
170
  return;
151
171
  }
152
172
  var getSelection = function getSelection(view) {
173
+ var _api$userPreferences, _api$selectionToolbar, _api$editorViewMode2;
153
174
  // ensure the same document state is applied to editor view to avoid mismatches
154
175
  var currentSelection = view.state.selection;
176
+ var toolbarDocking = (0, _platformFeatureFlags.fg)('platform_editor_use_preferences_plugin') ? api === null || api === void 0 || (_api$userPreferences = api.userPreferences) === null || _api$userPreferences === void 0 || (_api$userPreferences = _api$userPreferences.sharedState.currentState()) === null || _api$userPreferences === void 0 || (_api$userPreferences = _api$userPreferences.preferences) === null || _api$userPreferences === void 0 ? void 0 : _api$userPreferences.toolbarDockingPosition : api === null || api === void 0 || (_api$selectionToolbar = api.selectionToolbar) === null || _api$selectionToolbar === void 0 || (_api$selectionToolbar = _api$selectionToolbar.sharedState) === null || _api$selectionToolbar === void 0 || (_api$selectionToolbar = _api$selectionToolbar.currentState()) === null || _api$selectionToolbar === void 0 ? void 0 : _api$selectionToolbar.toolbarDocking;
177
+ var isEditMode = Boolean((api === null || api === void 0 || (_api$editorViewMode2 = api.editorViewMode) === null || _api$editorViewMode2 === void 0 || (_api$editorViewMode2 = _api$editorViewMode2.sharedState.currentState()) === null || _api$editorViewMode2 === void 0 ? void 0 : _api$editorViewMode2.mode) === 'edit');
178
+ var shouldOffsetToolbarHeight = toolbarDocking === 'top' && isEditMode && (0, _platformFeatureFlags.fg)('platform_editor_selection_extension_api_v2');
155
179
  var from = currentSelection.from,
156
180
  to = currentSelection.to;
157
181
  var text = view.state.doc.textBetween(from, to, '\n');
158
- var coords = (0, _getBoundingBoxFromSelection.getBoundingBoxFromSelection)(view, from, to);
182
+ var coords = (0, _getBoundingBoxFromSelection.getBoundingBoxFromSelection)(view, from, to, {
183
+ top: shouldOffsetToolbarHeight ? _editorSharedStyles.akEditorFullPageToolbarHeight : 0,
184
+ bottom: shouldOffsetToolbarHeight ? _editorSharedStyles.akEditorFullPageToolbarHeight : 0
185
+ });
159
186
  return {
160
187
  text: text,
161
188
  from: from,
@@ -187,8 +214,8 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
187
214
  selectionRanges: selectionRanges
188
215
  };
189
216
  (_extension$onClick = extension.onClick) === null || _extension$onClick === void 0 || _extension$onClick.call(extension, onClickCallbackOptions);
190
- api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref5) {
191
- var tr = _ref5.tr;
217
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref7) {
218
+ var tr = _ref7.tr;
192
219
  tr.setMeta(_main.selectionExtensionPluginKey, {
193
220
  type: _types.SelectionExtensionActionTypes.SET_SELECTED_NODE,
194
221
  selectedNode: selectedNode,
@@ -251,9 +278,7 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
251
278
  });
252
279
  };
253
280
 
254
- /**
255
- * Add a heading to the external extensions
256
- */
281
+ // Add a heading to the external extensions
257
282
  var getExternalExtensions = function getExternalExtensions(extensions) {
258
283
  var prefilteredExtensions = prefilterExtensions(extensions);
259
284
  var externalExtensions = [];
@@ -270,13 +295,28 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
270
295
  }
271
296
  return externalExtensions;
272
297
  };
298
+
299
+ // NEXT PR: Make sure we cache the whole generated selection toolbar
300
+ // also debug this to make sure it's actually preventing unnecessary re-renders / work
273
301
  if (cachedOverflowMenuOptions && state.selection.eq(cachedSelection) && (0, _platformFeatureFlags.fg)('platform_editor_selection_extension_api_v2')) {
274
- return (0, _selectionToolbar2.selectionToolbar)(cachedOverflowMenuOptions);
302
+ return (0, _selectionToolbar2.selectionToolbar)({
303
+ overflowOptions: cachedOverflowMenuOptions,
304
+ extensionList: extensionList
305
+ });
306
+ }
307
+ var allFirstParty = (0, _toConsumableArray2.default)(firstParty);
308
+ var allExternal = (0, _toConsumableArray2.default)(external);
309
+ if ((0, _platformFeatureFlags.fg)('platform_editor_selection_extension_api_v2')) {
310
+ allFirstParty = [].concat((0, _toConsumableArray2.default)(firstParty), (0, _toConsumableArray2.default)((0, _extensions.getMenuItemExtensions)(extensionList, 'first-party')));
311
+ allExternal = [].concat((0, _toConsumableArray2.default)(external), (0, _toConsumableArray2.default)((0, _extensions.getMenuItemExtensions)(extensionList, 'external')));
275
312
  }
276
- var groupedExtensionsArray = [].concat((0, _toConsumableArray2.default)(getFirstPartyExtensions(extensions.firstParty || [])), (0, _toConsumableArray2.default)(getExternalExtensions(extensions.external || [])));
313
+ var groupedExtensionsArray = [].concat((0, _toConsumableArray2.default)(getFirstPartyExtensions(allFirstParty)), (0, _toConsumableArray2.default)(getExternalExtensions(allExternal)));
277
314
  cachedOverflowMenuOptions = groupedExtensionsArray;
278
315
  cachedSelection = state.selection;
279
- return (0, _selectionToolbar2.selectionToolbar)(groupedExtensionsArray);
316
+ return (0, _selectionToolbar2.selectionToolbar)({
317
+ overflowOptions: cachedOverflowMenuOptions,
318
+ extensionList: extensionList
319
+ });
280
320
  }
281
321
  },
282
322
  pmPlugins: function pmPlugins() {
@@ -0,0 +1,120 @@
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.LegacyPrimaryToolbarComponent = exports.LegacyExtensionToolbarItem = void 0;
9
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
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 LegacyPrimaryToolbarComponent = exports.LegacyPrimaryToolbarComponent = function LegacyPrimaryToolbarComponent(_ref) {
14
+ var primaryToolbarItemExtensions = _ref.primaryToolbarItemExtensions;
15
+ // NEXT PR: need to render a separator after – if there are extensions added
16
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, primaryToolbarItemExtensions.map(function (toolbarItemExtension, i) {
17
+ var toolbarItem = toolbarItemExtension.getToolbarItem();
18
+ return /*#__PURE__*/_react.default.createElement(LegacyExtensionToolbarItem, {
19
+ key: toolbarItem.tooltip,
20
+ toolbarItem: toolbarItem
21
+ });
22
+ }));
23
+ };
24
+ var LegacyExtensionToolbarItem = exports.LegacyExtensionToolbarItem = function LegacyExtensionToolbarItem(_ref2) {
25
+ var toolbarItem = _ref2.toolbarItem,
26
+ getMenuItems = _ref2.getMenuItems;
27
+ var _useState = (0, _react.useState)(false),
28
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
29
+ isOpen = _useState2[0],
30
+ setIsOpen = _useState2[1];
31
+ var Icon = toolbarItem.icon,
32
+ tooltip = toolbarItem.tooltip,
33
+ isDisabled = toolbarItem.isDisabled,
34
+ onClick = toolbarItem.onClick,
35
+ _label = toolbarItem.label;
36
+ if (!getMenuItems) {
37
+ return /*#__PURE__*/_react.default.createElement(_uiMenu.ToolbarButton, {
38
+ spacing: "default",
39
+ disabled: isDisabled,
40
+ selected: isOpen,
41
+ title: tooltip,
42
+ "aria-label": tooltip,
43
+ "aria-expanded": isOpen,
44
+ "aria-haspopup": true,
45
+ onClick: onClick,
46
+ iconBefore: /*#__PURE__*/_react.default.createElement(Icon, {
47
+ label: tooltip
48
+ })
49
+ });
50
+ }
51
+ var toggleOpen = function toggleOpen() {
52
+ setIsOpen(function (prev) {
53
+ return !prev;
54
+ });
55
+ };
56
+ var toggleOpenByKeyboard = function toggleOpenByKeyboard(event) {
57
+ if (event.key === 'Enter' || event.key === ' ') {
58
+ event.preventDefault();
59
+ toggleOpen();
60
+ }
61
+ };
62
+ var handleItemActivated = function handleItemActivated(_ref3) {
63
+ var _item$onClick;
64
+ var item = _ref3.item,
65
+ _ref3$shouldCloseMenu = _ref3.shouldCloseMenu,
66
+ shouldCloseMenu = _ref3$shouldCloseMenu === void 0 ? true : _ref3$shouldCloseMenu;
67
+ (_item$onClick = item.onClick) === null || _item$onClick === void 0 || _item$onClick.call(item);
68
+ if (shouldCloseMenu) {
69
+ setIsOpen(false);
70
+ }
71
+ };
72
+ var handleOnOpenChange = function handleOnOpenChange(attrs) {
73
+ setIsOpen(!!(attrs !== null && attrs !== void 0 && attrs.isOpen));
74
+ };
75
+ var items = isOpen ? getMenuItems().map(function (menuItem, i) {
76
+ return {
77
+ key: "menu-item-".concat(i),
78
+ content: menuItem.label,
79
+ elemBefore: /*#__PURE__*/_react.default.createElement(menuItem.icon, {
80
+ label: menuItem.label
81
+ }),
82
+ onClick: function onClick() {
83
+ var _menuItem$onClick;
84
+ (_menuItem$onClick = menuItem.onClick) === null || _menuItem$onClick === void 0 || _menuItem$onClick.call(menuItem);
85
+ // NEXT PR: here we need to set the active extension so the contentComponent can render
86
+ // menuItem.contentComponent
87
+ },
88
+ isDisabled: menuItem.isDisabled,
89
+ 'aria-label': menuItem.label,
90
+ value: {
91
+ name: menuItem.label
92
+ }
93
+ };
94
+ }) : [];
95
+ return /*#__PURE__*/_react.default.createElement(_uiMenu.DropdownMenuWithKeyboardNavigation, {
96
+ arrowKeyNavigationProviderOptions: {
97
+ type: _uiMenu.ArrowKeyNavigationType.MENU
98
+ },
99
+ items: [{
100
+ items: items
101
+ }],
102
+ isOpen: isOpen,
103
+ onItemActivated: handleItemActivated,
104
+ onOpenChange: handleOnOpenChange,
105
+ fitWidth: 200
106
+ }, /*#__PURE__*/_react.default.createElement(_uiMenu.ToolbarButton, {
107
+ spacing: "default",
108
+ disabled: isDisabled,
109
+ selected: isOpen,
110
+ title: tooltip,
111
+ "aria-label": tooltip,
112
+ "aria-expanded": isOpen,
113
+ "aria-haspopup": true,
114
+ onClick: toggleOpen,
115
+ onKeyDown: toggleOpenByKeyboard,
116
+ iconBefore: /*#__PURE__*/_react.default.createElement(Icon, {
117
+ label: tooltip
118
+ })
119
+ }));
120
+ };
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getToolbarItemExtensions = exports.getMenuItemExtensions = void 0;
7
+ /**
8
+ * From the full list of extensions, extract only those that have a toolbar item configuration
9
+ * for the specified type (either 'primaryToolbar' or 'inlineToolbar').
10
+ *
11
+ * @param extensionList - List of all extensions
12
+ * @param toolbarType - Type of toolbar ('primaryToolbar' or 'inlineToolbar')
13
+ * @returns Array of ToolbarItemExtension objects
14
+ * @example
15
+ */
16
+ var getToolbarItemExtensions = exports.getToolbarItemExtensions = function getToolbarItemExtensions(extensionList, toolbarType) {
17
+ return extensionList.reduce(function (acc, extension) {
18
+ var toolbarConfig = extension[toolbarType];
19
+ if (toolbarConfig !== null && toolbarConfig !== void 0 && toolbarConfig.getToolbarItem) {
20
+ acc.push({
21
+ getToolbarItem: toolbarConfig.getToolbarItem,
22
+ getMenuItems: toolbarConfig.getMenuItems
23
+ });
24
+ }
25
+ return acc;
26
+ }, []);
27
+ };
28
+
29
+ /**
30
+ * From the full list of extensions, extract only those that have a menu item configuration
31
+ * for the specified source (either 'first-party' or 'external').
32
+ *
33
+ * Map each to the legacy format for SelectionExtensionConfig.
34
+ *
35
+ * @param extensionList - List of all extensions
36
+ * @param targetSource - Source of the extensions ('first-party' or 'external')
37
+ * @returns Array of SelectionExtensionConfig objects
38
+ * @example
39
+ */
40
+ var getMenuItemExtensions = exports.getMenuItemExtensions = function getMenuItemExtensions(extensionList, targetSource) {
41
+ return extensionList.reduce(function (acc, extension) {
42
+ var source = extension.source,
43
+ inlineToolbar = extension.inlineToolbar;
44
+ if (source === targetSource && inlineToolbar !== null && inlineToolbar !== void 0 && inlineToolbar.getMenuItems && !inlineToolbar.getToolbarItem) {
45
+ var menuItems = inlineToolbar.getMenuItems();
46
+ menuItems.forEach(function (menuItem) {
47
+ acc.push({
48
+ name: menuItem.label,
49
+ icon: menuItem.icon,
50
+ onClick: menuItem.onClick,
51
+ isDisabled: function isDisabled() {
52
+ return !!menuItem.isDisabled;
53
+ },
54
+ component: menuItem.contentComponent
55
+ });
56
+ });
57
+ }
58
+ return acc;
59
+ }, []);
60
+ };
@@ -10,9 +10,14 @@ exports.getBoundingBoxFromSelection = void 0;
10
10
  * @param view - The editor view instance.
11
11
  * @param from - The starting position of the selection.
12
12
  * @param to - The ending position of the selection.
13
+ * @param offset - Optional offset to adjust the top and bottom coordinates of the bounding box.`
13
14
  * @returns An object containing the top, left, bottom, and right coordinates of the bounding box.
14
15
  */
15
16
  var getBoundingBoxFromSelection = exports.getBoundingBoxFromSelection = function getBoundingBoxFromSelection(view, from, to) {
17
+ var offset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {
18
+ top: 0,
19
+ bottom: 0
20
+ };
16
21
  var top = Infinity,
17
22
  left = Infinity,
18
23
  bottom = -Infinity,
@@ -26,6 +31,8 @@ var getBoundingBoxFromSelection = exports.getBoundingBoxFromSelection = function
26
31
  bottom = Math.max(bottom, coords.bottom);
27
32
  right = Math.max(right, coords.right);
28
33
  }
34
+ top = top - offset.top;
35
+ bottom = bottom - offset.bottom;
29
36
  return {
30
37
  top: top,
31
38
  left: left,
@@ -1,13 +1,40 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.selectionToolbar = void 0;
7
- var selectionToolbar = exports.selectionToolbar = function selectionToolbar(options) {
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _react = _interopRequireDefault(require("react"));
10
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
11
+ var _extensions = require("./extensions");
12
+ var _LegacyToolbarComponent = require("./LegacyToolbarComponent");
13
+ var selectionToolbar = exports.selectionToolbar = function selectionToolbar(_ref) {
14
+ var overflowOptions = _ref.overflowOptions,
15
+ _ref$extensionList = _ref.extensionList,
16
+ extensionList = _ref$extensionList === void 0 ? [] : _ref$extensionList;
17
+ var inlineToolbarItemExtensions = (0, _platformFeatureFlags.fg)('platform_editor_selection_extension_api_v2') ? (0, _extensions.getToolbarItemExtensions)(extensionList, 'inlineToolbar') : [];
8
18
  return {
9
- isToolbarAbove: true,
10
- items: [{
19
+ items: [].concat((0, _toConsumableArray2.default)(inlineToolbarItemExtensions.length ? [{
20
+ type: 'separator',
21
+ fullHeight: true,
22
+ supportsViewMode: true
23
+ }].concat((0, _toConsumableArray2.default)(inlineToolbarItemExtensions.map(function (_ref2) {
24
+ var getToolbarItem = _ref2.getToolbarItem,
25
+ getMenuItems = _ref2.getMenuItems;
26
+ return {
27
+ type: 'custom',
28
+ render: function render() {
29
+ return /*#__PURE__*/_react.default.createElement(_LegacyToolbarComponent.LegacyExtensionToolbarItem, {
30
+ toolbarItem: getToolbarItem(),
31
+ getMenuItems: getMenuItems
32
+ });
33
+ },
34
+ fallback: [],
35
+ supportsViewMode: true
36
+ };
37
+ }))) : []), [{
11
38
  type: 'separator',
12
39
  fullHeight: true,
13
40
  supportsViewMode: true
@@ -15,8 +42,8 @@ var selectionToolbar = exports.selectionToolbar = function selectionToolbar(opti
15
42
  type: 'overflow-dropdown',
16
43
  dropdownWidth: 240,
17
44
  supportsViewMode: true,
18
- options: options
19
- }],
45
+ options: overflowOptions
46
+ }]),
20
47
  rank: -6
21
48
  };
22
49
  };
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { selectionExtensionMessages } from '@atlaskit/editor-common/messages';
3
3
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
4
+ import { akEditorFullPageToolbarHeight } from '@atlaskit/editor-shared-styles';
4
5
  import { fg } from '@atlaskit/platform-feature-flags';
5
6
  import { insertSmartLinks } from './pm-plugins/actions';
6
7
  import { insertAdfAtEndOfDoc } from './pm-plugins/actions/insertAdfAtEndOfDoc';
@@ -9,7 +10,9 @@ import { createPlugin, selectionExtensionPluginKey } from './pm-plugins/main';
9
10
  import { getSelectionInfo } from './pm-plugins/utils';
10
11
  import { SelectionExtensionActionTypes } from './types';
11
12
  import { SelectionExtensionComponentWrapper } from './ui/extension/SelectionExtensionComponentWrapper';
13
+ import { getMenuItemExtensions, getToolbarItemExtensions } from './ui/extensions';
12
14
  import { getBoundingBoxFromSelection } from './ui/getBoundingBoxFromSelection';
15
+ import { LegacyPrimaryToolbarComponent } from './ui/LegacyToolbarComponent';
13
16
  import { selectionToolbar } from './ui/selectionToolbar';
14
17
  export const selectionExtensionPlugin = ({
15
18
  api,
@@ -20,6 +23,26 @@ export const selectionExtensionPlugin = ({
20
23
  };
21
24
  let cachedSelection;
22
25
  let cachedOverflowMenuOptions;
26
+ const {
27
+ extensionList = [],
28
+ extensions = {}
29
+ } = config || {};
30
+ const {
31
+ firstParty = [],
32
+ external = []
33
+ } = extensions || {};
34
+ if (fg('platform_editor_selection_extension_api_v2')) {
35
+ const primaryToolbarItemExtensions = getToolbarItemExtensions(extensionList, 'primaryToolbar');
36
+ if (primaryToolbarItemExtensions !== null && primaryToolbarItemExtensions !== void 0 && primaryToolbarItemExtensions.length) {
37
+ var _api$primaryToolbar, _api$primaryToolbar$a;
38
+ api === null || api === void 0 ? void 0 : (_api$primaryToolbar = api.primaryToolbar) === null || _api$primaryToolbar === void 0 ? void 0 : (_api$primaryToolbar$a = _api$primaryToolbar.actions) === null || _api$primaryToolbar$a === void 0 ? void 0 : _api$primaryToolbar$a.registerComponent({
39
+ name: 'selectionExtension',
40
+ component: () => /*#__PURE__*/React.createElement(LegacyPrimaryToolbarComponent, {
41
+ primaryToolbarItemExtensions: primaryToolbarItemExtensions
42
+ })
43
+ });
44
+ }
45
+ }
23
46
  return {
24
47
  name: 'selectionExtension',
25
48
  getSharedState(editorState) {
@@ -83,6 +106,10 @@ export const selectionExtensionPlugin = ({
83
106
  } = editorViewRef.current;
84
107
  return insertAdfAtEndOfDoc(nodeAdf)(state, dispatch);
85
108
  }
109
+ // NEXT PR: Implement this to return selectedNodeAdf, selectionRanges
110
+ // getSelectionAdf: () => {},
111
+ // NEXT PR: Implement this to return text, coords
112
+ // getSelectionText: () => {},
86
113
  },
87
114
  contentComponent: ({
88
115
  editorView
@@ -101,26 +128,18 @@ export const selectionExtensionPlugin = ({
101
128
  return;
102
129
  }
103
130
  const {
104
- pageModes,
105
- extensions
131
+ pageModes
106
132
  } = config;
107
133
 
108
- /**
109
- * Extensions Config Validation
110
- *
111
- * Check whether plugin contains any selection extensions
112
- */
113
- if ((!(extensions !== null && extensions !== void 0 && extensions.firstParty) || extensions.firstParty.length === 0) && (!(extensions !== null && extensions !== void 0 && extensions.external) || extensions.external.length === 0)) {
134
+ // Extensions Config Validation
135
+ // Check whether plugin contains any selection extensions
136
+ if (!(firstParty !== null && firstParty !== void 0 && firstParty.length) && !(external !== null && external !== void 0 && external.length) && !(extensionList !== null && extensionList !== void 0 && extensionList.length)) {
114
137
  return;
115
138
  }
116
139
 
117
- /**
118
- * Content Mode Validation
119
- *
120
- * Check if pageModes is provided and matches against current content mode
121
- *
122
- * TODO: This will eventially transition from mode to contentMode
123
- */
140
+ // Content Mode Validation
141
+ // Check if pageModes is provided and matches against current content mode
142
+ // This will eventially transition from mode to contentMode
124
143
  const editorContentMode = api === null || api === void 0 ? void 0 : (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : (_api$editorViewMode$s = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode$s === void 0 ? void 0 : _api$editorViewMode$s.mode;
125
144
  if (pageModes) {
126
145
  // Early Exit: consumer has set pageModes but editorContentMode is undefined
@@ -137,26 +156,30 @@ export const selectionExtensionPlugin = ({
137
156
  }
138
157
  }
139
158
 
140
- /**
141
- * Active Extension
142
- *
143
- * Check if there is an active extension and hide the selection extension dropdown
144
- */
159
+ // Active Extension
160
+ // Check if there is an active extension and hide the selection extension dropdown
145
161
  const selectionExtensionState = selectionExtensionPluginKey.getState(state);
146
162
  if (selectionExtensionState !== null && selectionExtensionState !== void 0 && selectionExtensionState.activeExtension) {
147
163
  return;
148
164
  }
149
165
  const getSelection = view => {
166
+ var _api$userPreferences, _api$userPreferences$, _api$userPreferences$2, _api$selectionToolbar, _api$selectionToolbar2, _api$selectionToolbar3, _api$editorViewMode2, _api$editorViewMode2$;
150
167
  // ensure the same document state is applied to editor view to avoid mismatches
151
168
  const {
152
169
  selection: currentSelection
153
170
  } = view.state;
171
+ const toolbarDocking = fg('platform_editor_use_preferences_plugin') ? api === null || api === void 0 ? void 0 : (_api$userPreferences = api.userPreferences) === null || _api$userPreferences === void 0 ? void 0 : (_api$userPreferences$ = _api$userPreferences.sharedState.currentState()) === null || _api$userPreferences$ === void 0 ? void 0 : (_api$userPreferences$2 = _api$userPreferences$.preferences) === null || _api$userPreferences$2 === void 0 ? void 0 : _api$userPreferences$2.toolbarDockingPosition : api === null || api === void 0 ? void 0 : (_api$selectionToolbar = api.selectionToolbar) === null || _api$selectionToolbar === void 0 ? void 0 : (_api$selectionToolbar2 = _api$selectionToolbar.sharedState) === null || _api$selectionToolbar2 === void 0 ? void 0 : (_api$selectionToolbar3 = _api$selectionToolbar2.currentState()) === null || _api$selectionToolbar3 === void 0 ? void 0 : _api$selectionToolbar3.toolbarDocking;
172
+ const isEditMode = Boolean((api === null || api === void 0 ? void 0 : (_api$editorViewMode2 = api.editorViewMode) === null || _api$editorViewMode2 === void 0 ? void 0 : (_api$editorViewMode2$ = _api$editorViewMode2.sharedState.currentState()) === null || _api$editorViewMode2$ === void 0 ? void 0 : _api$editorViewMode2$.mode) === 'edit');
173
+ const shouldOffsetToolbarHeight = toolbarDocking === 'top' && isEditMode && fg('platform_editor_selection_extension_api_v2');
154
174
  const {
155
175
  from,
156
176
  to
157
177
  } = currentSelection;
158
178
  const text = view.state.doc.textBetween(from, to, '\n');
159
- const coords = getBoundingBoxFromSelection(view, from, to);
179
+ const coords = getBoundingBoxFromSelection(view, from, to, {
180
+ top: shouldOffsetToolbarHeight ? akEditorFullPageToolbarHeight : 0,
181
+ bottom: shouldOffsetToolbarHeight ? akEditorFullPageToolbarHeight : 0
182
+ });
160
183
  return {
161
184
  text,
162
185
  from,
@@ -251,9 +274,7 @@ export const selectionExtensionPlugin = ({
251
274
  });
252
275
  };
253
276
 
254
- /**
255
- * Add a heading to the external extensions
256
- */
277
+ // Add a heading to the external extensions
257
278
  const getExternalExtensions = extensions => {
258
279
  const prefilteredExtensions = prefilterExtensions(extensions);
259
280
  let externalExtensions = [];
@@ -270,13 +291,28 @@ export const selectionExtensionPlugin = ({
270
291
  }
271
292
  return externalExtensions;
272
293
  };
294
+
295
+ // NEXT PR: Make sure we cache the whole generated selection toolbar
296
+ // also debug this to make sure it's actually preventing unnecessary re-renders / work
273
297
  if (cachedOverflowMenuOptions && state.selection.eq(cachedSelection) && fg('platform_editor_selection_extension_api_v2')) {
274
- return selectionToolbar(cachedOverflowMenuOptions);
298
+ return selectionToolbar({
299
+ overflowOptions: cachedOverflowMenuOptions,
300
+ extensionList
301
+ });
302
+ }
303
+ let allFirstParty = [...firstParty];
304
+ let allExternal = [...external];
305
+ if (fg('platform_editor_selection_extension_api_v2')) {
306
+ allFirstParty = [...firstParty, ...getMenuItemExtensions(extensionList, 'first-party')];
307
+ allExternal = [...external, ...getMenuItemExtensions(extensionList, 'external')];
275
308
  }
276
- const groupedExtensionsArray = [...getFirstPartyExtensions(extensions.firstParty || []), ...getExternalExtensions(extensions.external || [])];
309
+ const groupedExtensionsArray = [...getFirstPartyExtensions(allFirstParty), ...getExternalExtensions(allExternal)];
277
310
  cachedOverflowMenuOptions = groupedExtensionsArray;
278
311
  cachedSelection = state.selection;
279
- return selectionToolbar(groupedExtensionsArray);
312
+ return selectionToolbar({
313
+ overflowOptions: cachedOverflowMenuOptions,
314
+ extensionList
315
+ });
280
316
  }
281
317
  },
282
318
  pmPlugins: () => [{