@atlaskit/editor-plugin-paste-options-toolbar 9.1.6 → 9.1.7
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 +10 -0
- package/dist/cjs/ui/on-paste-actions-menu/PasteActionsMenu.js +61 -10
- package/dist/cjs/ui/on-paste-actions-menu/PasteActionsMenuContent.js +16 -13
- package/dist/cjs/ui/on-paste-actions-menu/PasteMenuComponents.js +45 -15
- package/dist/cjs/ui/on-paste-actions-menu/PasteOptionsDropdownButton.js +52 -0
- package/dist/es2019/ui/on-paste-actions-menu/PasteActionsMenu.js +60 -11
- package/dist/es2019/ui/on-paste-actions-menu/PasteActionsMenuContent.js +17 -14
- package/dist/es2019/ui/on-paste-actions-menu/PasteMenuComponents.js +45 -13
- package/dist/es2019/ui/on-paste-actions-menu/PasteOptionsDropdownButton.js +47 -0
- package/dist/esm/ui/on-paste-actions-menu/PasteActionsMenu.js +61 -11
- package/dist/esm/ui/on-paste-actions-menu/PasteActionsMenuContent.js +17 -14
- package/dist/esm/ui/on-paste-actions-menu/PasteMenuComponents.js +45 -15
- package/dist/esm/ui/on-paste-actions-menu/PasteOptionsDropdownButton.js +46 -0
- package/dist/types/ui/on-paste-actions-menu/PasteActionsMenu.d.ts +16 -0
- package/dist/types/ui/on-paste-actions-menu/PasteActionsMenuContent.d.ts +2 -1
- package/dist/types/ui/on-paste-actions-menu/PasteOptionsDropdownButton.d.ts +19 -0
- package/dist/types-ts4.5/ui/on-paste-actions-menu/PasteActionsMenu.d.ts +16 -0
- package/dist/types-ts4.5/ui/on-paste-actions-menu/PasteActionsMenuContent.d.ts +2 -1
- package/dist/types-ts4.5/ui/on-paste-actions-menu/PasteOptionsDropdownButton.d.ts +19 -0
- package/package.json +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-paste-options-toolbar
|
|
2
2
|
|
|
3
|
+
## 9.1.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`3b007c601e102`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/3b007c601e102) -
|
|
8
|
+
EDITOR-6092 Remove 100 character limit on legacy paste actions for new editor AI paste actions
|
|
9
|
+
menu. Also redesigns the legacy paste actions to more closely resemble the legacy paste floating
|
|
10
|
+
toolbar when there are no AI actions present.
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
|
|
3
13
|
## 9.1.6
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
|
@@ -9,6 +9,7 @@ exports.PasteActionsMenu = void 0;
|
|
|
9
9
|
exports.findBlockAncestorDOM = findBlockAncestorDOM;
|
|
10
10
|
exports.getTargetElement = getTargetElement;
|
|
11
11
|
exports.getVisualEndBottom = getVisualEndBottom;
|
|
12
|
+
exports.onInlinePositionCalculated = onInlinePositionCalculated;
|
|
12
13
|
exports.onPositionCalculated = onPositionCalculated;
|
|
13
14
|
exports.resolveTableAfterPos = resolveTableAfterPos;
|
|
14
15
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
@@ -118,6 +119,35 @@ function findBlockAncestorDOM(editorView, pos) {
|
|
|
118
119
|
return null;
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Positions the paste menu inline, immediately to the right of the cursor
|
|
124
|
+
* at the paste end position, vertically centered with the line.
|
|
125
|
+
* Used for short pastes without AI actions.
|
|
126
|
+
*/
|
|
127
|
+
function onInlinePositionCalculated(editorView, pasteEndPos, targetElement, popupContentRef) {
|
|
128
|
+
return function (position) {
|
|
129
|
+
var _popupContentRef$curr, _popupContentRef$curr2, _position$top, _position$left;
|
|
130
|
+
var endCoords = editorView.coordsAtPos(pasteEndPos);
|
|
131
|
+
var targetRect = targetElement.getBoundingClientRect();
|
|
132
|
+
|
|
133
|
+
// Vertical: center the menu with the line at the paste end position.
|
|
134
|
+
var lineHeight = endCoords.bottom - endCoords.top;
|
|
135
|
+
var lineMidpoint = endCoords.top + lineHeight / 2;
|
|
136
|
+
var menuHeight = (_popupContentRef$curr = (_popupContentRef$curr2 = popupContentRef.current) === null || _popupContentRef$curr2 === void 0 ? void 0 : _popupContentRef$curr2.getBoundingClientRect().height) !== null && _popupContentRef$curr !== void 0 ? _popupContentRef$curr : lineHeight;
|
|
137
|
+
var menuTop = lineMidpoint - menuHeight / 2;
|
|
138
|
+
var topDelta = menuTop - (targetRect.top + targetRect.height);
|
|
139
|
+
var adjustedTop = ((_position$top = position.top) !== null && _position$top !== void 0 ? _position$top : 0) + topDelta;
|
|
140
|
+
|
|
141
|
+
// Horizontal: position to the right of the cursor
|
|
142
|
+
var leftDelta = endCoords.right - targetRect.right;
|
|
143
|
+
var adjustedLeft = ((_position$left = position.left) !== null && _position$left !== void 0 ? _position$left : 0) + leftDelta;
|
|
144
|
+
return _objectSpread(_objectSpread({}, position), {}, {
|
|
145
|
+
top: adjustedTop,
|
|
146
|
+
left: adjustedLeft
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
121
151
|
/**
|
|
122
152
|
* Adjusts the position of the paste menu so that:
|
|
123
153
|
*
|
|
@@ -148,7 +178,7 @@ function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, targetElem
|
|
|
148
178
|
var tableAfterPos = resolveTableAfterPos(editorView, pasteEndPos);
|
|
149
179
|
var blockAncestorDOM = findBlockAncestorDOM(editorView, pasteStartPos);
|
|
150
180
|
return function (position) {
|
|
151
|
-
var _position$
|
|
181
|
+
var _position$top2;
|
|
152
182
|
var startCoords = editorView.coordsAtPos(pasteStartPos);
|
|
153
183
|
var endBottom = getVisualEndBottom(editorView, pasteEndPos, tableAfterPos);
|
|
154
184
|
var targetRect = targetElement.getBoundingClientRect();
|
|
@@ -158,7 +188,7 @@ function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, targetElem
|
|
|
158
188
|
// We shift it up so it aligns with the paste start position.
|
|
159
189
|
// Both coordinates are in viewport space, so the delta is offset-parent agnostic.
|
|
160
190
|
var topDelta = startCoords.top - (targetRect.top + targetRect.height);
|
|
161
|
-
var adjustedTop = ((_position$
|
|
191
|
+
var adjustedTop = ((_position$top2 = position.top) !== null && _position$top2 !== void 0 ? _position$top2 : 0) + topDelta;
|
|
162
192
|
|
|
163
193
|
// Sticky-top: clamp to the scroll container's top edge when the paste
|
|
164
194
|
// start has scrolled above the visible area, but only while some pasted
|
|
@@ -180,13 +210,13 @@ function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, targetElem
|
|
|
180
210
|
// re-anchoring to its right edge.
|
|
181
211
|
var adjustedLeft = position.left;
|
|
182
212
|
if (blockAncestorDOM && blockAncestorDOM !== targetElement) {
|
|
183
|
-
var _position$
|
|
213
|
+
var _position$left2;
|
|
184
214
|
var blockRect = blockAncestorDOM.getBoundingClientRect();
|
|
185
215
|
// Shift left by the difference between the block's right edge and
|
|
186
216
|
// the inline target's right edge. This mirrors what alignX="end"
|
|
187
217
|
// would have computed if the target were the block element.
|
|
188
218
|
var leftDelta = blockRect.right - targetRect.right;
|
|
189
|
-
adjustedLeft = ((_position$
|
|
219
|
+
adjustedLeft = ((_position$left2 = position.left) !== null && _position$left2 !== void 0 ? _position$left2 : 0) + leftDelta;
|
|
190
220
|
}
|
|
191
221
|
return _objectSpread(_objectSpread({}, position), {}, {
|
|
192
222
|
top: adjustedTop,
|
|
@@ -210,8 +240,8 @@ var PasteActionsMenu = exports.PasteActionsMenu = function PasteActionsMenu(_ref
|
|
|
210
240
|
}),
|
|
211
241
|
lastContentPasted = _useSharedPluginState.lastContentPasted;
|
|
212
242
|
var prevShowToolbarRef = (0, _react.useRef)(false);
|
|
243
|
+
var popupContentRef = (0, _react.useRef)(null);
|
|
213
244
|
(0, _react.useEffect)(function () {
|
|
214
|
-
var _lastContentPasted$te, _lastContentPasted$te2;
|
|
215
245
|
if (!lastContentPasted) {
|
|
216
246
|
(0, _commands.hideToolbar)()(editorView.state, editorView.dispatch);
|
|
217
247
|
return;
|
|
@@ -234,7 +264,7 @@ var PasteActionsMenu = exports.PasteActionsMenu = function PasteActionsMenu(_ref
|
|
|
234
264
|
pasteAncestorNodeNames.push($pos.node(depth).type.name);
|
|
235
265
|
}
|
|
236
266
|
}
|
|
237
|
-
var legacyVisible = (0, _toolbar2.isToolbarVisible)(editorView.state, lastContentPasted)
|
|
267
|
+
var legacyVisible = (0, _toolbar2.isToolbarVisible)(editorView.state, lastContentPasted);
|
|
238
268
|
(0, _commands.showToolbar)(lastContentPasted, selectedOption, legacyVisible, pasteAncestorNodeNames)(editorView.state, editorView.dispatch);
|
|
239
269
|
}, [lastContentPasted, editorView]);
|
|
240
270
|
var _useSharedPluginState2 = (0, _hooks.useSharedPluginStateWithSelector)(api, ['pasteOptionsToolbarPlugin'], function (states) {
|
|
@@ -298,16 +328,36 @@ var PasteActionsMenu = exports.PasteActionsMenu = function PasteActionsMenu(_ref
|
|
|
298
328
|
var effectiveScrollableElement = overflowScrollParent || scrollableElement;
|
|
299
329
|
var pasteMenuComponents = (_api$uiControlRegistr3 = api === null || api === void 0 || (_api$uiControlRegistr4 = api.uiControlRegistry) === null || _api$uiControlRegistr4 === void 0 ? void 0 : _api$uiControlRegistr4.actions.getComponents(_toolbar.PASTE_MENU.key)) !== null && _api$uiControlRegistr3 !== void 0 ? _api$uiControlRegistr3 : [];
|
|
300
330
|
var anyComponentVisible = (0, _hasVisibleButton.hasVisibleButton)(pasteMenuComponents);
|
|
331
|
+
|
|
332
|
+
// Two positioning modes:
|
|
333
|
+
// 1. Inline: no AI actions visible — menu appears to the right of the cursor,
|
|
334
|
+
// vertically centered with the text line.
|
|
335
|
+
// 2. Block-anchored: AI actions are visible — menu appears at the right edge
|
|
336
|
+
// of the content block, aligned with paste start.
|
|
337
|
+
var hasVisibleAiActions = (0, _hasVisibleButton.getVisibleKeys)(
|
|
338
|
+
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- pasteMenuComponents changes by reference each render; filter is small (< 10 items)
|
|
339
|
+
pasteMenuComponents.filter(function (c) {
|
|
340
|
+
var _c$parents;
|
|
341
|
+
return c.type === 'menu-item' && ((_c$parents = c.parents) === null || _c$parents === void 0 ? void 0 : _c$parents.some(function (p) {
|
|
342
|
+
return p.key === _toolbar.AI_PASTE_MENU_SECTION.key;
|
|
343
|
+
}));
|
|
344
|
+
}), ['menu-item']).length > 0;
|
|
345
|
+
var useInlinePosition = !hasVisibleAiActions;
|
|
301
346
|
if (!isToolbarShown) {
|
|
302
347
|
return null;
|
|
303
348
|
}
|
|
304
349
|
if (!anyComponentVisible) {
|
|
305
350
|
return null;
|
|
306
351
|
}
|
|
307
|
-
var target = getTargetElement(editorView, pasteStartPos);
|
|
352
|
+
var target = getTargetElement(editorView, useInlinePosition ? pasteEndPos : pasteStartPos);
|
|
308
353
|
if (!target) {
|
|
309
354
|
return null;
|
|
310
355
|
}
|
|
356
|
+
|
|
357
|
+
// Choose positioning strategy based on whether the menu appears inline
|
|
358
|
+
// (right of cursor for short pastes) or anchored to the block ancestor
|
|
359
|
+
// (right side of content area for longer pastes / AI actions).
|
|
360
|
+
var positionCalculator = useInlinePosition ? onInlinePositionCalculated(editorView, pasteEndPos, target, popupContentRef) : onPositionCalculated(editorView, pasteStartPos, pasteEndPos, target, effectiveScrollableElement);
|
|
311
361
|
return /*#__PURE__*/_react.default.createElement(PopupWithListeners, {
|
|
312
362
|
target: target,
|
|
313
363
|
mountTo: mountTo,
|
|
@@ -316,10 +366,10 @@ var PasteActionsMenu = exports.PasteActionsMenu = function PasteActionsMenu(_ref
|
|
|
316
366
|
minPopupMargin: _constants.PASTE_MENU_GAP_HORIZONTAL,
|
|
317
367
|
zIndex: _editorSharedStyles.akEditorFloatingPanelZIndex,
|
|
318
368
|
alignX: "end",
|
|
319
|
-
alignY:
|
|
369
|
+
alignY: useInlinePosition ? 'top' : 'bottom'
|
|
320
370
|
/* eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) */,
|
|
321
371
|
offset: [_constants.PASTE_MENU_GAP_HORIZONTAL, 0],
|
|
322
|
-
onPositionCalculated:
|
|
372
|
+
onPositionCalculated: positionCalculator,
|
|
323
373
|
handleClickOutside: handleClickOutside,
|
|
324
374
|
handleEscapeKeydown: handleDismiss
|
|
325
375
|
}, /*#__PURE__*/_react.default.createElement(_toolbar.EditorToolbarProvider, {
|
|
@@ -330,6 +380,7 @@ var PasteActionsMenu = exports.PasteActionsMenu = function PasteActionsMenu(_ref
|
|
|
330
380
|
}, /*#__PURE__*/_react.default.createElement(_PasteActionsMenuContent.PasteActionsMenuContent, {
|
|
331
381
|
onMouseDown: preventEditorFocusLoss,
|
|
332
382
|
onMouseEnter: handleMouseEnter,
|
|
333
|
-
components: pasteMenuComponents
|
|
383
|
+
components: pasteMenuComponents,
|
|
384
|
+
contentRef: popupContentRef
|
|
334
385
|
}))));
|
|
335
386
|
};
|
|
@@ -9,34 +9,37 @@ exports.PasteActionsMenuContent = void 0;
|
|
|
9
9
|
require("./PasteActionsMenuContent.compiled.css");
|
|
10
10
|
var _runtime = require("@compiled/react/runtime");
|
|
11
11
|
var _react = _interopRequireWildcard(require("react"));
|
|
12
|
-
var
|
|
13
|
-
var _messages = require("@atlaskit/editor-common/messages");
|
|
12
|
+
var _toolbar = require("@atlaskit/editor-common/toolbar");
|
|
14
13
|
var _uiReact = require("@atlaskit/editor-common/ui-react");
|
|
15
|
-
var _editorToolbar = require("@atlaskit/editor-toolbar");
|
|
16
14
|
var _editorUiControlModel = require("@atlaskit/editor-ui-control-model");
|
|
17
15
|
var _compiled = require("@atlaskit/primitives/compiled");
|
|
18
16
|
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); }
|
|
19
17
|
var styles = {
|
|
20
18
|
container: "_2rko12b0 _bfhk1bhr _16qs130s"
|
|
21
19
|
};
|
|
20
|
+
var pasteMenuSurface = {
|
|
21
|
+
type: _toolbar.PASTE_MENU.type,
|
|
22
|
+
key: _toolbar.PASTE_MENU.key
|
|
23
|
+
};
|
|
22
24
|
var PasteActionsMenuContent = exports.PasteActionsMenuContent = function PasteActionsMenuContent(_ref) {
|
|
23
25
|
var onMouseDown = _ref.onMouseDown,
|
|
24
26
|
onMouseEnter = _ref.onMouseEnter,
|
|
25
|
-
components = _ref.components
|
|
27
|
+
components = _ref.components,
|
|
28
|
+
contentRef = _ref.contentRef;
|
|
26
29
|
var setOutsideClickTargetRef = (0, _react.useContext)(_uiReact.OutsideClickTargetRefContext);
|
|
27
|
-
var
|
|
30
|
+
var mergedRef = (0, _react.useCallback)(function (node) {
|
|
31
|
+
setOutsideClickTargetRef === null || setOutsideClickTargetRef === void 0 || setOutsideClickTargetRef(node);
|
|
32
|
+
if (contentRef) {
|
|
33
|
+
contentRef.current = node;
|
|
34
|
+
}
|
|
35
|
+
}, [setOutsideClickTargetRef, contentRef]);
|
|
28
36
|
return /*#__PURE__*/_react.default.createElement(_compiled.Box, {
|
|
29
|
-
ref:
|
|
37
|
+
ref: mergedRef,
|
|
30
38
|
xcss: styles.container,
|
|
31
39
|
onMouseDown: onMouseDown,
|
|
32
40
|
onMouseEnter: onMouseEnter
|
|
33
|
-
}, /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, {
|
|
34
|
-
title: intl.formatMessage(_messages.pasteOptionsToolbarMessages.pasteMenuActionsTitle)
|
|
35
41
|
}, /*#__PURE__*/_react.default.createElement(_editorUiControlModel.SurfaceRenderer, {
|
|
36
|
-
surface:
|
|
37
|
-
type: 'menu',
|
|
38
|
-
key: 'paste-menu'
|
|
39
|
-
},
|
|
42
|
+
surface: pasteMenuSurface,
|
|
40
43
|
components: components
|
|
41
|
-
}))
|
|
44
|
+
}));
|
|
42
45
|
};
|
|
@@ -16,12 +16,14 @@ var _hooks = require("@atlaskit/editor-common/hooks");
|
|
|
16
16
|
var _messages = require("@atlaskit/editor-common/messages");
|
|
17
17
|
var _toolbar = require("@atlaskit/editor-common/toolbar");
|
|
18
18
|
var _editorToolbar = require("@atlaskit/editor-toolbar");
|
|
19
|
+
var _chevronDown = _interopRequireDefault(require("@atlaskit/icon/core/chevron-down"));
|
|
19
20
|
var _chevronRight = _interopRequireDefault(require("@atlaskit/icon/core/chevron-right"));
|
|
20
21
|
var _clipboard = _interopRequireDefault(require("@atlaskit/icon/core/clipboard"));
|
|
21
22
|
var _compiled = require("@atlaskit/primitives/compiled");
|
|
22
23
|
var _commands = require("../../editor-commands/commands");
|
|
23
24
|
var _types = require("../../types/types");
|
|
24
25
|
var _hasVisibleButton = require("./hasVisibleButton");
|
|
26
|
+
var _PasteOptionsDropdownButton = require("./PasteOptionsDropdownButton");
|
|
25
27
|
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); }
|
|
26
28
|
var nestedMenuStyles = {
|
|
27
29
|
narrowSection: "_10gv1lit"
|
|
@@ -100,21 +102,49 @@ var PasteMenuItem = function PasteMenuItem(_ref) {
|
|
|
100
102
|
}, displayLabel);
|
|
101
103
|
};
|
|
102
104
|
var PasteOptionsNestedMenu = function PasteOptionsNestedMenu(_ref2) {
|
|
103
|
-
var children = _ref2.children
|
|
105
|
+
var children = _ref2.children,
|
|
106
|
+
hasVisibleAiActions = _ref2.hasVisibleAiActions;
|
|
104
107
|
var intl = (0, _reactIntlNext.useIntl)();
|
|
108
|
+
var label = intl.formatMessage(_messages.pasteOptionsToolbarMessages.pasteMenuActionsPasteAs);
|
|
109
|
+
if (!hasVisibleAiActions) {
|
|
110
|
+
return /*#__PURE__*/_react.default.createElement(_PasteOptionsDropdownButton.PasteOptionsDropdownButton, {
|
|
111
|
+
elemBefore: /*#__PURE__*/_react.default.createElement(_clipboard.default, {
|
|
112
|
+
size: "small",
|
|
113
|
+
label: ""
|
|
114
|
+
}),
|
|
115
|
+
elemAfter: /*#__PURE__*/_react.default.createElement(_chevronDown.default, {
|
|
116
|
+
size: "small",
|
|
117
|
+
label: ""
|
|
118
|
+
}),
|
|
119
|
+
label: label,
|
|
120
|
+
testId: "paste-options-nested-menu",
|
|
121
|
+
tooltipContent: label
|
|
122
|
+
}, children);
|
|
123
|
+
}
|
|
105
124
|
return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarNestedDropdownMenu, {
|
|
106
125
|
elemBefore: /*#__PURE__*/_react.default.createElement(_clipboard.default, {
|
|
107
126
|
size: "small",
|
|
108
|
-
label:
|
|
127
|
+
label: label
|
|
109
128
|
}),
|
|
110
129
|
elemAfter: /*#__PURE__*/_react.default.createElement(_chevronRight.default, {
|
|
111
130
|
size: "small",
|
|
112
|
-
label:
|
|
131
|
+
label: ""
|
|
113
132
|
}),
|
|
114
133
|
testId: "paste-options-nested-menu",
|
|
115
|
-
text:
|
|
134
|
+
text: label
|
|
116
135
|
}, children);
|
|
117
136
|
};
|
|
137
|
+
var getHasVisibleAiActions = function getHasVisibleAiActions(api) {
|
|
138
|
+
var _api$uiControlRegistr, _api$uiControlRegistr2;
|
|
139
|
+
var allComponents = (_api$uiControlRegistr = api === null || api === void 0 || (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(_toolbar.PASTE_MENU.key)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [];
|
|
140
|
+
var aiMenuItems = allComponents.filter(function (c) {
|
|
141
|
+
var _c$parents;
|
|
142
|
+
return c.type === 'menu-item' && ((_c$parents = c.parents) === null || _c$parents === void 0 ? void 0 : _c$parents.some(function (p) {
|
|
143
|
+
return p.key === _toolbar.AI_PASTE_MENU_SECTION.key;
|
|
144
|
+
}));
|
|
145
|
+
});
|
|
146
|
+
return (0, _hasVisibleButton.getVisibleKeys)(aiMenuItems, ['menu-item']).length > 0;
|
|
147
|
+
};
|
|
118
148
|
var getPasteMenuComponents = exports.getPasteMenuComponents = function getPasteMenuComponents(_ref3) {
|
|
119
149
|
var api = _ref3.api;
|
|
120
150
|
return [{
|
|
@@ -134,17 +164,14 @@ var getPasteMenuComponents = exports.getPasteMenuComponents = function getPasteM
|
|
|
134
164
|
return !((_pluginState$showLega = pluginState === null || pluginState === void 0 ? void 0 : pluginState.showLegacyOptions) !== null && _pluginState$showLega !== void 0 ? _pluginState$showLega : false);
|
|
135
165
|
},
|
|
136
166
|
component: function component(props) {
|
|
137
|
-
var
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}));
|
|
144
|
-
});
|
|
145
|
-
var hasVisibleAiActions = (0, _hasVisibleButton.getVisibleKeys)(aiMenuItems, ['menu-item']).length > 0;
|
|
167
|
+
var hasVisibleAiActions = getHasVisibleAiActions(api);
|
|
168
|
+
if (!hasVisibleAiActions) {
|
|
169
|
+
return /*#__PURE__*/_react.default.createElement(_compiled.Box, {
|
|
170
|
+
padding: "space.050"
|
|
171
|
+
}, props.children);
|
|
172
|
+
}
|
|
146
173
|
return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, {
|
|
147
|
-
hasSeparator:
|
|
174
|
+
hasSeparator: true
|
|
148
175
|
}, props.children);
|
|
149
176
|
}
|
|
150
177
|
}, {
|
|
@@ -156,7 +183,10 @@ var getPasteMenuComponents = exports.getPasteMenuComponents = function getPasteM
|
|
|
156
183
|
rank: _toolbar.PASTE_MENU_SECTION_RANK[_toolbar.PASTE_NESTED_MENU.key]
|
|
157
184
|
}],
|
|
158
185
|
component: function component(props) {
|
|
159
|
-
|
|
186
|
+
var hasVisibleAiActions = getHasVisibleAiActions(api);
|
|
187
|
+
return /*#__PURE__*/_react.default.createElement(PasteOptionsNestedMenu, {
|
|
188
|
+
hasVisibleAiActions: hasVisibleAiActions
|
|
189
|
+
}, props.children);
|
|
160
190
|
}
|
|
161
191
|
}, {
|
|
162
192
|
type: _toolbar.PASTE_MENU_NESTED_SECTION.type,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* PasteOptionsDropdownButton.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
5
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
6
|
+
Object.defineProperty(exports, "__esModule", {
|
|
7
|
+
value: true
|
|
8
|
+
});
|
|
9
|
+
exports.PasteOptionsDropdownButton = void 0;
|
|
10
|
+
var _runtime = require("@compiled/react/runtime");
|
|
11
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
12
|
+
var _dropdownMenu = _interopRequireDefault(require("@atlaskit/dropdown-menu"));
|
|
13
|
+
var _editorToolbar = require("@atlaskit/editor-toolbar");
|
|
14
|
+
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); }
|
|
15
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
16
|
+
/**
|
|
17
|
+
* A compact dropdown button for paste options, styled like floating toolbar buttons.
|
|
18
|
+
* Renders as a ToolbarButton with an icon and dropdown caret that opens a
|
|
19
|
+
* dropdown menu below. Used when AI actions are not visible and the paste
|
|
20
|
+
* options menu is the only content.
|
|
21
|
+
*/
|
|
22
|
+
var PasteOptionsDropdownButton = exports.PasteOptionsDropdownButton = function PasteOptionsDropdownButton(_ref) {
|
|
23
|
+
var children = _ref.children,
|
|
24
|
+
elemBefore = _ref.elemBefore,
|
|
25
|
+
elemAfter = _ref.elemAfter,
|
|
26
|
+
label = _ref.label,
|
|
27
|
+
testId = _ref.testId,
|
|
28
|
+
tooltipContent = _ref.tooltipContent;
|
|
29
|
+
var trigger = (0, _react.useCallback)(function (triggerProps) {
|
|
30
|
+
var button = /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarButton, {
|
|
31
|
+
ref: triggerProps.triggerRef,
|
|
32
|
+
isSelected: triggerProps.isSelected,
|
|
33
|
+
"aria-expanded": triggerProps['aria-expanded'],
|
|
34
|
+
"aria-haspopup": triggerProps['aria-haspopup'],
|
|
35
|
+
onClick: triggerProps.onClick,
|
|
36
|
+
testId: testId,
|
|
37
|
+
iconBefore: elemBefore,
|
|
38
|
+
label: label
|
|
39
|
+
}, elemAfter);
|
|
40
|
+
if (tooltipContent) {
|
|
41
|
+
return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarTooltip, {
|
|
42
|
+
content: tooltipContent,
|
|
43
|
+
position: "top"
|
|
44
|
+
}, button);
|
|
45
|
+
}
|
|
46
|
+
return button;
|
|
47
|
+
}, [testId, elemBefore, elemAfter, label, tooltipContent]);
|
|
48
|
+
return /*#__PURE__*/_react.default.createElement(_dropdownMenu.default, {
|
|
49
|
+
placement: "bottom-start",
|
|
50
|
+
trigger: trigger
|
|
51
|
+
}, children);
|
|
52
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef } from 'react';
|
|
2
2
|
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
3
3
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
4
|
-
import { EditorToolbarProvider, PASTE_MENU } from '@atlaskit/editor-common/toolbar';
|
|
4
|
+
import { AI_PASTE_MENU_SECTION, EditorToolbarProvider, PASTE_MENU } from '@atlaskit/editor-common/toolbar';
|
|
5
5
|
import { findOverflowScrollParent, Popup } from '@atlaskit/editor-common/ui';
|
|
6
6
|
import { withReactEditorViewOuterListeners } from '@atlaskit/editor-common/ui-react';
|
|
7
7
|
import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
|
|
@@ -101,6 +101,36 @@ export function findBlockAncestorDOM(editorView, pos) {
|
|
|
101
101
|
return null;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Positions the paste menu inline, immediately to the right of the cursor
|
|
106
|
+
* at the paste end position, vertically centered with the line.
|
|
107
|
+
* Used for short pastes without AI actions.
|
|
108
|
+
*/
|
|
109
|
+
export function onInlinePositionCalculated(editorView, pasteEndPos, targetElement, popupContentRef) {
|
|
110
|
+
return position => {
|
|
111
|
+
var _popupContentRef$curr, _popupContentRef$curr2, _position$top, _position$left;
|
|
112
|
+
const endCoords = editorView.coordsAtPos(pasteEndPos);
|
|
113
|
+
const targetRect = targetElement.getBoundingClientRect();
|
|
114
|
+
|
|
115
|
+
// Vertical: center the menu with the line at the paste end position.
|
|
116
|
+
const lineHeight = endCoords.bottom - endCoords.top;
|
|
117
|
+
const lineMidpoint = endCoords.top + lineHeight / 2;
|
|
118
|
+
const menuHeight = (_popupContentRef$curr = (_popupContentRef$curr2 = popupContentRef.current) === null || _popupContentRef$curr2 === void 0 ? void 0 : _popupContentRef$curr2.getBoundingClientRect().height) !== null && _popupContentRef$curr !== void 0 ? _popupContentRef$curr : lineHeight;
|
|
119
|
+
const menuTop = lineMidpoint - menuHeight / 2;
|
|
120
|
+
const topDelta = menuTop - (targetRect.top + targetRect.height);
|
|
121
|
+
const adjustedTop = ((_position$top = position.top) !== null && _position$top !== void 0 ? _position$top : 0) + topDelta;
|
|
122
|
+
|
|
123
|
+
// Horizontal: position to the right of the cursor
|
|
124
|
+
const leftDelta = endCoords.right - targetRect.right;
|
|
125
|
+
const adjustedLeft = ((_position$left = position.left) !== null && _position$left !== void 0 ? _position$left : 0) + leftDelta;
|
|
126
|
+
return {
|
|
127
|
+
...position,
|
|
128
|
+
top: adjustedTop,
|
|
129
|
+
left: adjustedLeft
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
104
134
|
/**
|
|
105
135
|
* Adjusts the position of the paste menu so that:
|
|
106
136
|
*
|
|
@@ -131,7 +161,7 @@ export function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, tar
|
|
|
131
161
|
const tableAfterPos = resolveTableAfterPos(editorView, pasteEndPos);
|
|
132
162
|
const blockAncestorDOM = findBlockAncestorDOM(editorView, pasteStartPos);
|
|
133
163
|
return position => {
|
|
134
|
-
var _position$
|
|
164
|
+
var _position$top2;
|
|
135
165
|
const startCoords = editorView.coordsAtPos(pasteStartPos);
|
|
136
166
|
const endBottom = getVisualEndBottom(editorView, pasteEndPos, tableAfterPos);
|
|
137
167
|
const targetRect = targetElement.getBoundingClientRect();
|
|
@@ -141,7 +171,7 @@ export function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, tar
|
|
|
141
171
|
// We shift it up so it aligns with the paste start position.
|
|
142
172
|
// Both coordinates are in viewport space, so the delta is offset-parent agnostic.
|
|
143
173
|
const topDelta = startCoords.top - (targetRect.top + targetRect.height);
|
|
144
|
-
let adjustedTop = ((_position$
|
|
174
|
+
let adjustedTop = ((_position$top2 = position.top) !== null && _position$top2 !== void 0 ? _position$top2 : 0) + topDelta;
|
|
145
175
|
|
|
146
176
|
// Sticky-top: clamp to the scroll container's top edge when the paste
|
|
147
177
|
// start has scrolled above the visible area, but only while some pasted
|
|
@@ -163,13 +193,13 @@ export function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, tar
|
|
|
163
193
|
// re-anchoring to its right edge.
|
|
164
194
|
let adjustedLeft = position.left;
|
|
165
195
|
if (blockAncestorDOM && blockAncestorDOM !== targetElement) {
|
|
166
|
-
var _position$
|
|
196
|
+
var _position$left2;
|
|
167
197
|
const blockRect = blockAncestorDOM.getBoundingClientRect();
|
|
168
198
|
// Shift left by the difference between the block's right edge and
|
|
169
199
|
// the inline target's right edge. This mirrors what alignX="end"
|
|
170
200
|
// would have computed if the target were the block element.
|
|
171
201
|
const leftDelta = blockRect.right - targetRect.right;
|
|
172
|
-
adjustedLeft = ((_position$
|
|
202
|
+
adjustedLeft = ((_position$left2 = position.left) !== null && _position$left2 !== void 0 ? _position$left2 : 0) + leftDelta;
|
|
173
203
|
}
|
|
174
204
|
return {
|
|
175
205
|
...position,
|
|
@@ -196,8 +226,8 @@ export const PasteActionsMenu = ({
|
|
|
196
226
|
};
|
|
197
227
|
});
|
|
198
228
|
const prevShowToolbarRef = useRef(false);
|
|
229
|
+
const popupContentRef = useRef(null);
|
|
199
230
|
useEffect(() => {
|
|
200
|
-
var _lastContentPasted$te, _lastContentPasted$te2;
|
|
201
231
|
if (!lastContentPasted) {
|
|
202
232
|
hideToolbar()(editorView.state, editorView.dispatch);
|
|
203
233
|
return;
|
|
@@ -220,7 +250,7 @@ export const PasteActionsMenu = ({
|
|
|
220
250
|
pasteAncestorNodeNames.push($pos.node(depth).type.name);
|
|
221
251
|
}
|
|
222
252
|
}
|
|
223
|
-
const legacyVisible = isToolbarVisible(editorView.state, lastContentPasted)
|
|
253
|
+
const legacyVisible = isToolbarVisible(editorView.state, lastContentPasted);
|
|
224
254
|
showToolbar(lastContentPasted, selectedOption, legacyVisible, pasteAncestorNodeNames)(editorView.state, editorView.dispatch);
|
|
225
255
|
}, [lastContentPasted, editorView]);
|
|
226
256
|
const {
|
|
@@ -285,16 +315,34 @@ export const PasteActionsMenu = ({
|
|
|
285
315
|
const effectiveScrollableElement = overflowScrollParent || scrollableElement;
|
|
286
316
|
const pasteMenuComponents = (_api$uiControlRegistr3 = api === null || api === void 0 ? void 0 : (_api$uiControlRegistr4 = api.uiControlRegistry) === null || _api$uiControlRegistr4 === void 0 ? void 0 : _api$uiControlRegistr4.actions.getComponents(PASTE_MENU.key)) !== null && _api$uiControlRegistr3 !== void 0 ? _api$uiControlRegistr3 : [];
|
|
287
317
|
const anyComponentVisible = hasVisibleButton(pasteMenuComponents);
|
|
318
|
+
|
|
319
|
+
// Two positioning modes:
|
|
320
|
+
// 1. Inline: no AI actions visible — menu appears to the right of the cursor,
|
|
321
|
+
// vertically centered with the text line.
|
|
322
|
+
// 2. Block-anchored: AI actions are visible — menu appears at the right edge
|
|
323
|
+
// of the content block, aligned with paste start.
|
|
324
|
+
const hasVisibleAiActions = getVisibleKeys(
|
|
325
|
+
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- pasteMenuComponents changes by reference each render; filter is small (< 10 items)
|
|
326
|
+
pasteMenuComponents.filter(c => {
|
|
327
|
+
var _c$parents;
|
|
328
|
+
return c.type === 'menu-item' && ((_c$parents = c.parents) === null || _c$parents === void 0 ? void 0 : _c$parents.some(p => p.key === AI_PASTE_MENU_SECTION.key));
|
|
329
|
+
}), ['menu-item']).length > 0;
|
|
330
|
+
const useInlinePosition = !hasVisibleAiActions;
|
|
288
331
|
if (!isToolbarShown) {
|
|
289
332
|
return null;
|
|
290
333
|
}
|
|
291
334
|
if (!anyComponentVisible) {
|
|
292
335
|
return null;
|
|
293
336
|
}
|
|
294
|
-
const target = getTargetElement(editorView, pasteStartPos);
|
|
337
|
+
const target = getTargetElement(editorView, useInlinePosition ? pasteEndPos : pasteStartPos);
|
|
295
338
|
if (!target) {
|
|
296
339
|
return null;
|
|
297
340
|
}
|
|
341
|
+
|
|
342
|
+
// Choose positioning strategy based on whether the menu appears inline
|
|
343
|
+
// (right of cursor for short pastes) or anchored to the block ancestor
|
|
344
|
+
// (right side of content area for longer pastes / AI actions).
|
|
345
|
+
const positionCalculator = useInlinePosition ? onInlinePositionCalculated(editorView, pasteEndPos, target, popupContentRef) : onPositionCalculated(editorView, pasteStartPos, pasteEndPos, target, effectiveScrollableElement);
|
|
298
346
|
return /*#__PURE__*/React.createElement(PopupWithListeners, {
|
|
299
347
|
target: target,
|
|
300
348
|
mountTo: mountTo,
|
|
@@ -303,10 +351,10 @@ export const PasteActionsMenu = ({
|
|
|
303
351
|
minPopupMargin: PASTE_MENU_GAP_HORIZONTAL,
|
|
304
352
|
zIndex: akEditorFloatingPanelZIndex,
|
|
305
353
|
alignX: "end",
|
|
306
|
-
alignY:
|
|
354
|
+
alignY: useInlinePosition ? 'top' : 'bottom'
|
|
307
355
|
/* eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) */,
|
|
308
356
|
offset: [PASTE_MENU_GAP_HORIZONTAL, 0],
|
|
309
|
-
onPositionCalculated:
|
|
357
|
+
onPositionCalculated: positionCalculator,
|
|
310
358
|
handleClickOutside: handleClickOutside,
|
|
311
359
|
handleEscapeKeydown: handleDismiss
|
|
312
360
|
}, /*#__PURE__*/React.createElement(EditorToolbarProvider, {
|
|
@@ -317,6 +365,7 @@ export const PasteActionsMenu = ({
|
|
|
317
365
|
}, /*#__PURE__*/React.createElement(PasteActionsMenuContent, {
|
|
318
366
|
onMouseDown: preventEditorFocusLoss,
|
|
319
367
|
onMouseEnter: handleMouseEnter,
|
|
320
|
-
components: pasteMenuComponents
|
|
368
|
+
components: pasteMenuComponents,
|
|
369
|
+
contentRef: popupContentRef
|
|
321
370
|
}))));
|
|
322
371
|
};
|
|
@@ -1,35 +1,38 @@
|
|
|
1
1
|
/* PasteActionsMenuContent.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
2
|
import "./PasteActionsMenuContent.compiled.css";
|
|
3
3
|
import { ax, ix } from "@compiled/react/runtime";
|
|
4
|
-
import React, { useContext } from 'react';
|
|
5
|
-
import {
|
|
6
|
-
import { pasteOptionsToolbarMessages as messages } from '@atlaskit/editor-common/messages';
|
|
4
|
+
import React, { useCallback, useContext } from 'react';
|
|
5
|
+
import { PASTE_MENU } from '@atlaskit/editor-common/toolbar';
|
|
7
6
|
import { OutsideClickTargetRefContext } from '@atlaskit/editor-common/ui-react';
|
|
8
|
-
import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
|
|
9
7
|
import { SurfaceRenderer } from '@atlaskit/editor-ui-control-model';
|
|
10
8
|
import { Box } from '@atlaskit/primitives/compiled';
|
|
11
9
|
const styles = {
|
|
12
10
|
container: "_2rko12b0 _bfhk1bhr _16qs130s"
|
|
13
11
|
};
|
|
12
|
+
const pasteMenuSurface = {
|
|
13
|
+
type: PASTE_MENU.type,
|
|
14
|
+
key: PASTE_MENU.key
|
|
15
|
+
};
|
|
14
16
|
export const PasteActionsMenuContent = ({
|
|
15
17
|
onMouseDown,
|
|
16
18
|
onMouseEnter,
|
|
17
|
-
components
|
|
19
|
+
components,
|
|
20
|
+
contentRef
|
|
18
21
|
}) => {
|
|
19
22
|
const setOutsideClickTargetRef = useContext(OutsideClickTargetRefContext);
|
|
20
|
-
const
|
|
23
|
+
const mergedRef = useCallback(node => {
|
|
24
|
+
setOutsideClickTargetRef === null || setOutsideClickTargetRef === void 0 ? void 0 : setOutsideClickTargetRef(node);
|
|
25
|
+
if (contentRef) {
|
|
26
|
+
contentRef.current = node;
|
|
27
|
+
}
|
|
28
|
+
}, [setOutsideClickTargetRef, contentRef]);
|
|
21
29
|
return /*#__PURE__*/React.createElement(Box, {
|
|
22
|
-
ref:
|
|
30
|
+
ref: mergedRef,
|
|
23
31
|
xcss: styles.container,
|
|
24
32
|
onMouseDown: onMouseDown,
|
|
25
33
|
onMouseEnter: onMouseEnter
|
|
26
|
-
}, /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
|
|
27
|
-
title: intl.formatMessage(messages.pasteMenuActionsTitle)
|
|
28
34
|
}, /*#__PURE__*/React.createElement(SurfaceRenderer, {
|
|
29
|
-
surface:
|
|
30
|
-
type: 'menu',
|
|
31
|
-
key: 'paste-menu'
|
|
32
|
-
},
|
|
35
|
+
surface: pasteMenuSurface,
|
|
33
36
|
components: components
|
|
34
|
-
}))
|
|
37
|
+
}));
|
|
35
38
|
};
|
|
@@ -8,12 +8,14 @@ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'
|
|
|
8
8
|
import { pasteOptionsToolbarMessages as messages } from '@atlaskit/editor-common/messages';
|
|
9
9
|
import { useEditorToolbar, PASTE_MENU, PASTE_MENU_SECTION, PASTE_NESTED_MENU, PASTE_MENU_NESTED_SECTION, PASTE_RICH_TEXT_MENU_ITEM, PASTE_MARKDOWN_MENU_ITEM, PASTE_PLAIN_TEXT_MENU_ITEM, PASTE_MENU_RANK, PASTE_MENU_SECTION_RANK, PASTE_NESTED_MENU_RANK, PASTE_MENU_NESTED_SECTION_RANK, AI_PASTE_MENU_SECTION } from '@atlaskit/editor-common/toolbar';
|
|
10
10
|
import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
|
|
11
|
+
import ChevronDownIcon from '@atlaskit/icon/core/chevron-down';
|
|
11
12
|
import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
|
|
12
13
|
import ClipboardIcon from '@atlaskit/icon/core/clipboard';
|
|
13
14
|
import { Box } from '@atlaskit/primitives/compiled';
|
|
14
15
|
import { changeToMarkdownWithAnalytics, changeToPlainTextWithAnalytics, changeToRichTextWithAnalytics } from '../../editor-commands/commands';
|
|
15
16
|
import { ToolbarDropdownOption } from '../../types/types';
|
|
16
17
|
import { getVisibleKeys } from './hasVisibleButton';
|
|
18
|
+
import { PasteOptionsDropdownButton } from './PasteOptionsDropdownButton';
|
|
17
19
|
const nestedMenuStyles = {
|
|
18
20
|
narrowSection: "_10gv1lit"
|
|
19
21
|
};
|
|
@@ -94,22 +96,48 @@ const PasteMenuItem = ({
|
|
|
94
96
|
}, displayLabel);
|
|
95
97
|
};
|
|
96
98
|
const PasteOptionsNestedMenu = ({
|
|
97
|
-
children
|
|
99
|
+
children,
|
|
100
|
+
hasVisibleAiActions
|
|
98
101
|
}) => {
|
|
99
102
|
const intl = useIntl();
|
|
103
|
+
const label = intl.formatMessage(messages.pasteMenuActionsPasteAs);
|
|
104
|
+
if (!hasVisibleAiActions) {
|
|
105
|
+
return /*#__PURE__*/React.createElement(PasteOptionsDropdownButton, {
|
|
106
|
+
elemBefore: /*#__PURE__*/React.createElement(ClipboardIcon, {
|
|
107
|
+
size: "small",
|
|
108
|
+
label: ""
|
|
109
|
+
}),
|
|
110
|
+
elemAfter: /*#__PURE__*/React.createElement(ChevronDownIcon, {
|
|
111
|
+
size: "small",
|
|
112
|
+
label: ""
|
|
113
|
+
}),
|
|
114
|
+
label: label,
|
|
115
|
+
testId: "paste-options-nested-menu",
|
|
116
|
+
tooltipContent: label
|
|
117
|
+
}, children);
|
|
118
|
+
}
|
|
100
119
|
return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
|
|
101
120
|
elemBefore: /*#__PURE__*/React.createElement(ClipboardIcon, {
|
|
102
121
|
size: "small",
|
|
103
|
-
label:
|
|
122
|
+
label: label
|
|
104
123
|
}),
|
|
105
124
|
elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
|
|
106
125
|
size: "small",
|
|
107
|
-
label:
|
|
126
|
+
label: ""
|
|
108
127
|
}),
|
|
109
128
|
testId: "paste-options-nested-menu",
|
|
110
|
-
text:
|
|
129
|
+
text: label
|
|
111
130
|
}, children);
|
|
112
131
|
};
|
|
132
|
+
const getHasVisibleAiActions = api => {
|
|
133
|
+
var _api$uiControlRegistr, _api$uiControlRegistr2;
|
|
134
|
+
const allComponents = (_api$uiControlRegistr = api === null || api === void 0 ? void 0 : (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(PASTE_MENU.key)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [];
|
|
135
|
+
const aiMenuItems = allComponents.filter(c => {
|
|
136
|
+
var _c$parents;
|
|
137
|
+
return c.type === 'menu-item' && ((_c$parents = c.parents) === null || _c$parents === void 0 ? void 0 : _c$parents.some(p => p.key === AI_PASTE_MENU_SECTION.key));
|
|
138
|
+
});
|
|
139
|
+
return getVisibleKeys(aiMenuItems, ['menu-item']).length > 0;
|
|
140
|
+
};
|
|
113
141
|
export const getPasteMenuComponents = ({
|
|
114
142
|
api
|
|
115
143
|
}) => [{
|
|
@@ -129,15 +157,14 @@ export const getPasteMenuComponents = ({
|
|
|
129
157
|
return !((_pluginState$showLega = pluginState === null || pluginState === void 0 ? void 0 : pluginState.showLegacyOptions) !== null && _pluginState$showLega !== void 0 ? _pluginState$showLega : false);
|
|
130
158
|
},
|
|
131
159
|
component: props => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
const hasVisibleAiActions = getVisibleKeys(aiMenuItems, ['menu-item']).length > 0;
|
|
160
|
+
const hasVisibleAiActions = getHasVisibleAiActions(api);
|
|
161
|
+
if (!hasVisibleAiActions) {
|
|
162
|
+
return /*#__PURE__*/React.createElement(Box, {
|
|
163
|
+
padding: "space.050"
|
|
164
|
+
}, props.children);
|
|
165
|
+
}
|
|
139
166
|
return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
|
|
140
|
-
hasSeparator:
|
|
167
|
+
hasSeparator: true
|
|
141
168
|
}, props.children);
|
|
142
169
|
}
|
|
143
170
|
}, {
|
|
@@ -148,7 +175,12 @@ export const getPasteMenuComponents = ({
|
|
|
148
175
|
key: PASTE_MENU_SECTION.key,
|
|
149
176
|
rank: PASTE_MENU_SECTION_RANK[PASTE_NESTED_MENU.key]
|
|
150
177
|
}],
|
|
151
|
-
component: props =>
|
|
178
|
+
component: props => {
|
|
179
|
+
const hasVisibleAiActions = getHasVisibleAiActions(api);
|
|
180
|
+
return /*#__PURE__*/React.createElement(PasteOptionsNestedMenu, {
|
|
181
|
+
hasVisibleAiActions: hasVisibleAiActions
|
|
182
|
+
}, props.children);
|
|
183
|
+
}
|
|
152
184
|
}, {
|
|
153
185
|
type: PASTE_MENU_NESTED_SECTION.type,
|
|
154
186
|
key: PASTE_MENU_NESTED_SECTION.key,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* PasteOptionsDropdownButton.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
|
+
import { ax, ix } from "@compiled/react/runtime";
|
|
3
|
+
import React, { useCallback } from 'react';
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
6
|
+
|
|
7
|
+
import DropdownMenu from '@atlaskit/dropdown-menu';
|
|
8
|
+
import { ToolbarButton, ToolbarTooltip } from '@atlaskit/editor-toolbar';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A compact dropdown button for paste options, styled like floating toolbar buttons.
|
|
12
|
+
* Renders as a ToolbarButton with an icon and dropdown caret that opens a
|
|
13
|
+
* dropdown menu below. Used when AI actions are not visible and the paste
|
|
14
|
+
* options menu is the only content.
|
|
15
|
+
*/
|
|
16
|
+
export const PasteOptionsDropdownButton = ({
|
|
17
|
+
children,
|
|
18
|
+
elemBefore,
|
|
19
|
+
elemAfter,
|
|
20
|
+
label,
|
|
21
|
+
testId,
|
|
22
|
+
tooltipContent
|
|
23
|
+
}) => {
|
|
24
|
+
const trigger = useCallback(triggerProps => {
|
|
25
|
+
const button = /*#__PURE__*/React.createElement(ToolbarButton, {
|
|
26
|
+
ref: triggerProps.triggerRef,
|
|
27
|
+
isSelected: triggerProps.isSelected,
|
|
28
|
+
"aria-expanded": triggerProps['aria-expanded'],
|
|
29
|
+
"aria-haspopup": triggerProps['aria-haspopup'],
|
|
30
|
+
onClick: triggerProps.onClick,
|
|
31
|
+
testId: testId,
|
|
32
|
+
iconBefore: elemBefore,
|
|
33
|
+
label: label
|
|
34
|
+
}, elemAfter);
|
|
35
|
+
if (tooltipContent) {
|
|
36
|
+
return /*#__PURE__*/React.createElement(ToolbarTooltip, {
|
|
37
|
+
content: tooltipContent,
|
|
38
|
+
position: "top"
|
|
39
|
+
}, button);
|
|
40
|
+
}
|
|
41
|
+
return button;
|
|
42
|
+
}, [testId, elemBefore, elemAfter, label, tooltipContent]);
|
|
43
|
+
return /*#__PURE__*/React.createElement(DropdownMenu, {
|
|
44
|
+
placement: "bottom-start",
|
|
45
|
+
trigger: trigger
|
|
46
|
+
}, children);
|
|
47
|
+
};
|
|
@@ -4,7 +4,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
4
4
|
import React, { useCallback, useEffect, useRef } from 'react';
|
|
5
5
|
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
6
6
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
7
|
-
import { EditorToolbarProvider, PASTE_MENU } from '@atlaskit/editor-common/toolbar';
|
|
7
|
+
import { AI_PASTE_MENU_SECTION, EditorToolbarProvider, PASTE_MENU } from '@atlaskit/editor-common/toolbar';
|
|
8
8
|
import { findOverflowScrollParent, Popup } from '@atlaskit/editor-common/ui';
|
|
9
9
|
import { withReactEditorViewOuterListeners } from '@atlaskit/editor-common/ui-react';
|
|
10
10
|
import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
|
|
@@ -104,6 +104,35 @@ export function findBlockAncestorDOM(editorView, pos) {
|
|
|
104
104
|
return null;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Positions the paste menu inline, immediately to the right of the cursor
|
|
109
|
+
* at the paste end position, vertically centered with the line.
|
|
110
|
+
* Used for short pastes without AI actions.
|
|
111
|
+
*/
|
|
112
|
+
export function onInlinePositionCalculated(editorView, pasteEndPos, targetElement, popupContentRef) {
|
|
113
|
+
return function (position) {
|
|
114
|
+
var _popupContentRef$curr, _popupContentRef$curr2, _position$top, _position$left;
|
|
115
|
+
var endCoords = editorView.coordsAtPos(pasteEndPos);
|
|
116
|
+
var targetRect = targetElement.getBoundingClientRect();
|
|
117
|
+
|
|
118
|
+
// Vertical: center the menu with the line at the paste end position.
|
|
119
|
+
var lineHeight = endCoords.bottom - endCoords.top;
|
|
120
|
+
var lineMidpoint = endCoords.top + lineHeight / 2;
|
|
121
|
+
var menuHeight = (_popupContentRef$curr = (_popupContentRef$curr2 = popupContentRef.current) === null || _popupContentRef$curr2 === void 0 ? void 0 : _popupContentRef$curr2.getBoundingClientRect().height) !== null && _popupContentRef$curr !== void 0 ? _popupContentRef$curr : lineHeight;
|
|
122
|
+
var menuTop = lineMidpoint - menuHeight / 2;
|
|
123
|
+
var topDelta = menuTop - (targetRect.top + targetRect.height);
|
|
124
|
+
var adjustedTop = ((_position$top = position.top) !== null && _position$top !== void 0 ? _position$top : 0) + topDelta;
|
|
125
|
+
|
|
126
|
+
// Horizontal: position to the right of the cursor
|
|
127
|
+
var leftDelta = endCoords.right - targetRect.right;
|
|
128
|
+
var adjustedLeft = ((_position$left = position.left) !== null && _position$left !== void 0 ? _position$left : 0) + leftDelta;
|
|
129
|
+
return _objectSpread(_objectSpread({}, position), {}, {
|
|
130
|
+
top: adjustedTop,
|
|
131
|
+
left: adjustedLeft
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
107
136
|
/**
|
|
108
137
|
* Adjusts the position of the paste menu so that:
|
|
109
138
|
*
|
|
@@ -134,7 +163,7 @@ export function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, tar
|
|
|
134
163
|
var tableAfterPos = resolveTableAfterPos(editorView, pasteEndPos);
|
|
135
164
|
var blockAncestorDOM = findBlockAncestorDOM(editorView, pasteStartPos);
|
|
136
165
|
return function (position) {
|
|
137
|
-
var _position$
|
|
166
|
+
var _position$top2;
|
|
138
167
|
var startCoords = editorView.coordsAtPos(pasteStartPos);
|
|
139
168
|
var endBottom = getVisualEndBottom(editorView, pasteEndPos, tableAfterPos);
|
|
140
169
|
var targetRect = targetElement.getBoundingClientRect();
|
|
@@ -144,7 +173,7 @@ export function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, tar
|
|
|
144
173
|
// We shift it up so it aligns with the paste start position.
|
|
145
174
|
// Both coordinates are in viewport space, so the delta is offset-parent agnostic.
|
|
146
175
|
var topDelta = startCoords.top - (targetRect.top + targetRect.height);
|
|
147
|
-
var adjustedTop = ((_position$
|
|
176
|
+
var adjustedTop = ((_position$top2 = position.top) !== null && _position$top2 !== void 0 ? _position$top2 : 0) + topDelta;
|
|
148
177
|
|
|
149
178
|
// Sticky-top: clamp to the scroll container's top edge when the paste
|
|
150
179
|
// start has scrolled above the visible area, but only while some pasted
|
|
@@ -166,13 +195,13 @@ export function onPositionCalculated(editorView, pasteStartPos, pasteEndPos, tar
|
|
|
166
195
|
// re-anchoring to its right edge.
|
|
167
196
|
var adjustedLeft = position.left;
|
|
168
197
|
if (blockAncestorDOM && blockAncestorDOM !== targetElement) {
|
|
169
|
-
var _position$
|
|
198
|
+
var _position$left2;
|
|
170
199
|
var blockRect = blockAncestorDOM.getBoundingClientRect();
|
|
171
200
|
// Shift left by the difference between the block's right edge and
|
|
172
201
|
// the inline target's right edge. This mirrors what alignX="end"
|
|
173
202
|
// would have computed if the target were the block element.
|
|
174
203
|
var leftDelta = blockRect.right - targetRect.right;
|
|
175
|
-
adjustedLeft = ((_position$
|
|
204
|
+
adjustedLeft = ((_position$left2 = position.left) !== null && _position$left2 !== void 0 ? _position$left2 : 0) + leftDelta;
|
|
176
205
|
}
|
|
177
206
|
return _objectSpread(_objectSpread({}, position), {}, {
|
|
178
207
|
top: adjustedTop,
|
|
@@ -196,8 +225,8 @@ export var PasteActionsMenu = function PasteActionsMenu(_ref) {
|
|
|
196
225
|
}),
|
|
197
226
|
lastContentPasted = _useSharedPluginState.lastContentPasted;
|
|
198
227
|
var prevShowToolbarRef = useRef(false);
|
|
228
|
+
var popupContentRef = useRef(null);
|
|
199
229
|
useEffect(function () {
|
|
200
|
-
var _lastContentPasted$te, _lastContentPasted$te2;
|
|
201
230
|
if (!lastContentPasted) {
|
|
202
231
|
hideToolbar()(editorView.state, editorView.dispatch);
|
|
203
232
|
return;
|
|
@@ -220,7 +249,7 @@ export var PasteActionsMenu = function PasteActionsMenu(_ref) {
|
|
|
220
249
|
pasteAncestorNodeNames.push($pos.node(depth).type.name);
|
|
221
250
|
}
|
|
222
251
|
}
|
|
223
|
-
var legacyVisible = isToolbarVisible(editorView.state, lastContentPasted)
|
|
252
|
+
var legacyVisible = isToolbarVisible(editorView.state, lastContentPasted);
|
|
224
253
|
showToolbar(lastContentPasted, selectedOption, legacyVisible, pasteAncestorNodeNames)(editorView.state, editorView.dispatch);
|
|
225
254
|
}, [lastContentPasted, editorView]);
|
|
226
255
|
var _useSharedPluginState2 = useSharedPluginStateWithSelector(api, ['pasteOptionsToolbarPlugin'], function (states) {
|
|
@@ -284,16 +313,36 @@ export var PasteActionsMenu = function PasteActionsMenu(_ref) {
|
|
|
284
313
|
var effectiveScrollableElement = overflowScrollParent || scrollableElement;
|
|
285
314
|
var pasteMenuComponents = (_api$uiControlRegistr3 = api === null || api === void 0 || (_api$uiControlRegistr4 = api.uiControlRegistry) === null || _api$uiControlRegistr4 === void 0 ? void 0 : _api$uiControlRegistr4.actions.getComponents(PASTE_MENU.key)) !== null && _api$uiControlRegistr3 !== void 0 ? _api$uiControlRegistr3 : [];
|
|
286
315
|
var anyComponentVisible = hasVisibleButton(pasteMenuComponents);
|
|
316
|
+
|
|
317
|
+
// Two positioning modes:
|
|
318
|
+
// 1. Inline: no AI actions visible — menu appears to the right of the cursor,
|
|
319
|
+
// vertically centered with the text line.
|
|
320
|
+
// 2. Block-anchored: AI actions are visible — menu appears at the right edge
|
|
321
|
+
// of the content block, aligned with paste start.
|
|
322
|
+
var hasVisibleAiActions = getVisibleKeys(
|
|
323
|
+
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- pasteMenuComponents changes by reference each render; filter is small (< 10 items)
|
|
324
|
+
pasteMenuComponents.filter(function (c) {
|
|
325
|
+
var _c$parents;
|
|
326
|
+
return c.type === 'menu-item' && ((_c$parents = c.parents) === null || _c$parents === void 0 ? void 0 : _c$parents.some(function (p) {
|
|
327
|
+
return p.key === AI_PASTE_MENU_SECTION.key;
|
|
328
|
+
}));
|
|
329
|
+
}), ['menu-item']).length > 0;
|
|
330
|
+
var useInlinePosition = !hasVisibleAiActions;
|
|
287
331
|
if (!isToolbarShown) {
|
|
288
332
|
return null;
|
|
289
333
|
}
|
|
290
334
|
if (!anyComponentVisible) {
|
|
291
335
|
return null;
|
|
292
336
|
}
|
|
293
|
-
var target = getTargetElement(editorView, pasteStartPos);
|
|
337
|
+
var target = getTargetElement(editorView, useInlinePosition ? pasteEndPos : pasteStartPos);
|
|
294
338
|
if (!target) {
|
|
295
339
|
return null;
|
|
296
340
|
}
|
|
341
|
+
|
|
342
|
+
// Choose positioning strategy based on whether the menu appears inline
|
|
343
|
+
// (right of cursor for short pastes) or anchored to the block ancestor
|
|
344
|
+
// (right side of content area for longer pastes / AI actions).
|
|
345
|
+
var positionCalculator = useInlinePosition ? onInlinePositionCalculated(editorView, pasteEndPos, target, popupContentRef) : onPositionCalculated(editorView, pasteStartPos, pasteEndPos, target, effectiveScrollableElement);
|
|
297
346
|
return /*#__PURE__*/React.createElement(PopupWithListeners, {
|
|
298
347
|
target: target,
|
|
299
348
|
mountTo: mountTo,
|
|
@@ -302,10 +351,10 @@ export var PasteActionsMenu = function PasteActionsMenu(_ref) {
|
|
|
302
351
|
minPopupMargin: PASTE_MENU_GAP_HORIZONTAL,
|
|
303
352
|
zIndex: akEditorFloatingPanelZIndex,
|
|
304
353
|
alignX: "end",
|
|
305
|
-
alignY:
|
|
354
|
+
alignY: useInlinePosition ? 'top' : 'bottom'
|
|
306
355
|
/* eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) */,
|
|
307
356
|
offset: [PASTE_MENU_GAP_HORIZONTAL, 0],
|
|
308
|
-
onPositionCalculated:
|
|
357
|
+
onPositionCalculated: positionCalculator,
|
|
309
358
|
handleClickOutside: handleClickOutside,
|
|
310
359
|
handleEscapeKeydown: handleDismiss
|
|
311
360
|
}, /*#__PURE__*/React.createElement(EditorToolbarProvider, {
|
|
@@ -316,6 +365,7 @@ export var PasteActionsMenu = function PasteActionsMenu(_ref) {
|
|
|
316
365
|
}, /*#__PURE__*/React.createElement(PasteActionsMenuContent, {
|
|
317
366
|
onMouseDown: preventEditorFocusLoss,
|
|
318
367
|
onMouseEnter: handleMouseEnter,
|
|
319
|
-
components: pasteMenuComponents
|
|
368
|
+
components: pasteMenuComponents,
|
|
369
|
+
contentRef: popupContentRef
|
|
320
370
|
}))));
|
|
321
371
|
};
|
|
@@ -1,34 +1,37 @@
|
|
|
1
1
|
/* PasteActionsMenuContent.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
2
|
import "./PasteActionsMenuContent.compiled.css";
|
|
3
3
|
import { ax, ix } from "@compiled/react/runtime";
|
|
4
|
-
import React, { useContext } from 'react';
|
|
5
|
-
import {
|
|
6
|
-
import { pasteOptionsToolbarMessages as messages } from '@atlaskit/editor-common/messages';
|
|
4
|
+
import React, { useCallback, useContext } from 'react';
|
|
5
|
+
import { PASTE_MENU } from '@atlaskit/editor-common/toolbar';
|
|
7
6
|
import { OutsideClickTargetRefContext } from '@atlaskit/editor-common/ui-react';
|
|
8
|
-
import { ToolbarDropdownItemSection } from '@atlaskit/editor-toolbar';
|
|
9
7
|
import { SurfaceRenderer } from '@atlaskit/editor-ui-control-model';
|
|
10
8
|
import { Box } from '@atlaskit/primitives/compiled';
|
|
11
9
|
var styles = {
|
|
12
10
|
container: "_2rko12b0 _bfhk1bhr _16qs130s"
|
|
13
11
|
};
|
|
12
|
+
var pasteMenuSurface = {
|
|
13
|
+
type: PASTE_MENU.type,
|
|
14
|
+
key: PASTE_MENU.key
|
|
15
|
+
};
|
|
14
16
|
export var PasteActionsMenuContent = function PasteActionsMenuContent(_ref) {
|
|
15
17
|
var onMouseDown = _ref.onMouseDown,
|
|
16
18
|
onMouseEnter = _ref.onMouseEnter,
|
|
17
|
-
components = _ref.components
|
|
19
|
+
components = _ref.components,
|
|
20
|
+
contentRef = _ref.contentRef;
|
|
18
21
|
var setOutsideClickTargetRef = useContext(OutsideClickTargetRefContext);
|
|
19
|
-
var
|
|
22
|
+
var mergedRef = useCallback(function (node) {
|
|
23
|
+
setOutsideClickTargetRef === null || setOutsideClickTargetRef === void 0 || setOutsideClickTargetRef(node);
|
|
24
|
+
if (contentRef) {
|
|
25
|
+
contentRef.current = node;
|
|
26
|
+
}
|
|
27
|
+
}, [setOutsideClickTargetRef, contentRef]);
|
|
20
28
|
return /*#__PURE__*/React.createElement(Box, {
|
|
21
|
-
ref:
|
|
29
|
+
ref: mergedRef,
|
|
22
30
|
xcss: styles.container,
|
|
23
31
|
onMouseDown: onMouseDown,
|
|
24
32
|
onMouseEnter: onMouseEnter
|
|
25
|
-
}, /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
|
|
26
|
-
title: intl.formatMessage(messages.pasteMenuActionsTitle)
|
|
27
33
|
}, /*#__PURE__*/React.createElement(SurfaceRenderer, {
|
|
28
|
-
surface:
|
|
29
|
-
type: 'menu',
|
|
30
|
-
key: 'paste-menu'
|
|
31
|
-
},
|
|
34
|
+
surface: pasteMenuSurface,
|
|
32
35
|
components: components
|
|
33
|
-
}))
|
|
36
|
+
}));
|
|
34
37
|
};
|
|
@@ -8,12 +8,14 @@ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'
|
|
|
8
8
|
import { pasteOptionsToolbarMessages as messages } from '@atlaskit/editor-common/messages';
|
|
9
9
|
import { useEditorToolbar, PASTE_MENU, PASTE_MENU_SECTION, PASTE_NESTED_MENU, PASTE_MENU_NESTED_SECTION, PASTE_RICH_TEXT_MENU_ITEM, PASTE_MARKDOWN_MENU_ITEM, PASTE_PLAIN_TEXT_MENU_ITEM, PASTE_MENU_RANK, PASTE_MENU_SECTION_RANK, PASTE_NESTED_MENU_RANK, PASTE_MENU_NESTED_SECTION_RANK, AI_PASTE_MENU_SECTION } from '@atlaskit/editor-common/toolbar';
|
|
10
10
|
import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
|
|
11
|
+
import ChevronDownIcon from '@atlaskit/icon/core/chevron-down';
|
|
11
12
|
import ChevronRightIcon from '@atlaskit/icon/core/chevron-right';
|
|
12
13
|
import ClipboardIcon from '@atlaskit/icon/core/clipboard';
|
|
13
14
|
import { Box } from '@atlaskit/primitives/compiled';
|
|
14
15
|
import { changeToMarkdownWithAnalytics, changeToPlainTextWithAnalytics, changeToRichTextWithAnalytics } from '../../editor-commands/commands';
|
|
15
16
|
import { ToolbarDropdownOption } from '../../types/types';
|
|
16
17
|
import { getVisibleKeys } from './hasVisibleButton';
|
|
18
|
+
import { PasteOptionsDropdownButton } from './PasteOptionsDropdownButton';
|
|
17
19
|
var nestedMenuStyles = {
|
|
18
20
|
narrowSection: "_10gv1lit"
|
|
19
21
|
};
|
|
@@ -91,21 +93,49 @@ var PasteMenuItem = function PasteMenuItem(_ref) {
|
|
|
91
93
|
}, displayLabel);
|
|
92
94
|
};
|
|
93
95
|
var PasteOptionsNestedMenu = function PasteOptionsNestedMenu(_ref2) {
|
|
94
|
-
var children = _ref2.children
|
|
96
|
+
var children = _ref2.children,
|
|
97
|
+
hasVisibleAiActions = _ref2.hasVisibleAiActions;
|
|
95
98
|
var intl = useIntl();
|
|
99
|
+
var label = intl.formatMessage(messages.pasteMenuActionsPasteAs);
|
|
100
|
+
if (!hasVisibleAiActions) {
|
|
101
|
+
return /*#__PURE__*/React.createElement(PasteOptionsDropdownButton, {
|
|
102
|
+
elemBefore: /*#__PURE__*/React.createElement(ClipboardIcon, {
|
|
103
|
+
size: "small",
|
|
104
|
+
label: ""
|
|
105
|
+
}),
|
|
106
|
+
elemAfter: /*#__PURE__*/React.createElement(ChevronDownIcon, {
|
|
107
|
+
size: "small",
|
|
108
|
+
label: ""
|
|
109
|
+
}),
|
|
110
|
+
label: label,
|
|
111
|
+
testId: "paste-options-nested-menu",
|
|
112
|
+
tooltipContent: label
|
|
113
|
+
}, children);
|
|
114
|
+
}
|
|
96
115
|
return /*#__PURE__*/React.createElement(ToolbarNestedDropdownMenu, {
|
|
97
116
|
elemBefore: /*#__PURE__*/React.createElement(ClipboardIcon, {
|
|
98
117
|
size: "small",
|
|
99
|
-
label:
|
|
118
|
+
label: label
|
|
100
119
|
}),
|
|
101
120
|
elemAfter: /*#__PURE__*/React.createElement(ChevronRightIcon, {
|
|
102
121
|
size: "small",
|
|
103
|
-
label:
|
|
122
|
+
label: ""
|
|
104
123
|
}),
|
|
105
124
|
testId: "paste-options-nested-menu",
|
|
106
|
-
text:
|
|
125
|
+
text: label
|
|
107
126
|
}, children);
|
|
108
127
|
};
|
|
128
|
+
var getHasVisibleAiActions = function getHasVisibleAiActions(api) {
|
|
129
|
+
var _api$uiControlRegistr, _api$uiControlRegistr2;
|
|
130
|
+
var allComponents = (_api$uiControlRegistr = api === null || api === void 0 || (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.getComponents(PASTE_MENU.key)) !== null && _api$uiControlRegistr !== void 0 ? _api$uiControlRegistr : [];
|
|
131
|
+
var aiMenuItems = allComponents.filter(function (c) {
|
|
132
|
+
var _c$parents;
|
|
133
|
+
return c.type === 'menu-item' && ((_c$parents = c.parents) === null || _c$parents === void 0 ? void 0 : _c$parents.some(function (p) {
|
|
134
|
+
return p.key === AI_PASTE_MENU_SECTION.key;
|
|
135
|
+
}));
|
|
136
|
+
});
|
|
137
|
+
return getVisibleKeys(aiMenuItems, ['menu-item']).length > 0;
|
|
138
|
+
};
|
|
109
139
|
export var getPasteMenuComponents = function getPasteMenuComponents(_ref3) {
|
|
110
140
|
var api = _ref3.api;
|
|
111
141
|
return [{
|
|
@@ -125,17 +155,14 @@ export var getPasteMenuComponents = function getPasteMenuComponents(_ref3) {
|
|
|
125
155
|
return !((_pluginState$showLega = pluginState === null || pluginState === void 0 ? void 0 : pluginState.showLegacyOptions) !== null && _pluginState$showLega !== void 0 ? _pluginState$showLega : false);
|
|
126
156
|
},
|
|
127
157
|
component: function component(props) {
|
|
128
|
-
var
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}));
|
|
135
|
-
});
|
|
136
|
-
var hasVisibleAiActions = getVisibleKeys(aiMenuItems, ['menu-item']).length > 0;
|
|
158
|
+
var hasVisibleAiActions = getHasVisibleAiActions(api);
|
|
159
|
+
if (!hasVisibleAiActions) {
|
|
160
|
+
return /*#__PURE__*/React.createElement(Box, {
|
|
161
|
+
padding: "space.050"
|
|
162
|
+
}, props.children);
|
|
163
|
+
}
|
|
137
164
|
return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
|
|
138
|
-
hasSeparator:
|
|
165
|
+
hasSeparator: true
|
|
139
166
|
}, props.children);
|
|
140
167
|
}
|
|
141
168
|
}, {
|
|
@@ -147,7 +174,10 @@ export var getPasteMenuComponents = function getPasteMenuComponents(_ref3) {
|
|
|
147
174
|
rank: PASTE_MENU_SECTION_RANK[PASTE_NESTED_MENU.key]
|
|
148
175
|
}],
|
|
149
176
|
component: function component(props) {
|
|
150
|
-
|
|
177
|
+
var hasVisibleAiActions = getHasVisibleAiActions(api);
|
|
178
|
+
return /*#__PURE__*/React.createElement(PasteOptionsNestedMenu, {
|
|
179
|
+
hasVisibleAiActions: hasVisibleAiActions
|
|
180
|
+
}, props.children);
|
|
151
181
|
}
|
|
152
182
|
}, {
|
|
153
183
|
type: PASTE_MENU_NESTED_SECTION.type,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* PasteOptionsDropdownButton.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
|
+
import { ax, ix } from "@compiled/react/runtime";
|
|
3
|
+
import React, { useCallback } from 'react';
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
6
|
+
|
|
7
|
+
import DropdownMenu from '@atlaskit/dropdown-menu';
|
|
8
|
+
import { ToolbarButton, ToolbarTooltip } from '@atlaskit/editor-toolbar';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A compact dropdown button for paste options, styled like floating toolbar buttons.
|
|
12
|
+
* Renders as a ToolbarButton with an icon and dropdown caret that opens a
|
|
13
|
+
* dropdown menu below. Used when AI actions are not visible and the paste
|
|
14
|
+
* options menu is the only content.
|
|
15
|
+
*/
|
|
16
|
+
export var PasteOptionsDropdownButton = function PasteOptionsDropdownButton(_ref) {
|
|
17
|
+
var children = _ref.children,
|
|
18
|
+
elemBefore = _ref.elemBefore,
|
|
19
|
+
elemAfter = _ref.elemAfter,
|
|
20
|
+
label = _ref.label,
|
|
21
|
+
testId = _ref.testId,
|
|
22
|
+
tooltipContent = _ref.tooltipContent;
|
|
23
|
+
var trigger = useCallback(function (triggerProps) {
|
|
24
|
+
var button = /*#__PURE__*/React.createElement(ToolbarButton, {
|
|
25
|
+
ref: triggerProps.triggerRef,
|
|
26
|
+
isSelected: triggerProps.isSelected,
|
|
27
|
+
"aria-expanded": triggerProps['aria-expanded'],
|
|
28
|
+
"aria-haspopup": triggerProps['aria-haspopup'],
|
|
29
|
+
onClick: triggerProps.onClick,
|
|
30
|
+
testId: testId,
|
|
31
|
+
iconBefore: elemBefore,
|
|
32
|
+
label: label
|
|
33
|
+
}, elemAfter);
|
|
34
|
+
if (tooltipContent) {
|
|
35
|
+
return /*#__PURE__*/React.createElement(ToolbarTooltip, {
|
|
36
|
+
content: tooltipContent,
|
|
37
|
+
position: "top"
|
|
38
|
+
}, button);
|
|
39
|
+
}
|
|
40
|
+
return button;
|
|
41
|
+
}, [testId, elemBefore, elemAfter, label, tooltipContent]);
|
|
42
|
+
return /*#__PURE__*/React.createElement(DropdownMenu, {
|
|
43
|
+
placement: "bottom-start",
|
|
44
|
+
trigger: trigger
|
|
45
|
+
}, children);
|
|
46
|
+
};
|
|
@@ -33,6 +33,22 @@ export declare function getVisualEndBottom(editorView: EditorView, pasteEndPos:
|
|
|
33
33
|
* Returns `null` if no block ancestor can be resolved to a DOM element.
|
|
34
34
|
*/
|
|
35
35
|
export declare function findBlockAncestorDOM(editorView: EditorView, pos: number): HTMLElement | null;
|
|
36
|
+
/**
|
|
37
|
+
* Positions the paste menu inline, immediately to the right of the cursor
|
|
38
|
+
* at the paste end position, vertically centered with the line.
|
|
39
|
+
* Used for short pastes without AI actions.
|
|
40
|
+
*/
|
|
41
|
+
export declare function onInlinePositionCalculated(editorView: EditorView, pasteEndPos: number, targetElement: HTMLElement, popupContentRef: React.RefObject<HTMLDivElement | null>): (position: {
|
|
42
|
+
bottom?: number;
|
|
43
|
+
left?: number;
|
|
44
|
+
right?: number;
|
|
45
|
+
top?: number;
|
|
46
|
+
}) => {
|
|
47
|
+
bottom?: number;
|
|
48
|
+
left?: number;
|
|
49
|
+
right?: number;
|
|
50
|
+
top: number;
|
|
51
|
+
};
|
|
36
52
|
/**
|
|
37
53
|
* Adjusts the position of the paste menu so that:
|
|
38
54
|
*
|
|
@@ -2,8 +2,9 @@ import React from 'react';
|
|
|
2
2
|
import type { RegisterComponent } from '@atlaskit/editor-ui-control-model';
|
|
3
3
|
interface PasteActionsMenuContentProps {
|
|
4
4
|
components: RegisterComponent[];
|
|
5
|
+
contentRef?: React.RefObject<HTMLDivElement | null>;
|
|
5
6
|
onMouseDown: (e: React.MouseEvent) => void;
|
|
6
7
|
onMouseEnter: () => void;
|
|
7
8
|
}
|
|
8
|
-
export declare const PasteActionsMenuContent: ({ onMouseDown, onMouseEnter, components, }: PasteActionsMenuContentProps) => React.JSX.Element;
|
|
9
|
+
export declare const PasteActionsMenuContent: ({ onMouseDown, onMouseEnter, components, contentRef, }: PasteActionsMenuContentProps) => React.JSX.Element;
|
|
9
10
|
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jsxRuntime classic
|
|
3
|
+
* @jsx jsx
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
/**
|
|
7
|
+
* A compact dropdown button for paste options, styled like floating toolbar buttons.
|
|
8
|
+
* Renders as a ToolbarButton with an icon and dropdown caret that opens a
|
|
9
|
+
* dropdown menu below. Used when AI actions are not visible and the paste
|
|
10
|
+
* options menu is the only content.
|
|
11
|
+
*/
|
|
12
|
+
export declare const PasteOptionsDropdownButton: ({ children, elemBefore, elemAfter, label, testId, tooltipContent, }: {
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
elemAfter: React.ReactNode;
|
|
15
|
+
elemBefore: React.ReactNode;
|
|
16
|
+
label: string;
|
|
17
|
+
testId?: string;
|
|
18
|
+
tooltipContent?: string;
|
|
19
|
+
}) => JSX.Element;
|
|
@@ -33,6 +33,22 @@ export declare function getVisualEndBottom(editorView: EditorView, pasteEndPos:
|
|
|
33
33
|
* Returns `null` if no block ancestor can be resolved to a DOM element.
|
|
34
34
|
*/
|
|
35
35
|
export declare function findBlockAncestorDOM(editorView: EditorView, pos: number): HTMLElement | null;
|
|
36
|
+
/**
|
|
37
|
+
* Positions the paste menu inline, immediately to the right of the cursor
|
|
38
|
+
* at the paste end position, vertically centered with the line.
|
|
39
|
+
* Used for short pastes without AI actions.
|
|
40
|
+
*/
|
|
41
|
+
export declare function onInlinePositionCalculated(editorView: EditorView, pasteEndPos: number, targetElement: HTMLElement, popupContentRef: React.RefObject<HTMLDivElement | null>): (position: {
|
|
42
|
+
bottom?: number;
|
|
43
|
+
left?: number;
|
|
44
|
+
right?: number;
|
|
45
|
+
top?: number;
|
|
46
|
+
}) => {
|
|
47
|
+
bottom?: number;
|
|
48
|
+
left?: number;
|
|
49
|
+
right?: number;
|
|
50
|
+
top: number;
|
|
51
|
+
};
|
|
36
52
|
/**
|
|
37
53
|
* Adjusts the position of the paste menu so that:
|
|
38
54
|
*
|
|
@@ -2,8 +2,9 @@ import React from 'react';
|
|
|
2
2
|
import type { RegisterComponent } from '@atlaskit/editor-ui-control-model';
|
|
3
3
|
interface PasteActionsMenuContentProps {
|
|
4
4
|
components: RegisterComponent[];
|
|
5
|
+
contentRef?: React.RefObject<HTMLDivElement | null>;
|
|
5
6
|
onMouseDown: (e: React.MouseEvent) => void;
|
|
6
7
|
onMouseEnter: () => void;
|
|
7
8
|
}
|
|
8
|
-
export declare const PasteActionsMenuContent: ({ onMouseDown, onMouseEnter, components, }: PasteActionsMenuContentProps) => React.JSX.Element;
|
|
9
|
+
export declare const PasteActionsMenuContent: ({ onMouseDown, onMouseEnter, components, contentRef, }: PasteActionsMenuContentProps) => React.JSX.Element;
|
|
9
10
|
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jsxRuntime classic
|
|
3
|
+
* @jsx jsx
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
/**
|
|
7
|
+
* A compact dropdown button for paste options, styled like floating toolbar buttons.
|
|
8
|
+
* Renders as a ToolbarButton with an icon and dropdown caret that opens a
|
|
9
|
+
* dropdown menu below. Used when AI actions are not visible and the paste
|
|
10
|
+
* options menu is the only content.
|
|
11
|
+
*/
|
|
12
|
+
export declare const PasteOptionsDropdownButton: ({ children, elemBefore, elemAfter, label, testId, tooltipContent, }: {
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
elemAfter: React.ReactNode;
|
|
15
|
+
elemBefore: React.ReactNode;
|
|
16
|
+
label: string;
|
|
17
|
+
testId?: string;
|
|
18
|
+
tooltipContent?: string;
|
|
19
|
+
}) => JSX.Element;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-paste-options-toolbar",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.7",
|
|
4
4
|
"description": "Paste options toolbar for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"atlaskit:src": "src/index.ts",
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@atlaskit/css": "^0.19.0",
|
|
33
|
+
"@atlaskit/dropdown-menu": "^16.8.0",
|
|
33
34
|
"@atlaskit/editor-markdown-transformer": "^5.20.0",
|
|
34
35
|
"@atlaskit/editor-plugin-analytics": "^8.0.0",
|
|
35
36
|
"@atlaskit/editor-plugin-paste": "^9.0.0",
|
|
@@ -38,17 +39,17 @@
|
|
|
38
39
|
"@atlaskit/editor-shared-styles": "^3.10.0",
|
|
39
40
|
"@atlaskit/editor-toolbar": "^0.20.0",
|
|
40
41
|
"@atlaskit/editor-ui-control-model": "^1.1.0",
|
|
41
|
-
"@atlaskit/icon": "^33.
|
|
42
|
+
"@atlaskit/icon": "^33.1.0",
|
|
42
43
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
43
|
-
"@atlaskit/primitives": "^18.
|
|
44
|
-
"@atlaskit/tokens": "^11.
|
|
44
|
+
"@atlaskit/primitives": "^18.1.0",
|
|
45
|
+
"@atlaskit/tokens": "^11.3.0",
|
|
45
46
|
"@babel/runtime": "^7.0.0",
|
|
46
47
|
"@compiled/react": "^0.20.0",
|
|
47
48
|
"@emotion/react": "^11.7.1",
|
|
48
49
|
"react-intl-next": "npm:react-intl@^5.18.1"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|
|
51
|
-
"@atlaskit/editor-common": "^112.
|
|
52
|
+
"@atlaskit/editor-common": "^112.11.0",
|
|
52
53
|
"react": "^18.2.0",
|
|
53
54
|
"react-dom": "^18.2.0"
|
|
54
55
|
},
|