@atlaskit/editor-plugin-paste-options-toolbar 11.3.3 → 11.4.0
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 +11 -0
- package/current-pasted-smart-link/package.json +17 -0
- package/dist/cjs/entry-points/current-pasted-smart-link.js +12 -0
- package/dist/cjs/pasteOptionsToolbarPlugin.js +29 -8
- package/dist/cjs/ui/on-paste-actions-menu/PasteActionsMenu.js +11 -1
- package/dist/cjs/ui/on-paste-actions-menu/PasteMenuComponents.js +1 -1
- package/dist/cjs/ui/utils/current-pasted-smart-link.js +56 -0
- package/dist/cjs/ui/utils/paste-menu-rules/isNotSingleLink.js +12 -9
- package/dist/es2019/entry-points/current-pasted-smart-link.js +2 -0
- package/dist/es2019/pasteOptionsToolbarPlugin.js +27 -8
- package/dist/es2019/ui/on-paste-actions-menu/PasteActionsMenu.js +12 -1
- package/dist/es2019/ui/on-paste-actions-menu/PasteMenuComponents.js +1 -1
- package/dist/es2019/ui/utils/current-pasted-smart-link.js +50 -0
- package/dist/es2019/ui/utils/paste-menu-rules/isNotSingleLink.js +10 -9
- package/dist/esm/entry-points/current-pasted-smart-link.js +2 -0
- package/dist/esm/pasteOptionsToolbarPlugin.js +29 -8
- package/dist/esm/ui/on-paste-actions-menu/PasteActionsMenu.js +11 -1
- package/dist/esm/ui/on-paste-actions-menu/PasteMenuComponents.js +1 -1
- package/dist/esm/ui/utils/current-pasted-smart-link.js +50 -0
- package/dist/esm/ui/utils/paste-menu-rules/isNotSingleLink.js +12 -9
- package/dist/types/entry-points/current-pasted-smart-link.d.ts +1 -0
- package/dist/types/entry-points/paste-options-toolbar-plugin-type.d.ts +2 -1
- package/dist/types/pasteOptionsToolbarPluginType.d.ts +27 -19
- package/dist/types/ui/utils/current-pasted-smart-link.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/current-pasted-smart-link.d.ts +1 -0
- package/dist/types-ts4.5/entry-points/paste-options-toolbar-plugin-type.d.ts +2 -1
- package/dist/types-ts4.5/pasteOptionsToolbarPluginType.d.ts +27 -19
- package/dist/types-ts4.5/ui/utils/current-pasted-smart-link.d.ts +2 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-paste-options-toolbar
|
|
2
2
|
|
|
3
|
+
## 11.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`d2be5b45b39b0`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/d2be5b45b39b0) -
|
|
8
|
+
Add Smart Link-aware paste actions for the paste actions menu V2 experiment.
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
|
|
3
14
|
## 11.3.3
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atlaskit/editor-plugin-paste-options-toolbar/current-pasted-smart-link",
|
|
3
|
+
"main": "../dist/cjs/entry-points/current-pasted-smart-link.js",
|
|
4
|
+
"module": "../dist/esm/entry-points/current-pasted-smart-link.js",
|
|
5
|
+
"module:es2019": "../dist/es2019/entry-points/current-pasted-smart-link.js",
|
|
6
|
+
"sideEffects": [
|
|
7
|
+
"*.compiled.css"
|
|
8
|
+
],
|
|
9
|
+
"types": "../dist/types/entry-points/current-pasted-smart-link.d.ts",
|
|
10
|
+
"typesVersions": {
|
|
11
|
+
">=4.5 <5.9": {
|
|
12
|
+
"*": [
|
|
13
|
+
"../dist/types-ts4.5/entry-points/current-pasted-smart-link.d.ts"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "getSingleSmartLinkUrlFromSlice", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function get() {
|
|
9
|
+
return _currentPastedSmartLink.getSingleSmartLinkUrlFromSlice;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
var _currentPastedSmartLink = require("../ui/utils/current-pasted-smart-link");
|
|
@@ -9,6 +9,7 @@ var _react = _interopRequireWildcard(require("react"));
|
|
|
9
9
|
var _hooks = require("@atlaskit/editor-common/hooks");
|
|
10
10
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
11
11
|
var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
|
|
12
|
+
var _expVal = require("@atlaskit/tmp-editor-statsig/expVal");
|
|
12
13
|
var _commands = require("./editor-commands/commands");
|
|
13
14
|
var _main = require("./pm-plugins/main");
|
|
14
15
|
var _types = require("./types/types");
|
|
@@ -17,6 +18,7 @@ var _exposureV = require("./ui/on-paste-actions-menu/exposure-v2");
|
|
|
17
18
|
var _PasteActionsMenu = require("./ui/on-paste-actions-menu/PasteActionsMenu");
|
|
18
19
|
var _PasteMenuComponents = require("./ui/on-paste-actions-menu/PasteMenuComponents");
|
|
19
20
|
var _toolbar = require("./ui/toolbar");
|
|
21
|
+
var _currentPastedSmartLink = require("./ui/utils/current-pasted-smart-link");
|
|
20
22
|
var _rules = require("./ui/utils/paste-menu-rules/rules");
|
|
21
23
|
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); }
|
|
22
24
|
var pasteOptionsToolbarPlugin = exports.pasteOptionsToolbarPlugin = function pasteOptionsToolbarPlugin(_ref) {
|
|
@@ -24,6 +26,25 @@ var pasteOptionsToolbarPlugin = exports.pasteOptionsToolbarPlugin = function pas
|
|
|
24
26
|
var config = _ref.config,
|
|
25
27
|
api = _ref.api;
|
|
26
28
|
var editorAnalyticsAPI = api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions;
|
|
29
|
+
var getPasteMenuContext = function getPasteMenuContext() {
|
|
30
|
+
return {
|
|
31
|
+
getCurrentPasteRange: function getCurrentPasteRange() {
|
|
32
|
+
var _api$pasteOptionsTool;
|
|
33
|
+
var state = api === null || api === void 0 || (_api$pasteOptionsTool = api.pasteOptionsToolbarPlugin) === null || _api$pasteOptionsTool === void 0 ? void 0 : _api$pasteOptionsTool.sharedState.currentState();
|
|
34
|
+
if (!state) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
pasteEndPos: state.pasteEndPos,
|
|
39
|
+
pasteStartPos: state.pasteStartPos
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
getCurrentPastedUrl: function getCurrentPastedUrl() {
|
|
43
|
+
var _api$paste;
|
|
44
|
+
return (0, _currentPastedSmartLink.getSingleSmartLinkUrlFromSlice)(api === null || api === void 0 || (_api$paste = api.paste) === null || _api$paste === void 0 || (_api$paste = _api$paste.sharedState.currentState()) === null || _api$paste === void 0 || (_api$paste = _api$paste.lastContentPasted) === null || _api$paste === void 0 ? void 0 : _api$paste.pastedSlice);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
27
48
|
if (config !== null && config !== void 0 && config.usePopupBasedPasteActionsMenu && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_paste_actions_menu', 'isEnabled', true)) {
|
|
28
49
|
var _api$uiControlRegistr;
|
|
29
50
|
api === null || api === void 0 || (_api$uiControlRegistr = api.uiControlRegistry) === null || _api$uiControlRegistr === void 0 || _api$uiControlRegistr.actions.register((0, _PasteMenuComponents.getPasteMenuComponents)({
|
|
@@ -34,9 +55,9 @@ var pasteOptionsToolbarPlugin = exports.pasteOptionsToolbarPlugin = function pas
|
|
|
34
55
|
var _api$uiControlRegistr2;
|
|
35
56
|
var rules = function () {
|
|
36
57
|
var getContext = function getContext() {
|
|
37
|
-
var _api$
|
|
38
|
-
var pasteOptsState = api === null || api === void 0 || (_api$
|
|
39
|
-
var pasteState = api === null || api === void 0 || (_api$
|
|
58
|
+
var _api$pasteOptionsTool2, _api$paste2;
|
|
59
|
+
var pasteOptsState = api === null || api === void 0 || (_api$pasteOptionsTool2 = api.pasteOptionsToolbarPlugin) === null || _api$pasteOptionsTool2 === void 0 ? void 0 : _api$pasteOptionsTool2.sharedState.currentState();
|
|
60
|
+
var pasteState = api === null || api === void 0 || (_api$paste2 = api.paste) === null || _api$paste2 === void 0 ? void 0 : _api$paste2.sharedState.currentState();
|
|
40
61
|
return {
|
|
41
62
|
getPlaintextLength: function getPlaintextLength() {
|
|
42
63
|
var _pasteOptsState$plain;
|
|
@@ -65,7 +86,7 @@ var pasteOptionsToolbarPlugin = exports.pasteOptionsToolbarPlugin = function pas
|
|
|
65
86
|
};
|
|
66
87
|
return (0, _rules.createPasteMenuRuleFactories)(getContext);
|
|
67
88
|
}();
|
|
68
|
-
var productButtons = config.pasteMenuButtonsFactory(rules);
|
|
89
|
+
var productButtons = config.pasteMenuButtonsFactory(rules, getPasteMenuContext());
|
|
69
90
|
api === null || api === void 0 || (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 || _api$uiControlRegistr2.actions.register(productButtons);
|
|
70
91
|
}
|
|
71
92
|
return {
|
|
@@ -73,9 +94,9 @@ var pasteOptionsToolbarPlugin = exports.pasteOptionsToolbarPlugin = function pas
|
|
|
73
94
|
actions: {
|
|
74
95
|
getPasteMenuRules: function getPasteMenuRules() {
|
|
75
96
|
var getContext = function getContext() {
|
|
76
|
-
var _api$
|
|
77
|
-
var pasteOptsState = api === null || api === void 0 || (_api$
|
|
78
|
-
var pasteState = api === null || api === void 0 || (_api$
|
|
97
|
+
var _api$pasteOptionsTool3, _api$paste3;
|
|
98
|
+
var pasteOptsState = api === null || api === void 0 || (_api$pasteOptionsTool3 = api.pasteOptionsToolbarPlugin) === null || _api$pasteOptionsTool3 === void 0 ? void 0 : _api$pasteOptionsTool3.sharedState.currentState();
|
|
99
|
+
var pasteState = api === null || api === void 0 || (_api$paste3 = api.paste) === null || _api$paste3 === void 0 ? void 0 : _api$paste3.sharedState.currentState();
|
|
79
100
|
return {
|
|
80
101
|
getPlaintextLength: function getPlaintextLength() {
|
|
81
102
|
var _pasteOptsState$plain2;
|
|
@@ -159,7 +180,7 @@ var pasteOptionsToolbarPlugin = exports.pasteOptionsToolbarPlugin = function pas
|
|
|
159
180
|
popupsMountPoint = _ref3.popupsMountPoint,
|
|
160
181
|
popupsBoundariesElement = _ref3.popupsBoundariesElement,
|
|
161
182
|
popupsScrollableElement = _ref3.popupsScrollableElement;
|
|
162
|
-
if (!(config !== null && config !== void 0 && config.usePopupBasedPasteActionsMenu && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_paste_actions_menu', 'isEnabled', true)) || !editorView) {
|
|
183
|
+
if (!(config !== null && config !== void 0 && config.usePopupBasedPasteActionsMenu && ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_paste_actions_menu', 'isEnabled', true) || ['hasSpellingAndGrammar', 'hasAltAiActions'].includes((0, _expVal.expValNoExposure)('platform_editor_paste_actions_menu_v2', 'variant', 'control')))) || !editorView) {
|
|
163
184
|
return null;
|
|
164
185
|
}
|
|
165
186
|
return /*#__PURE__*/_react.default.createElement(_PasteActionsMenu.PasteActionsMenu, {
|
|
@@ -357,7 +357,17 @@ var PasteActionsMenu = exports.PasteActionsMenu = function PasteActionsMenu(_ref
|
|
|
357
357
|
// Choose positioning strategy based on whether the menu appears inline
|
|
358
358
|
// (right of cursor for short pastes) or anchored to the block ancestor
|
|
359
359
|
// (right side of content area for longer pastes / AI actions).
|
|
360
|
-
var positionCalculator
|
|
360
|
+
var positionCalculator;
|
|
361
|
+
try {
|
|
362
|
+
positionCalculator = useInlinePosition ? onInlinePositionCalculated(editorView, pasteEndPos, target, popupContentRef) : onPositionCalculated(editorView, pasteStartPos, pasteEndPos, target, effectiveScrollableElement);
|
|
363
|
+
} catch (error) {
|
|
364
|
+
positionCalculator = function positionCalculator(position) {
|
|
365
|
+
var _position$top3;
|
|
366
|
+
return _objectSpread(_objectSpread({}, position), {}, {
|
|
367
|
+
top: (_position$top3 = position.top) !== null && _position$top3 !== void 0 ? _position$top3 : 0
|
|
368
|
+
});
|
|
369
|
+
};
|
|
370
|
+
}
|
|
361
371
|
return /*#__PURE__*/_react.default.createElement(PopupWithListeners, {
|
|
362
372
|
target: target,
|
|
363
373
|
mountTo: mountTo,
|
|
@@ -167,7 +167,7 @@ var getPasteMenuComponents = exports.getPasteMenuComponents = function getPasteM
|
|
|
167
167
|
var hasVisibleAiActions = getHasVisibleAiActions(api);
|
|
168
168
|
if (!hasVisibleAiActions) {
|
|
169
169
|
return /*#__PURE__*/_react.default.createElement(_compiled.Box, {
|
|
170
|
-
padding: "space.
|
|
170
|
+
padding: "space.100"
|
|
171
171
|
}, props.children);
|
|
172
172
|
}
|
|
173
173
|
return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItemSection, {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getSingleSmartLinkUrlFromSlice = void 0;
|
|
7
|
+
var _isNotSingleLink = require("./paste-menu-rules/isNotSingleLink");
|
|
8
|
+
var getUrlFromTextLinkNode = function getUrlFromTextLinkNode(node) {
|
|
9
|
+
var _node$marks$0$attrs;
|
|
10
|
+
if (!node.isText || node.marks.length !== 1 || node.marks[0].type.name !== 'link') {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
var href = (_node$marks$0$attrs = node.marks[0].attrs) === null || _node$marks$0$attrs === void 0 ? void 0 : _node$marks$0$attrs.href;
|
|
14
|
+
return typeof href === 'string' && node.text === href ? href : undefined;
|
|
15
|
+
};
|
|
16
|
+
var getUrlFromInlineCardNode = function getUrlFromInlineCardNode(node) {
|
|
17
|
+
var _node$attrs;
|
|
18
|
+
if (node.type.name !== 'inlineCard') {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
var url = (_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.url;
|
|
22
|
+
return typeof url === 'string' ? url : undefined;
|
|
23
|
+
};
|
|
24
|
+
var significantChildren = function significantChildren(node) {
|
|
25
|
+
var children = [];
|
|
26
|
+
node.content.forEach(function (child) {
|
|
27
|
+
var _child$text;
|
|
28
|
+
if (child.isText && ((_child$text = child.text) === null || _child$text === void 0 ? void 0 : _child$text.trim()) === '') {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
children.push(child);
|
|
32
|
+
});
|
|
33
|
+
return children;
|
|
34
|
+
};
|
|
35
|
+
var getSingleSmartLinkUrlFromSlice = exports.getSingleSmartLinkUrlFromSlice = function getSingleSmartLinkUrlFromSlice(slice) {
|
|
36
|
+
var _getUrlFromTextLinkNo, _getUrlFromTextLinkNo2;
|
|
37
|
+
if (!slice || (0, _isNotSingleLink.isNotSingleLink)(slice)) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
if (slice.content.childCount !== 1) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
var topNode = slice.content.child(0);
|
|
44
|
+
var topNodeUrl = (_getUrlFromTextLinkNo = getUrlFromTextLinkNode(topNode)) !== null && _getUrlFromTextLinkNo !== void 0 ? _getUrlFromTextLinkNo : getUrlFromInlineCardNode(topNode);
|
|
45
|
+
if (topNodeUrl) {
|
|
46
|
+
return topNodeUrl;
|
|
47
|
+
}
|
|
48
|
+
if (topNode.type.name !== 'paragraph') {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
var children = significantChildren(topNode);
|
|
52
|
+
if (children.length !== 1) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
return (_getUrlFromTextLinkNo2 = getUrlFromTextLinkNode(children[0])) !== null && _getUrlFromTextLinkNo2 !== void 0 ? _getUrlFromTextLinkNo2 : getUrlFromInlineCardNode(children[0]);
|
|
56
|
+
};
|
|
@@ -21,30 +21,33 @@ var isUrlOnlyLinkTextNode = function isUrlOnlyLinkTextNode(node) {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* Returns true if the slice represents a single
|
|
24
|
+
* Returns true if the slice represents a single smart-link card node.
|
|
25
25
|
* Handles two shapes:
|
|
26
|
-
* - paragraph > inlineCard
|
|
27
|
-
* - inlineCard
|
|
26
|
+
* - paragraph > inlineCard|blockCard (smartlink from editor/renderer, wrapped in a paragraph)
|
|
27
|
+
* - inlineCard|blockCard (top-level card with no paragraph wrapper)
|
|
28
28
|
*/
|
|
29
|
-
var
|
|
29
|
+
var isSingleSmartLinkCard = function isSingleSmartLinkCard(slice) {
|
|
30
|
+
var isSupportedCard = function isSupportedCard(node) {
|
|
31
|
+
return node.type.name === 'inlineCard' || node.type.name === 'blockCard';
|
|
32
|
+
};
|
|
30
33
|
if (slice.content.childCount !== 1) {
|
|
31
34
|
return false;
|
|
32
35
|
}
|
|
33
36
|
var topNode = slice.content.child(0);
|
|
34
37
|
|
|
35
|
-
// Top-level inlineCard (no paragraph wrapper)
|
|
36
|
-
if (topNode
|
|
38
|
+
// Top-level inlineCard/blockCard (no paragraph wrapper)
|
|
39
|
+
if (isSupportedCard(topNode)) {
|
|
37
40
|
return true;
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
// paragraph > inlineCard
|
|
43
|
+
// paragraph > inlineCard/blockCard
|
|
41
44
|
if (topNode.type.name !== 'paragraph') {
|
|
42
45
|
return false;
|
|
43
46
|
}
|
|
44
47
|
if (topNode.childCount !== 1) {
|
|
45
48
|
return false;
|
|
46
49
|
}
|
|
47
|
-
return topNode.child(0)
|
|
50
|
+
return isSupportedCard(topNode.child(0));
|
|
48
51
|
};
|
|
49
52
|
|
|
50
53
|
/**
|
|
@@ -113,5 +116,5 @@ var isNotSingleLink = exports.isNotSingleLink = function isNotSingleLink(slice)
|
|
|
113
116
|
// No rich-text slice → plain text paste, not a single link in the relevant sense
|
|
114
117
|
return true;
|
|
115
118
|
}
|
|
116
|
-
return !isSingleBareLink(slice) && !
|
|
119
|
+
return !isSingleBareLink(slice) && !isSingleSmartLinkCard(slice);
|
|
117
120
|
};
|
|
@@ -2,6 +2,7 @@ import React, { useEffect } from 'react';
|
|
|
2
2
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
3
3
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
4
4
|
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
|
|
5
|
+
import { expValNoExposure } from '@atlaskit/tmp-editor-statsig/expVal';
|
|
5
6
|
import { hideToolbar, showToolbar } from './editor-commands/commands';
|
|
6
7
|
import { createPlugin } from './pm-plugins/main';
|
|
7
8
|
import { pasteOptionsPluginKey, ToolbarDropdownOption } from './types/types';
|
|
@@ -10,6 +11,7 @@ import { firePasteActionsMenuV2ExperimentExposure } from './ui/on-paste-actions-
|
|
|
10
11
|
import { PasteActionsMenu } from './ui/on-paste-actions-menu/PasteActionsMenu';
|
|
11
12
|
import { getPasteMenuComponents } from './ui/on-paste-actions-menu/PasteMenuComponents';
|
|
12
13
|
import { buildToolbar, isToolbarVisible } from './ui/toolbar';
|
|
14
|
+
import { getSingleSmartLinkUrlFromSlice } from './ui/utils/current-pasted-smart-link';
|
|
13
15
|
import { createPasteMenuRuleFactories } from './ui/utils/paste-menu-rules/rules';
|
|
14
16
|
export const pasteOptionsToolbarPlugin = ({
|
|
15
17
|
config,
|
|
@@ -17,6 +19,23 @@ export const pasteOptionsToolbarPlugin = ({
|
|
|
17
19
|
}) => {
|
|
18
20
|
var _api$analytics;
|
|
19
21
|
const editorAnalyticsAPI = api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions;
|
|
22
|
+
const getPasteMenuContext = () => ({
|
|
23
|
+
getCurrentPasteRange: () => {
|
|
24
|
+
var _api$pasteOptionsTool;
|
|
25
|
+
const state = api === null || api === void 0 ? void 0 : (_api$pasteOptionsTool = api.pasteOptionsToolbarPlugin) === null || _api$pasteOptionsTool === void 0 ? void 0 : _api$pasteOptionsTool.sharedState.currentState();
|
|
26
|
+
if (!state) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
pasteEndPos: state.pasteEndPos,
|
|
31
|
+
pasteStartPos: state.pasteStartPos
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
getCurrentPastedUrl: () => {
|
|
35
|
+
var _api$paste, _api$paste$sharedStat, _api$paste$sharedStat2;
|
|
36
|
+
return getSingleSmartLinkUrlFromSlice(api === null || api === void 0 ? void 0 : (_api$paste = api.paste) === null || _api$paste === void 0 ? void 0 : (_api$paste$sharedStat = _api$paste.sharedState.currentState()) === null || _api$paste$sharedStat === void 0 ? void 0 : (_api$paste$sharedStat2 = _api$paste$sharedStat.lastContentPasted) === null || _api$paste$sharedStat2 === void 0 ? void 0 : _api$paste$sharedStat2.pastedSlice);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
20
39
|
if (config !== null && config !== void 0 && config.usePopupBasedPasteActionsMenu && expValEqualsNoExposure('platform_editor_paste_actions_menu', 'isEnabled', true)) {
|
|
21
40
|
var _api$uiControlRegistr;
|
|
22
41
|
api === null || api === void 0 ? void 0 : (_api$uiControlRegistr = api.uiControlRegistry) === null || _api$uiControlRegistr === void 0 ? void 0 : _api$uiControlRegistr.actions.register(getPasteMenuComponents({
|
|
@@ -27,9 +46,9 @@ export const pasteOptionsToolbarPlugin = ({
|
|
|
27
46
|
var _api$uiControlRegistr2;
|
|
28
47
|
const rules = (() => {
|
|
29
48
|
const getContext = () => {
|
|
30
|
-
var _api$
|
|
31
|
-
const pasteOptsState = api === null || api === void 0 ? void 0 : (_api$
|
|
32
|
-
const pasteState = api === null || api === void 0 ? void 0 : (_api$
|
|
49
|
+
var _api$pasteOptionsTool2, _api$paste2;
|
|
50
|
+
const pasteOptsState = api === null || api === void 0 ? void 0 : (_api$pasteOptionsTool2 = api.pasteOptionsToolbarPlugin) === null || _api$pasteOptionsTool2 === void 0 ? void 0 : _api$pasteOptionsTool2.sharedState.currentState();
|
|
51
|
+
const pasteState = api === null || api === void 0 ? void 0 : (_api$paste2 = api.paste) === null || _api$paste2 === void 0 ? void 0 : _api$paste2.sharedState.currentState();
|
|
33
52
|
return {
|
|
34
53
|
getPlaintextLength: () => {
|
|
35
54
|
var _pasteOptsState$plain;
|
|
@@ -56,7 +75,7 @@ export const pasteOptionsToolbarPlugin = ({
|
|
|
56
75
|
};
|
|
57
76
|
return createPasteMenuRuleFactories(getContext);
|
|
58
77
|
})();
|
|
59
|
-
const productButtons = config.pasteMenuButtonsFactory(rules);
|
|
78
|
+
const productButtons = config.pasteMenuButtonsFactory(rules, getPasteMenuContext());
|
|
60
79
|
api === null || api === void 0 ? void 0 : (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 ? void 0 : _api$uiControlRegistr2.actions.register(productButtons);
|
|
61
80
|
}
|
|
62
81
|
return {
|
|
@@ -64,9 +83,9 @@ export const pasteOptionsToolbarPlugin = ({
|
|
|
64
83
|
actions: {
|
|
65
84
|
getPasteMenuRules: () => {
|
|
66
85
|
const getContext = () => {
|
|
67
|
-
var _api$
|
|
68
|
-
const pasteOptsState = api === null || api === void 0 ? void 0 : (_api$
|
|
69
|
-
const pasteState = api === null || api === void 0 ? void 0 : (_api$
|
|
86
|
+
var _api$pasteOptionsTool3, _api$paste3;
|
|
87
|
+
const pasteOptsState = api === null || api === void 0 ? void 0 : (_api$pasteOptionsTool3 = api.pasteOptionsToolbarPlugin) === null || _api$pasteOptionsTool3 === void 0 ? void 0 : _api$pasteOptionsTool3.sharedState.currentState();
|
|
88
|
+
const pasteState = api === null || api === void 0 ? void 0 : (_api$paste3 = api.paste) === null || _api$paste3 === void 0 ? void 0 : _api$paste3.sharedState.currentState();
|
|
70
89
|
return {
|
|
71
90
|
getPlaintextLength: () => {
|
|
72
91
|
var _pasteOptsState$plain2;
|
|
@@ -148,7 +167,7 @@ export const pasteOptionsToolbarPlugin = ({
|
|
|
148
167
|
popupsBoundariesElement,
|
|
149
168
|
popupsScrollableElement
|
|
150
169
|
}) {
|
|
151
|
-
if (!(config !== null && config !== void 0 && config.usePopupBasedPasteActionsMenu && expValEqualsNoExposure('platform_editor_paste_actions_menu', 'isEnabled', true)) || !editorView) {
|
|
170
|
+
if (!(config !== null && config !== void 0 && config.usePopupBasedPasteActionsMenu && (expValEqualsNoExposure('platform_editor_paste_actions_menu', 'isEnabled', true) || ['hasSpellingAndGrammar', 'hasAltAiActions'].includes(expValNoExposure('platform_editor_paste_actions_menu_v2', 'variant', 'control')))) || !editorView) {
|
|
152
171
|
return null;
|
|
153
172
|
}
|
|
154
173
|
return /*#__PURE__*/React.createElement(PasteActionsMenu, {
|
|
@@ -342,7 +342,18 @@ export const PasteActionsMenu = ({
|
|
|
342
342
|
// Choose positioning strategy based on whether the menu appears inline
|
|
343
343
|
// (right of cursor for short pastes) or anchored to the block ancestor
|
|
344
344
|
// (right side of content area for longer pastes / AI actions).
|
|
345
|
-
|
|
345
|
+
let positionCalculator;
|
|
346
|
+
try {
|
|
347
|
+
positionCalculator = useInlinePosition ? onInlinePositionCalculated(editorView, pasteEndPos, target, popupContentRef) : onPositionCalculated(editorView, pasteStartPos, pasteEndPos, target, effectiveScrollableElement);
|
|
348
|
+
} catch (error) {
|
|
349
|
+
positionCalculator = position => {
|
|
350
|
+
var _position$top3;
|
|
351
|
+
return {
|
|
352
|
+
...position,
|
|
353
|
+
top: (_position$top3 = position.top) !== null && _position$top3 !== void 0 ? _position$top3 : 0
|
|
354
|
+
};
|
|
355
|
+
};
|
|
356
|
+
}
|
|
346
357
|
return /*#__PURE__*/React.createElement(PopupWithListeners, {
|
|
347
358
|
target: target,
|
|
348
359
|
mountTo: mountTo,
|
|
@@ -160,7 +160,7 @@ export const getPasteMenuComponents = ({
|
|
|
160
160
|
const hasVisibleAiActions = getHasVisibleAiActions(api);
|
|
161
161
|
if (!hasVisibleAiActions) {
|
|
162
162
|
return /*#__PURE__*/React.createElement(Box, {
|
|
163
|
-
padding: "space.
|
|
163
|
+
padding: "space.100"
|
|
164
164
|
}, props.children);
|
|
165
165
|
}
|
|
166
166
|
return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isNotSingleLink } from './paste-menu-rules/isNotSingleLink';
|
|
2
|
+
const getUrlFromTextLinkNode = node => {
|
|
3
|
+
var _node$marks$0$attrs;
|
|
4
|
+
if (!node.isText || node.marks.length !== 1 || node.marks[0].type.name !== 'link') {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
const href = (_node$marks$0$attrs = node.marks[0].attrs) === null || _node$marks$0$attrs === void 0 ? void 0 : _node$marks$0$attrs.href;
|
|
8
|
+
return typeof href === 'string' && node.text === href ? href : undefined;
|
|
9
|
+
};
|
|
10
|
+
const getUrlFromInlineCardNode = node => {
|
|
11
|
+
var _node$attrs;
|
|
12
|
+
if (node.type.name !== 'inlineCard') {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
const url = (_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.url;
|
|
16
|
+
return typeof url === 'string' ? url : undefined;
|
|
17
|
+
};
|
|
18
|
+
const significantChildren = node => {
|
|
19
|
+
const children = [];
|
|
20
|
+
node.content.forEach(child => {
|
|
21
|
+
var _child$text;
|
|
22
|
+
if (child.isText && ((_child$text = child.text) === null || _child$text === void 0 ? void 0 : _child$text.trim()) === '') {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
children.push(child);
|
|
26
|
+
});
|
|
27
|
+
return children;
|
|
28
|
+
};
|
|
29
|
+
export const getSingleSmartLinkUrlFromSlice = slice => {
|
|
30
|
+
var _getUrlFromTextLinkNo, _getUrlFromTextLinkNo2;
|
|
31
|
+
if (!slice || isNotSingleLink(slice)) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
if (slice.content.childCount !== 1) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const topNode = slice.content.child(0);
|
|
38
|
+
const topNodeUrl = (_getUrlFromTextLinkNo = getUrlFromTextLinkNode(topNode)) !== null && _getUrlFromTextLinkNo !== void 0 ? _getUrlFromTextLinkNo : getUrlFromInlineCardNode(topNode);
|
|
39
|
+
if (topNodeUrl) {
|
|
40
|
+
return topNodeUrl;
|
|
41
|
+
}
|
|
42
|
+
if (topNode.type.name !== 'paragraph') {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const children = significantChildren(topNode);
|
|
46
|
+
if (children.length !== 1) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return (_getUrlFromTextLinkNo2 = getUrlFromTextLinkNode(children[0])) !== null && _getUrlFromTextLinkNo2 !== void 0 ? _getUrlFromTextLinkNo2 : getUrlFromInlineCardNode(children[0]);
|
|
50
|
+
};
|
|
@@ -15,30 +15,31 @@ const isUrlOnlyLinkTextNode = node => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Returns true if the slice represents a single
|
|
18
|
+
* Returns true if the slice represents a single smart-link card node.
|
|
19
19
|
* Handles two shapes:
|
|
20
|
-
* - paragraph > inlineCard
|
|
21
|
-
* - inlineCard
|
|
20
|
+
* - paragraph > inlineCard|blockCard (smartlink from editor/renderer, wrapped in a paragraph)
|
|
21
|
+
* - inlineCard|blockCard (top-level card with no paragraph wrapper)
|
|
22
22
|
*/
|
|
23
|
-
const
|
|
23
|
+
const isSingleSmartLinkCard = slice => {
|
|
24
|
+
const isSupportedCard = node => node.type.name === 'inlineCard' || node.type.name === 'blockCard';
|
|
24
25
|
if (slice.content.childCount !== 1) {
|
|
25
26
|
return false;
|
|
26
27
|
}
|
|
27
28
|
const topNode = slice.content.child(0);
|
|
28
29
|
|
|
29
|
-
// Top-level inlineCard (no paragraph wrapper)
|
|
30
|
-
if (topNode
|
|
30
|
+
// Top-level inlineCard/blockCard (no paragraph wrapper)
|
|
31
|
+
if (isSupportedCard(topNode)) {
|
|
31
32
|
return true;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
// paragraph > inlineCard
|
|
35
|
+
// paragraph > inlineCard/blockCard
|
|
35
36
|
if (topNode.type.name !== 'paragraph') {
|
|
36
37
|
return false;
|
|
37
38
|
}
|
|
38
39
|
if (topNode.childCount !== 1) {
|
|
39
40
|
return false;
|
|
40
41
|
}
|
|
41
|
-
return topNode.child(0)
|
|
42
|
+
return isSupportedCard(topNode.child(0));
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
/**
|
|
@@ -107,5 +108,5 @@ export const isNotSingleLink = slice => {
|
|
|
107
108
|
// No rich-text slice → plain text paste, not a single link in the relevant sense
|
|
108
109
|
return true;
|
|
109
110
|
}
|
|
110
|
-
return !isSingleBareLink(slice) && !
|
|
111
|
+
return !isSingleBareLink(slice) && !isSingleSmartLinkCard(slice);
|
|
111
112
|
};
|
|
@@ -2,6 +2,7 @@ import React, { useEffect } from 'react';
|
|
|
2
2
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
3
3
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
4
4
|
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
|
|
5
|
+
import { expValNoExposure } from '@atlaskit/tmp-editor-statsig/expVal';
|
|
5
6
|
import { hideToolbar, showToolbar } from './editor-commands/commands';
|
|
6
7
|
import { createPlugin } from './pm-plugins/main';
|
|
7
8
|
import { pasteOptionsPluginKey, ToolbarDropdownOption } from './types/types';
|
|
@@ -10,12 +11,32 @@ import { firePasteActionsMenuV2ExperimentExposure } from './ui/on-paste-actions-
|
|
|
10
11
|
import { PasteActionsMenu } from './ui/on-paste-actions-menu/PasteActionsMenu';
|
|
11
12
|
import { getPasteMenuComponents } from './ui/on-paste-actions-menu/PasteMenuComponents';
|
|
12
13
|
import { buildToolbar, isToolbarVisible } from './ui/toolbar';
|
|
14
|
+
import { getSingleSmartLinkUrlFromSlice } from './ui/utils/current-pasted-smart-link';
|
|
13
15
|
import { createPasteMenuRuleFactories } from './ui/utils/paste-menu-rules/rules';
|
|
14
16
|
export var pasteOptionsToolbarPlugin = function pasteOptionsToolbarPlugin(_ref) {
|
|
15
17
|
var _api$analytics;
|
|
16
18
|
var config = _ref.config,
|
|
17
19
|
api = _ref.api;
|
|
18
20
|
var editorAnalyticsAPI = api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions;
|
|
21
|
+
var getPasteMenuContext = function getPasteMenuContext() {
|
|
22
|
+
return {
|
|
23
|
+
getCurrentPasteRange: function getCurrentPasteRange() {
|
|
24
|
+
var _api$pasteOptionsTool;
|
|
25
|
+
var state = api === null || api === void 0 || (_api$pasteOptionsTool = api.pasteOptionsToolbarPlugin) === null || _api$pasteOptionsTool === void 0 ? void 0 : _api$pasteOptionsTool.sharedState.currentState();
|
|
26
|
+
if (!state) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
pasteEndPos: state.pasteEndPos,
|
|
31
|
+
pasteStartPos: state.pasteStartPos
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
getCurrentPastedUrl: function getCurrentPastedUrl() {
|
|
35
|
+
var _api$paste;
|
|
36
|
+
return getSingleSmartLinkUrlFromSlice(api === null || api === void 0 || (_api$paste = api.paste) === null || _api$paste === void 0 || (_api$paste = _api$paste.sharedState.currentState()) === null || _api$paste === void 0 || (_api$paste = _api$paste.lastContentPasted) === null || _api$paste === void 0 ? void 0 : _api$paste.pastedSlice);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
};
|
|
19
40
|
if (config !== null && config !== void 0 && config.usePopupBasedPasteActionsMenu && expValEqualsNoExposure('platform_editor_paste_actions_menu', 'isEnabled', true)) {
|
|
20
41
|
var _api$uiControlRegistr;
|
|
21
42
|
api === null || api === void 0 || (_api$uiControlRegistr = api.uiControlRegistry) === null || _api$uiControlRegistr === void 0 || _api$uiControlRegistr.actions.register(getPasteMenuComponents({
|
|
@@ -26,9 +47,9 @@ export var pasteOptionsToolbarPlugin = function pasteOptionsToolbarPlugin(_ref)
|
|
|
26
47
|
var _api$uiControlRegistr2;
|
|
27
48
|
var rules = function () {
|
|
28
49
|
var getContext = function getContext() {
|
|
29
|
-
var _api$
|
|
30
|
-
var pasteOptsState = api === null || api === void 0 || (_api$
|
|
31
|
-
var pasteState = api === null || api === void 0 || (_api$
|
|
50
|
+
var _api$pasteOptionsTool2, _api$paste2;
|
|
51
|
+
var pasteOptsState = api === null || api === void 0 || (_api$pasteOptionsTool2 = api.pasteOptionsToolbarPlugin) === null || _api$pasteOptionsTool2 === void 0 ? void 0 : _api$pasteOptionsTool2.sharedState.currentState();
|
|
52
|
+
var pasteState = api === null || api === void 0 || (_api$paste2 = api.paste) === null || _api$paste2 === void 0 ? void 0 : _api$paste2.sharedState.currentState();
|
|
32
53
|
return {
|
|
33
54
|
getPlaintextLength: function getPlaintextLength() {
|
|
34
55
|
var _pasteOptsState$plain;
|
|
@@ -57,7 +78,7 @@ export var pasteOptionsToolbarPlugin = function pasteOptionsToolbarPlugin(_ref)
|
|
|
57
78
|
};
|
|
58
79
|
return createPasteMenuRuleFactories(getContext);
|
|
59
80
|
}();
|
|
60
|
-
var productButtons = config.pasteMenuButtonsFactory(rules);
|
|
81
|
+
var productButtons = config.pasteMenuButtonsFactory(rules, getPasteMenuContext());
|
|
61
82
|
api === null || api === void 0 || (_api$uiControlRegistr2 = api.uiControlRegistry) === null || _api$uiControlRegistr2 === void 0 || _api$uiControlRegistr2.actions.register(productButtons);
|
|
62
83
|
}
|
|
63
84
|
return {
|
|
@@ -65,9 +86,9 @@ export var pasteOptionsToolbarPlugin = function pasteOptionsToolbarPlugin(_ref)
|
|
|
65
86
|
actions: {
|
|
66
87
|
getPasteMenuRules: function getPasteMenuRules() {
|
|
67
88
|
var getContext = function getContext() {
|
|
68
|
-
var _api$
|
|
69
|
-
var pasteOptsState = api === null || api === void 0 || (_api$
|
|
70
|
-
var pasteState = api === null || api === void 0 || (_api$
|
|
89
|
+
var _api$pasteOptionsTool3, _api$paste3;
|
|
90
|
+
var pasteOptsState = api === null || api === void 0 || (_api$pasteOptionsTool3 = api.pasteOptionsToolbarPlugin) === null || _api$pasteOptionsTool3 === void 0 ? void 0 : _api$pasteOptionsTool3.sharedState.currentState();
|
|
91
|
+
var pasteState = api === null || api === void 0 || (_api$paste3 = api.paste) === null || _api$paste3 === void 0 ? void 0 : _api$paste3.sharedState.currentState();
|
|
71
92
|
return {
|
|
72
93
|
getPlaintextLength: function getPlaintextLength() {
|
|
73
94
|
var _pasteOptsState$plain2;
|
|
@@ -151,7 +172,7 @@ export var pasteOptionsToolbarPlugin = function pasteOptionsToolbarPlugin(_ref)
|
|
|
151
172
|
popupsMountPoint = _ref3.popupsMountPoint,
|
|
152
173
|
popupsBoundariesElement = _ref3.popupsBoundariesElement,
|
|
153
174
|
popupsScrollableElement = _ref3.popupsScrollableElement;
|
|
154
|
-
if (!(config !== null && config !== void 0 && config.usePopupBasedPasteActionsMenu && expValEqualsNoExposure('platform_editor_paste_actions_menu', 'isEnabled', true)) || !editorView) {
|
|
175
|
+
if (!(config !== null && config !== void 0 && config.usePopupBasedPasteActionsMenu && (expValEqualsNoExposure('platform_editor_paste_actions_menu', 'isEnabled', true) || ['hasSpellingAndGrammar', 'hasAltAiActions'].includes(expValNoExposure('platform_editor_paste_actions_menu_v2', 'variant', 'control')))) || !editorView) {
|
|
155
176
|
return null;
|
|
156
177
|
}
|
|
157
178
|
return /*#__PURE__*/React.createElement(PasteActionsMenu, {
|
|
@@ -342,7 +342,17 @@ export var PasteActionsMenu = function PasteActionsMenu(_ref) {
|
|
|
342
342
|
// Choose positioning strategy based on whether the menu appears inline
|
|
343
343
|
// (right of cursor for short pastes) or anchored to the block ancestor
|
|
344
344
|
// (right side of content area for longer pastes / AI actions).
|
|
345
|
-
var positionCalculator
|
|
345
|
+
var positionCalculator;
|
|
346
|
+
try {
|
|
347
|
+
positionCalculator = useInlinePosition ? onInlinePositionCalculated(editorView, pasteEndPos, target, popupContentRef) : onPositionCalculated(editorView, pasteStartPos, pasteEndPos, target, effectiveScrollableElement);
|
|
348
|
+
} catch (error) {
|
|
349
|
+
positionCalculator = function positionCalculator(position) {
|
|
350
|
+
var _position$top3;
|
|
351
|
+
return _objectSpread(_objectSpread({}, position), {}, {
|
|
352
|
+
top: (_position$top3 = position.top) !== null && _position$top3 !== void 0 ? _position$top3 : 0
|
|
353
|
+
});
|
|
354
|
+
};
|
|
355
|
+
}
|
|
346
356
|
return /*#__PURE__*/React.createElement(PopupWithListeners, {
|
|
347
357
|
target: target,
|
|
348
358
|
mountTo: mountTo,
|
|
@@ -158,7 +158,7 @@ export var getPasteMenuComponents = function getPasteMenuComponents(_ref3) {
|
|
|
158
158
|
var hasVisibleAiActions = getHasVisibleAiActions(api);
|
|
159
159
|
if (!hasVisibleAiActions) {
|
|
160
160
|
return /*#__PURE__*/React.createElement(Box, {
|
|
161
|
-
padding: "space.
|
|
161
|
+
padding: "space.100"
|
|
162
162
|
}, props.children);
|
|
163
163
|
}
|
|
164
164
|
return /*#__PURE__*/React.createElement(ToolbarDropdownItemSection, {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isNotSingleLink } from './paste-menu-rules/isNotSingleLink';
|
|
2
|
+
var getUrlFromTextLinkNode = function getUrlFromTextLinkNode(node) {
|
|
3
|
+
var _node$marks$0$attrs;
|
|
4
|
+
if (!node.isText || node.marks.length !== 1 || node.marks[0].type.name !== 'link') {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
var href = (_node$marks$0$attrs = node.marks[0].attrs) === null || _node$marks$0$attrs === void 0 ? void 0 : _node$marks$0$attrs.href;
|
|
8
|
+
return typeof href === 'string' && node.text === href ? href : undefined;
|
|
9
|
+
};
|
|
10
|
+
var getUrlFromInlineCardNode = function getUrlFromInlineCardNode(node) {
|
|
11
|
+
var _node$attrs;
|
|
12
|
+
if (node.type.name !== 'inlineCard') {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
var url = (_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.url;
|
|
16
|
+
return typeof url === 'string' ? url : undefined;
|
|
17
|
+
};
|
|
18
|
+
var significantChildren = function significantChildren(node) {
|
|
19
|
+
var children = [];
|
|
20
|
+
node.content.forEach(function (child) {
|
|
21
|
+
var _child$text;
|
|
22
|
+
if (child.isText && ((_child$text = child.text) === null || _child$text === void 0 ? void 0 : _child$text.trim()) === '') {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
children.push(child);
|
|
26
|
+
});
|
|
27
|
+
return children;
|
|
28
|
+
};
|
|
29
|
+
export var getSingleSmartLinkUrlFromSlice = function getSingleSmartLinkUrlFromSlice(slice) {
|
|
30
|
+
var _getUrlFromTextLinkNo, _getUrlFromTextLinkNo2;
|
|
31
|
+
if (!slice || isNotSingleLink(slice)) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
if (slice.content.childCount !== 1) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
var topNode = slice.content.child(0);
|
|
38
|
+
var topNodeUrl = (_getUrlFromTextLinkNo = getUrlFromTextLinkNode(topNode)) !== null && _getUrlFromTextLinkNo !== void 0 ? _getUrlFromTextLinkNo : getUrlFromInlineCardNode(topNode);
|
|
39
|
+
if (topNodeUrl) {
|
|
40
|
+
return topNodeUrl;
|
|
41
|
+
}
|
|
42
|
+
if (topNode.type.name !== 'paragraph') {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
var children = significantChildren(topNode);
|
|
46
|
+
if (children.length !== 1) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return (_getUrlFromTextLinkNo2 = getUrlFromTextLinkNode(children[0])) !== null && _getUrlFromTextLinkNo2 !== void 0 ? _getUrlFromTextLinkNo2 : getUrlFromInlineCardNode(children[0]);
|
|
50
|
+
};
|
|
@@ -15,30 +15,33 @@ var isUrlOnlyLinkTextNode = function isUrlOnlyLinkTextNode(node) {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Returns true if the slice represents a single
|
|
18
|
+
* Returns true if the slice represents a single smart-link card node.
|
|
19
19
|
* Handles two shapes:
|
|
20
|
-
* - paragraph > inlineCard
|
|
21
|
-
* - inlineCard
|
|
20
|
+
* - paragraph > inlineCard|blockCard (smartlink from editor/renderer, wrapped in a paragraph)
|
|
21
|
+
* - inlineCard|blockCard (top-level card with no paragraph wrapper)
|
|
22
22
|
*/
|
|
23
|
-
var
|
|
23
|
+
var isSingleSmartLinkCard = function isSingleSmartLinkCard(slice) {
|
|
24
|
+
var isSupportedCard = function isSupportedCard(node) {
|
|
25
|
+
return node.type.name === 'inlineCard' || node.type.name === 'blockCard';
|
|
26
|
+
};
|
|
24
27
|
if (slice.content.childCount !== 1) {
|
|
25
28
|
return false;
|
|
26
29
|
}
|
|
27
30
|
var topNode = slice.content.child(0);
|
|
28
31
|
|
|
29
|
-
// Top-level inlineCard (no paragraph wrapper)
|
|
30
|
-
if (topNode
|
|
32
|
+
// Top-level inlineCard/blockCard (no paragraph wrapper)
|
|
33
|
+
if (isSupportedCard(topNode)) {
|
|
31
34
|
return true;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
// paragraph > inlineCard
|
|
37
|
+
// paragraph > inlineCard/blockCard
|
|
35
38
|
if (topNode.type.name !== 'paragraph') {
|
|
36
39
|
return false;
|
|
37
40
|
}
|
|
38
41
|
if (topNode.childCount !== 1) {
|
|
39
42
|
return false;
|
|
40
43
|
}
|
|
41
|
-
return topNode.child(0)
|
|
44
|
+
return isSupportedCard(topNode.child(0));
|
|
42
45
|
};
|
|
43
46
|
|
|
44
47
|
/**
|
|
@@ -107,5 +110,5 @@ export var isNotSingleLink = function isNotSingleLink(slice) {
|
|
|
107
110
|
// No rich-text slice → plain text paste, not a single link in the relevant sense
|
|
108
111
|
return true;
|
|
109
112
|
}
|
|
110
|
-
return !isSingleBareLink(slice) && !
|
|
113
|
+
return !isSingleBareLink(slice) && !isSingleSmartLinkCard(slice);
|
|
111
114
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getSingleSmartLinkUrlFromSlice } from '../ui/utils/current-pasted-smart-link';
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export type { PasteOptionsToolbarPlugin, PasteOptionsToolbarPluginDependencies, PasteOptionsToolbarSharedState, } from '../pasteOptionsToolbarPluginType';
|
|
1
|
+
export type { PasteOptionsToolbarPlugin, PasteOptionsToolbarPluginConfiguration, PasteOptionsToolbarPluginDependencies, PasteOptionsToolbarPasteMenuContext, PasteOptionsToolbarSharedState, } from '../pasteOptionsToolbarPluginType';
|
|
2
|
+
export type { PasteMenuRuleFactories } from '../ui/utils/paste-menu-rules/types';
|
|
@@ -20,6 +20,32 @@ export interface PasteOptionsToolbarSharedState {
|
|
|
20
20
|
showLegacyOptions: boolean;
|
|
21
21
|
showToolbar: boolean;
|
|
22
22
|
}
|
|
23
|
+
export type PasteOptionsToolbarPasteMenuContext = {
|
|
24
|
+
getCurrentPastedUrl: () => string | undefined;
|
|
25
|
+
getCurrentPasteRange: () => {
|
|
26
|
+
pasteEndPos: number;
|
|
27
|
+
pasteStartPos: number;
|
|
28
|
+
} | undefined;
|
|
29
|
+
};
|
|
30
|
+
export type PasteOptionsToolbarPluginConfiguration = {
|
|
31
|
+
/**
|
|
32
|
+
* Optional factory for composing product-specific paste menu buttons.
|
|
33
|
+
* Called with the pre-bound rule factories so products can compose
|
|
34
|
+
* `isHidden` callbacks before plugin setup.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* pasteMenuButtonsFactory: (rules) => [
|
|
38
|
+
* {
|
|
39
|
+
* type: 'menu-item',
|
|
40
|
+
* key: 'my-product-button',
|
|
41
|
+
* isHidden: rules.allRules(rules.notProseRule, rules.minCharsRule(100)),
|
|
42
|
+
* component: () => <MyProductButton />,
|
|
43
|
+
* },
|
|
44
|
+
* ]
|
|
45
|
+
*/
|
|
46
|
+
pasteMenuButtonsFactory?: (rules: PasteMenuRuleFactories, context?: PasteOptionsToolbarPasteMenuContext) => RegisterComponent[];
|
|
47
|
+
usePopupBasedPasteActionsMenu?: boolean;
|
|
48
|
+
};
|
|
23
49
|
export type PasteOptionsToolbarPlugin = NextEditorPlugin<'pasteOptionsToolbarPlugin', {
|
|
24
50
|
actions: {
|
|
25
51
|
/**
|
|
@@ -35,24 +61,6 @@ export type PasteOptionsToolbarPlugin = NextEditorPlugin<'pasteOptionsToolbarPlu
|
|
|
35
61
|
getPasteMenuRules: () => PasteMenuRuleFactories;
|
|
36
62
|
};
|
|
37
63
|
dependencies: PasteOptionsToolbarPluginDependencies;
|
|
38
|
-
pluginConfiguration?:
|
|
39
|
-
/**
|
|
40
|
-
* Optional factory for composing product-specific paste menu buttons.
|
|
41
|
-
* Called with the pre-bound rule factories so products can compose
|
|
42
|
-
* `isHidden` callbacks before plugin setup.
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* pasteMenuButtonsFactory: (rules) => [
|
|
46
|
-
* {
|
|
47
|
-
* type: 'menu-item',
|
|
48
|
-
* key: 'my-product-button',
|
|
49
|
-
* isHidden: rules.allRules(rules.notProseRule, rules.minCharsRule(100)),
|
|
50
|
-
* component: () => <MyProductButton />,
|
|
51
|
-
* },
|
|
52
|
-
* ]
|
|
53
|
-
*/
|
|
54
|
-
pasteMenuButtonsFactory?: (rules: PasteMenuRuleFactories) => RegisterComponent[];
|
|
55
|
-
usePopupBasedPasteActionsMenu?: boolean;
|
|
56
|
-
};
|
|
64
|
+
pluginConfiguration?: PasteOptionsToolbarPluginConfiguration;
|
|
57
65
|
sharedState: PasteOptionsToolbarSharedState;
|
|
58
66
|
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getSingleSmartLinkUrlFromSlice } from '../ui/utils/current-pasted-smart-link';
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export type { PasteOptionsToolbarPlugin, PasteOptionsToolbarPluginDependencies, PasteOptionsToolbarSharedState, } from '../pasteOptionsToolbarPluginType';
|
|
1
|
+
export type { PasteOptionsToolbarPlugin, PasteOptionsToolbarPluginConfiguration, PasteOptionsToolbarPluginDependencies, PasteOptionsToolbarPasteMenuContext, PasteOptionsToolbarSharedState, } from '../pasteOptionsToolbarPluginType';
|
|
2
|
+
export type { PasteMenuRuleFactories } from '../ui/utils/paste-menu-rules/types';
|
|
@@ -20,6 +20,32 @@ export interface PasteOptionsToolbarSharedState {
|
|
|
20
20
|
showLegacyOptions: boolean;
|
|
21
21
|
showToolbar: boolean;
|
|
22
22
|
}
|
|
23
|
+
export type PasteOptionsToolbarPasteMenuContext = {
|
|
24
|
+
getCurrentPastedUrl: () => string | undefined;
|
|
25
|
+
getCurrentPasteRange: () => {
|
|
26
|
+
pasteEndPos: number;
|
|
27
|
+
pasteStartPos: number;
|
|
28
|
+
} | undefined;
|
|
29
|
+
};
|
|
30
|
+
export type PasteOptionsToolbarPluginConfiguration = {
|
|
31
|
+
/**
|
|
32
|
+
* Optional factory for composing product-specific paste menu buttons.
|
|
33
|
+
* Called with the pre-bound rule factories so products can compose
|
|
34
|
+
* `isHidden` callbacks before plugin setup.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* pasteMenuButtonsFactory: (rules) => [
|
|
38
|
+
* {
|
|
39
|
+
* type: 'menu-item',
|
|
40
|
+
* key: 'my-product-button',
|
|
41
|
+
* isHidden: rules.allRules(rules.notProseRule, rules.minCharsRule(100)),
|
|
42
|
+
* component: () => <MyProductButton />,
|
|
43
|
+
* },
|
|
44
|
+
* ]
|
|
45
|
+
*/
|
|
46
|
+
pasteMenuButtonsFactory?: (rules: PasteMenuRuleFactories, context?: PasteOptionsToolbarPasteMenuContext) => RegisterComponent[];
|
|
47
|
+
usePopupBasedPasteActionsMenu?: boolean;
|
|
48
|
+
};
|
|
23
49
|
export type PasteOptionsToolbarPlugin = NextEditorPlugin<'pasteOptionsToolbarPlugin', {
|
|
24
50
|
actions: {
|
|
25
51
|
/**
|
|
@@ -35,24 +61,6 @@ export type PasteOptionsToolbarPlugin = NextEditorPlugin<'pasteOptionsToolbarPlu
|
|
|
35
61
|
getPasteMenuRules: () => PasteMenuRuleFactories;
|
|
36
62
|
};
|
|
37
63
|
dependencies: PasteOptionsToolbarPluginDependencies;
|
|
38
|
-
pluginConfiguration?:
|
|
39
|
-
/**
|
|
40
|
-
* Optional factory for composing product-specific paste menu buttons.
|
|
41
|
-
* Called with the pre-bound rule factories so products can compose
|
|
42
|
-
* `isHidden` callbacks before plugin setup.
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* pasteMenuButtonsFactory: (rules) => [
|
|
46
|
-
* {
|
|
47
|
-
* type: 'menu-item',
|
|
48
|
-
* key: 'my-product-button',
|
|
49
|
-
* isHidden: rules.allRules(rules.notProseRule, rules.minCharsRule(100)),
|
|
50
|
-
* component: () => <MyProductButton />,
|
|
51
|
-
* },
|
|
52
|
-
* ]
|
|
53
|
-
*/
|
|
54
|
-
pasteMenuButtonsFactory?: (rules: PasteMenuRuleFactories) => RegisterComponent[];
|
|
55
|
-
usePopupBasedPasteActionsMenu?: boolean;
|
|
56
|
-
};
|
|
64
|
+
pluginConfiguration?: PasteOptionsToolbarPluginConfiguration;
|
|
57
65
|
sharedState: PasteOptionsToolbarSharedState;
|
|
58
66
|
}>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-paste-options-toolbar",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.4.0",
|
|
4
4
|
"description": "Paste options toolbar for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -30,26 +30,26 @@
|
|
|
30
30
|
"atlaskit:src": "src/index.ts",
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@atlaskit/css": "^0.19.0",
|
|
33
|
-
"@atlaskit/dropdown-menu": "^16.
|
|
33
|
+
"@atlaskit/dropdown-menu": "^16.10.0",
|
|
34
34
|
"@atlaskit/editor-markdown-transformer": "^5.21.0",
|
|
35
35
|
"@atlaskit/editor-plugin-analytics": "^10.1.0",
|
|
36
36
|
"@atlaskit/editor-plugin-paste": "^11.2.0",
|
|
37
37
|
"@atlaskit/editor-plugin-ui-control-registry": "^4.1.0",
|
|
38
38
|
"@atlaskit/editor-prosemirror": "^7.3.0",
|
|
39
39
|
"@atlaskit/editor-shared-styles": "^3.11.0",
|
|
40
|
-
"@atlaskit/editor-toolbar": "^1.
|
|
40
|
+
"@atlaskit/editor-toolbar": "^1.9.0",
|
|
41
41
|
"@atlaskit/editor-ui-control-model": "^1.2.0",
|
|
42
42
|
"@atlaskit/icon": "^35.3.0",
|
|
43
43
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
44
44
|
"@atlaskit/primitives": "^19.0.0",
|
|
45
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
45
|
+
"@atlaskit/tmp-editor-statsig": "^86.0.0",
|
|
46
46
|
"@atlaskit/tokens": "^13.1.0",
|
|
47
47
|
"@babel/runtime": "^7.0.0",
|
|
48
48
|
"@compiled/react": "^0.20.0",
|
|
49
49
|
"@emotion/react": "^11.7.1"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"@atlaskit/editor-common": "^114.
|
|
52
|
+
"@atlaskit/editor-common": "^114.54.0",
|
|
53
53
|
"react": "^18.2.0",
|
|
54
54
|
"react-dom": "^18.2.0",
|
|
55
55
|
"react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
|