@atlaskit/editor-plugin-block-controls 3.15.11 → 3.16.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.
Files changed (26) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/pm-plugins/decorations-quick-insert-button.js +25 -0
  3. package/dist/cjs/pm-plugins/main.js +55 -14
  4. package/dist/cjs/pm-plugins/quick-insert-calculate-position.js +70 -0
  5. package/dist/cjs/pm-plugins/vanilla-quick-insert.js +190 -0
  6. package/dist/cjs/pm-plugins/vanilla-tooltip.js +179 -0
  7. package/dist/cjs/ui/global-styles.js +86 -1
  8. package/dist/es2019/pm-plugins/decorations-quick-insert-button.js +25 -0
  9. package/dist/es2019/pm-plugins/main.js +58 -16
  10. package/dist/es2019/pm-plugins/quick-insert-calculate-position.js +64 -0
  11. package/dist/es2019/pm-plugins/vanilla-quick-insert.js +189 -0
  12. package/dist/es2019/pm-plugins/vanilla-tooltip.js +147 -0
  13. package/dist/es2019/ui/global-styles.js +84 -1
  14. package/dist/esm/pm-plugins/decorations-quick-insert-button.js +25 -0
  15. package/dist/esm/pm-plugins/main.js +55 -14
  16. package/dist/esm/pm-plugins/quick-insert-calculate-position.js +64 -0
  17. package/dist/esm/pm-plugins/vanilla-quick-insert.js +183 -0
  18. package/dist/esm/pm-plugins/vanilla-tooltip.js +172 -0
  19. package/dist/esm/ui/global-styles.js +86 -1
  20. package/dist/types/pm-plugins/quick-insert-calculate-position.d.ts +12 -0
  21. package/dist/types/pm-plugins/vanilla-quick-insert.d.ts +21 -0
  22. package/dist/types/pm-plugins/vanilla-tooltip.d.ts +27 -0
  23. package/dist/types-ts4.5/pm-plugins/quick-insert-calculate-position.d.ts +12 -0
  24. package/dist/types-ts4.5/pm-plugins/vanilla-quick-insert.d.ts +21 -0
  25. package/dist/types-ts4.5/pm-plugins/vanilla-tooltip.d.ts +27 -0
  26. package/package.json +8 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 3.16.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#164171](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/164171)
8
+ [`6e761beb64a85`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6e761beb64a85) -
9
+ ED-28155 add dnd performance tracker
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+
15
+ ## 3.15.12
16
+
17
+ ### Patch Changes
18
+
19
+ - [#162142](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/162142)
20
+ [`b92367d4d728b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/b92367d4d728b) -
21
+ Migrating the quick insert decoration button to vanilla javascript to improve performance
22
+ - Updated dependencies
23
+
3
24
  ## 3.15.11
4
25
 
5
26
  ### Patch Changes
@@ -11,6 +11,7 @@ var _view = require("@atlaskit/editor-prosemirror/view");
11
11
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
12
12
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
13
13
  var _quickInsertButton = require("../ui/quick-insert-button");
14
+ var _vanillaQuickInsert = require("./vanilla-quick-insert");
14
15
  var TYPE_QUICK_INSERT = 'INSERT_BUTTON';
15
16
  var findQuickInsertInsertButtonDecoration = exports.findQuickInsertInsertButtonDecoration = function findQuickInsertInsertButtonDecoration(decorations, from, to) {
16
17
  return decorations.find(from, to, function (spec) {
@@ -19,6 +20,7 @@ var findQuickInsertInsertButtonDecoration = exports.findQuickInsertInsertButtonD
19
20
  };
20
21
  var quickInsertButtonDecoration = exports.quickInsertButtonDecoration = function quickInsertButtonDecoration(api, formatMessage, rootPos, anchorName, nodeType, nodeViewPortalProviderAPI, rootAnchorName, rootNodeType, anchorRectCache) {
21
22
  var key = (0, _uuid.default)();
23
+ var cleanupCallbacks = [];
22
24
  var widgetSpec = (0, _experiments.editorExperiment)('platform_editor_breakout_resizing', true) ? {
23
25
  side: -2,
24
26
  type: TYPE_QUICK_INSERT,
@@ -33,6 +35,9 @@ var quickInsertButtonDecoration = exports.quickInsertButtonDecoration = function
33
35
  if ((0, _platformFeatureFlags.fg)('platform_editor_fix_widget_destroy')) {
34
36
  nodeViewPortalProviderAPI.remove(key);
35
37
  }
38
+ cleanupCallbacks.forEach(function (cb) {
39
+ cb();
40
+ });
36
41
  }
37
42
  } : {
38
43
  side: -2,
@@ -41,6 +46,9 @@ var quickInsertButtonDecoration = exports.quickInsertButtonDecoration = function
41
46
  if ((0, _platformFeatureFlags.fg)('platform_editor_fix_widget_destroy')) {
42
47
  nodeViewPortalProviderAPI.remove(key);
43
48
  }
49
+ cleanupCallbacks.forEach(function (cb) {
50
+ cb();
51
+ });
44
52
  }
45
53
  };
46
54
  return _view.Decoration.widget(rootPos, function (view, getPos) {
@@ -48,6 +56,23 @@ var quickInsertButtonDecoration = exports.quickInsertButtonDecoration = function
48
56
  element.contentEditable = 'false';
49
57
  element.setAttribute('data-blocks-quick-insert-container', 'true');
50
58
  element.setAttribute('data-testid', 'block-ctrl-quick-insert-button');
59
+ if ((0, _experiments.editorExperiment)('platform_editor_block_control_optimise_render', true, {
60
+ exposure: true
61
+ })) {
62
+ var vanillaElement = (0, _vanillaQuickInsert.createVanillaButton)({
63
+ formatMessage: formatMessage,
64
+ api: api,
65
+ view: view,
66
+ getPos: getPos,
67
+ cleanupCallbacks: cleanupCallbacks,
68
+ rootAnchorName: rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : nodeType,
69
+ anchorName: anchorName,
70
+ rootNodeType: rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType,
71
+ anchorRectCache: anchorRectCache
72
+ });
73
+ element.appendChild(vanillaElement);
74
+ return element;
75
+ }
51
76
 
52
77
  // all changes already under experiment
53
78
  if ((0, _platformFeatureFlags.fg)('platform_editor_controls_widget_visibility')) {
@@ -38,6 +38,12 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
38
38
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
39
39
  var key = exports.key = new _state.PluginKey('blockControls');
40
40
  var EDITOR_BLOCKS_DRAG_INIT = 'Editor Blocks Drag Initialization Time';
41
+ var EDITOR_BLOCKS_DROP_INIT = 'Editor Blocks Drop Initialization Time';
42
+ var scheduleCallback = function scheduleCallback(cb, options) {
43
+ return 'requestIdleCallback' in window ? requestIdleCallback(cb, _objectSpread({
44
+ timeout: 5000
45
+ }, options)) : requestAnimationFrame(cb);
46
+ };
41
47
  var isHTMLElement = function isHTMLElement(element) {
42
48
  return element instanceof HTMLElement;
43
49
  };
@@ -49,27 +55,36 @@ var destroyFn = function destroyFn(api, editorView) {
49
55
  element: scrollable
50
56
  }));
51
57
  }
58
+ var dragInitializationDuration = 0;
52
59
  cleanupFn.push((0, _adapter.monitorForElements)({
53
60
  canMonitor: function canMonitor(_ref) {
54
61
  var source = _ref.source;
55
62
  return source.data.type === 'element';
56
63
  },
57
64
  onDrag: function onDrag() {
58
- if ((0, _performanceMeasures.isMeasuring)(EDITOR_BLOCKS_DRAG_INIT)) {
59
- (0, _performanceMeasures.stopMeasure)(EDITOR_BLOCKS_DRAG_INIT, function (duration, startTime) {
60
- var _api$analytics;
61
- var state = editorView.state;
62
- api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent({
63
- action: _analytics.ACTION.BLOCKS_DRAG_INIT,
64
- actionSubject: _analytics.ACTION_SUBJECT.EDITOR,
65
- eventType: _analytics.EVENT_TYPE.OPERATIONAL,
66
- attributes: {
67
- duration: duration,
68
- startTime: startTime,
69
- nodesCount: state.doc.nodeSize
70
- }
65
+ if ((0, _platformFeatureFlags.fg)('platform_editor_drag_and_drop_perf_analytics')) {
66
+ if ((0, _performanceMeasures.isMeasuring)(EDITOR_BLOCKS_DRAG_INIT)) {
67
+ (0, _performanceMeasures.stopMeasure)(EDITOR_BLOCKS_DRAG_INIT, function (duration) {
68
+ dragInitializationDuration = duration;
71
69
  });
72
- });
70
+ }
71
+ } else {
72
+ if ((0, _performanceMeasures.isMeasuring)(EDITOR_BLOCKS_DRAG_INIT)) {
73
+ (0, _performanceMeasures.stopMeasure)(EDITOR_BLOCKS_DRAG_INIT, function (duration, startTime) {
74
+ var _api$analytics;
75
+ var state = editorView.state;
76
+ api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent({
77
+ action: _analytics.ACTION.BLOCKS_DRAG_INIT,
78
+ actionSubject: _analytics.ACTION_SUBJECT.EDITOR,
79
+ eventType: _analytics.EVENT_TYPE.OPERATIONAL,
80
+ attributes: {
81
+ duration: duration,
82
+ startTime: startTime,
83
+ nodesCount: state.doc.nodeSize
84
+ }
85
+ });
86
+ });
87
+ }
73
88
  }
74
89
  },
75
90
  onDragStart: function onDragStart() {
@@ -84,6 +99,9 @@ var destroyFn = function destroyFn(api, editorView) {
84
99
  if (isHTMLElement(scrollable)) {
85
100
  scrollable.style.setProperty('scroll-behavior', null);
86
101
  }
102
+ if ((0, _platformFeatureFlags.fg)('platform_editor_drag_and_drop_perf_analytics')) {
103
+ (0, _performanceMeasures.startMeasure)(EDITOR_BLOCKS_DROP_INIT);
104
+ }
87
105
  if (!api) {
88
106
  return;
89
107
  }
@@ -160,6 +178,29 @@ var destroyFn = function destroyFn(api, editorView) {
160
178
  lastDragCancelled: lastDragCancelled
161
179
  }));
162
180
  });
181
+ if ((0, _platformFeatureFlags.fg)('platform_editor_drag_and_drop_perf_analytics')) {
182
+ // wait for the idle callback to ensure that the drag operation has completed
183
+ scheduleCallback(function () {
184
+ if ((0, _performanceMeasures.isMeasuring)(EDITOR_BLOCKS_DROP_INIT)) {
185
+ (0, _performanceMeasures.stopMeasure)(EDITOR_BLOCKS_DROP_INIT, function (duration) {
186
+ var _api$analytics3;
187
+ var isCancelled = location.current.dropTargets.length === 0;
188
+ api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.fireAnalyticsEvent({
189
+ action: _analytics.ACTION.ENDED,
190
+ eventType: _analytics.EVENT_TYPE.TRACK,
191
+ actionSubject: _analytics.ACTION_SUBJECT.DRAG,
192
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
193
+ attributes: {
194
+ dragInitializationDuration: dragInitializationDuration,
195
+ dropProcessingDuration: duration,
196
+ isCancelled: isCancelled,
197
+ nodesCount: editorView.state.doc.nodeSize
198
+ }
199
+ });
200
+ });
201
+ }
202
+ });
203
+ }
163
204
  }
164
205
  }));
165
206
  return _combine.combine.apply(void 0, cleanupFn);
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.calculatePosition = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _consts = require("../ui/consts");
10
+ var _anchorName = require("../ui/utils/anchor-name");
11
+ var _dragHandlePositions = require("./utils/drag-handle-positions");
12
+ var _widgetPositions = require("./utils/widget-positions");
13
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
14
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
15
+ // Adapted from `src/ui/drag-handle.tsx` as positioning logic is similar
16
+ // CHANGES - added an offset so quick insert button can be positioned beside drag handle
17
+ // CHANGES - removed `editorExperiment('nested-dnd', true)` check and rootNodeType calculation
18
+ // CHANGES - replace anchorName with rootAnchorName
19
+ // CHANGES - `removed editorExperiment('advanced_layouts', true) && isLayoutColumn` checks as quick insert button will not be positioned for layout column
20
+ var calculatePosition = exports.calculatePosition = function calculatePosition(_ref) {
21
+ var rootAnchorName = _ref.rootAnchorName,
22
+ anchorName = _ref.anchorName,
23
+ view = _ref.view,
24
+ getPos = _ref.getPos,
25
+ rootNodeType = _ref.rootNodeType,
26
+ macroInteractionUpdates = _ref.macroInteractionUpdates,
27
+ anchorRectCache = _ref.anchorRectCache;
28
+ var supportsAnchor = CSS.supports('top', "anchor(".concat(rootAnchorName, " start)")) && CSS.supports('left', "anchor(".concat(rootAnchorName, " start)"));
29
+ var safeAnchorName = (0, _anchorName.refreshAnchorName)({
30
+ getPos: getPos,
31
+ view: view,
32
+ anchorName: rootAnchorName
33
+ });
34
+ var dom = view.dom.querySelector("[data-drag-handler-anchor-name=\"".concat(safeAnchorName, "\"]"));
35
+ var hasResizer = rootNodeType === 'table' || rootNodeType === 'mediaSingle';
36
+ var isExtension = rootNodeType === 'extension' || rootNodeType === 'bodiedExtension';
37
+ var isBlockCard = rootNodeType === 'blockCard';
38
+ var isEmbedCard = rootNodeType === 'embedCard';
39
+ var isMacroInteractionUpdates = macroInteractionUpdates && isExtension;
40
+ var innerContainer = null;
41
+ if (dom) {
42
+ if (isEmbedCard) {
43
+ innerContainer = dom.querySelector('.rich-media-item');
44
+ } else if (hasResizer) {
45
+ innerContainer = dom.querySelector('.resizer-item');
46
+ } else if (isExtension) {
47
+ innerContainer = dom.querySelector('.extension-container[data-layout]');
48
+ } else if (isBlockCard) {
49
+ //specific to datasource blockCard
50
+ innerContainer = dom.querySelector('.datasourceView-content-inner-wrap');
51
+ }
52
+ }
53
+ var isEdgeCase = (hasResizer || isExtension || isEmbedCard || isBlockCard) && innerContainer;
54
+ var isSticky = (0, _dragHandlePositions.shouldBeSticky)(rootNodeType);
55
+ var bottom = (0, _dragHandlePositions.getControlBottomCSSValue)(safeAnchorName || anchorName, isSticky, true);
56
+ if (supportsAnchor) {
57
+ return _objectSpread({
58
+ left: isEdgeCase ? "calc(anchor(".concat(safeAnchorName, " start) + ").concat((0, _widgetPositions.getLeftPositionForRootElement)(dom, rootNodeType, _consts.QUICK_INSERT_DIMENSIONS, innerContainer, isMacroInteractionUpdates), " + -").concat(_consts.QUICK_INSERT_LEFT_OFFSET, "px)") : "calc(anchor(".concat(safeAnchorName, " start) - ").concat(_consts.QUICK_INSERT_DIMENSIONS.width, "px - ").concat((0, _consts.rootElementGap)(rootNodeType), "px + -").concat(_consts.QUICK_INSERT_LEFT_OFFSET, "px)"),
59
+ top: "calc(anchor(".concat(safeAnchorName, " start) + ").concat((0, _consts.topPositionAdjustment)(rootNodeType), "px)")
60
+ }, bottom);
61
+ }
62
+
63
+ // expensive, calls offsetHeight
64
+ var nodeHeight = (0, _dragHandlePositions.getNodeHeight)(dom, safeAnchorName || anchorName, anchorRectCache) || 0;
65
+ var height = (0, _dragHandlePositions.getControlHeightCSSValue)(nodeHeight, isSticky, true, "var(--ds-space-300, 24px)");
66
+ return _objectSpread({
67
+ left: isEdgeCase ? "calc(".concat((dom === null || dom === void 0 ? void 0 : dom.offsetLeft) || 0, "px + ").concat((0, _widgetPositions.getLeftPositionForRootElement)(dom, rootNodeType, _consts.QUICK_INSERT_DIMENSIONS, innerContainer, isMacroInteractionUpdates), " + -").concat(_consts.QUICK_INSERT_LEFT_OFFSET, "px)") : "calc(".concat((0, _widgetPositions.getLeftPositionForRootElement)(dom, rootNodeType, _consts.QUICK_INSERT_DIMENSIONS, innerContainer, isMacroInteractionUpdates), " + -").concat(_consts.QUICK_INSERT_LEFT_OFFSET, "px)"),
68
+ top: (0, _dragHandlePositions.getTopPosition)(dom, rootNodeType)
69
+ }, height);
70
+ };
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.createVanillaButton = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _lazyNodeView = require("@atlaskit/editor-common/lazy-node-view");
10
+ var _messages = require("@atlaskit/editor-common/messages");
11
+ var _model = require("@atlaskit/editor-prosemirror/model");
12
+ var _state = require("@atlaskit/editor-prosemirror/state");
13
+ var _utils = require("@atlaskit/editor-prosemirror/utils");
14
+ var _cellSelection = require("@atlaskit/editor-tables/cell-selection");
15
+ var _documentChecks = require("../ui/utils/document-checks");
16
+ var _editorCommands = require("../ui/utils/editor-commands");
17
+ var _quickInsertCalculatePosition = require("./quick-insert-calculate-position");
18
+ var _vanillaTooltip = require("./vanilla-tooltip");
19
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
20
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
21
+ // Based on platform/packages/design-system/icon/svgs/utility/add.svg
22
+ var plusButtonDOM = ['http://www.w3.org/2000/svg svg', {
23
+ width: '12',
24
+ height: '12',
25
+ fill: 'none',
26
+ viewBox: '0 0 12 12',
27
+ style: 'pointer-events: none;'
28
+ }, ['http://www.w3.org/2000/svg path', {
29
+ fill: 'currentcolor',
30
+ 'fill-rule': 'evenodd',
31
+ d: 'M5.25 6.75V11h1.5V6.75H11v-1.5H6.75V1h-1.5v4.25H1v1.5z',
32
+ 'clip-rule': 'evenodd',
33
+ style: 'pointer-events: none;'
34
+ }]];
35
+ var vanillaQuickInsert = function vanillaQuickInsert(_ref) {
36
+ var _api$featureFlags$sha, _api$featureFlags;
37
+ var view = _ref.view,
38
+ getPos = _ref.getPos,
39
+ rootNodeType = _ref.rootNodeType,
40
+ anchorRectCache = _ref.anchorRectCache,
41
+ anchorName = _ref.anchorName,
42
+ rootAnchorName = _ref.rootAnchorName,
43
+ api = _ref.api;
44
+ return ['div', {
45
+ style: (0, _lazyNodeView.convertToInlineCss)(_objectSpread({
46
+ position: 'absolute'
47
+ }, (0, _quickInsertCalculatePosition.calculatePosition)({
48
+ rootAnchorName: rootAnchorName,
49
+ anchorName: anchorName,
50
+ view: view,
51
+ getPos: getPos,
52
+ rootNodeType: rootNodeType,
53
+ macroInteractionUpdates: (_api$featureFlags$sha = api === null || api === void 0 || (_api$featureFlags = api.featureFlags) === null || _api$featureFlags === void 0 || (_api$featureFlags = _api$featureFlags.sharedState.currentState()) === null || _api$featureFlags === void 0 ? void 0 : _api$featureFlags.macroInteractionUpdates) !== null && _api$featureFlags$sha !== void 0 ? _api$featureFlags$sha : false,
54
+ anchorRectCache: anchorRectCache
55
+ })))
56
+ }, ['button', {
57
+ class: 'blocks-quick-insert-button',
58
+ 'data-testid': 'editor-quick-insert-button'
59
+ }, plusButtonDOM]];
60
+ };
61
+
62
+ /**
63
+ * Create a Node which contains the quick insert button
64
+ */
65
+ var createVanillaButton = exports.createVanillaButton = function createVanillaButton(props) {
66
+ var _props$api$typeAhead, _props$api$blockContr, _props$api$typeAhead2, _props$api$blockContr2;
67
+ var _DOMSerializer$render = _model.DOMSerializer.renderSpec(document, vanillaQuickInsert(props)),
68
+ dom = _DOMSerializer$render.dom;
69
+ if (dom instanceof HTMLElement) {
70
+ var button = dom.querySelector('button[data-testid="editor-quick-insert-button"]');
71
+ if (button instanceof HTMLButtonElement) {
72
+ button.onclick = function () {
73
+ return handleQuickInsert(props);
74
+ };
75
+ var tooltip = new _vanillaTooltip.VanillaTooltip(button, props.formatMessage(_messages.blockControlsMessages.insert), 'quick-insert-button-tooltip');
76
+ props.cleanupCallbacks.push(function () {
77
+ tooltip.destroy();
78
+ });
79
+ }
80
+ }
81
+
82
+ // Dynamically control the visibility of the node
83
+ var isTypeAheadOpen = (_props$api$typeAhead = props.api.typeAhead) === null || _props$api$typeAhead === void 0 || (_props$api$typeAhead = _props$api$typeAhead.sharedState.currentState()) === null || _props$api$typeAhead === void 0 ? void 0 : _props$api$typeAhead.isOpen;
84
+ var isEditing = (_props$api$blockContr = props.api.blockControls) === null || _props$api$blockContr === void 0 || (_props$api$blockContr = _props$api$blockContr.sharedState.currentState()) === null || _props$api$blockContr === void 0 ? void 0 : _props$api$blockContr.isEditing;
85
+ var changeDOMVisibility = function changeDOMVisibility() {
86
+ if (!(dom instanceof HTMLElement)) {
87
+ return;
88
+ }
89
+ if (isTypeAheadOpen || isEditing) {
90
+ dom.classList.add('blocks-quick-insert-invisible-container');
91
+ dom.classList.remove('blocks-quick-insert-visible-container');
92
+ } else {
93
+ dom.classList.add('blocks-quick-insert-visible-container');
94
+ dom.classList.remove('blocks-quick-insert-invisible-container');
95
+ }
96
+ };
97
+ changeDOMVisibility();
98
+ props.cleanupCallbacks.push((_props$api$typeAhead2 = props.api.typeAhead) === null || _props$api$typeAhead2 === void 0 ? void 0 : _props$api$typeAhead2.sharedState.onChange(function (_ref2) {
99
+ var nextSharedState = _ref2.nextSharedState;
100
+ isTypeAheadOpen = nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.isOpen;
101
+ changeDOMVisibility();
102
+ }));
103
+ props.cleanupCallbacks.push((_props$api$blockContr2 = props.api.blockControls) === null || _props$api$blockContr2 === void 0 ? void 0 : _props$api$blockContr2.sharedState.onChange(function (_ref3) {
104
+ var nextSharedState = _ref3.nextSharedState;
105
+ isEditing = nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.isEditing;
106
+ changeDOMVisibility();
107
+ }));
108
+ return dom;
109
+ };
110
+ var TEXT_PARENT_TYPES = ['paragraph', 'heading', 'blockquote', 'taskItem', 'decisionItem'];
111
+ var handleQuickInsert = function handleQuickInsert(_ref4) {
112
+ var _api$quickInsert;
113
+ var api = _ref4.api,
114
+ view = _ref4.view,
115
+ getPos = _ref4.getPos;
116
+ // if the selection is not within the node this decoration is rendered at
117
+ // then insert a newline and trigger quick insert
118
+ var start = getPos();
119
+ if (start !== undefined) {
120
+ // if the selection is not within the node this decoration is rendered at
121
+ // or the node is non-editable, then insert a newline and trigger quick insert
122
+ var isSelectionInsideNode = (0, _documentChecks.isSelectionInNode)(start, view);
123
+ if (!isSelectionInsideNode || (0, _documentChecks.isNonEditableBlock)(start, view)) {
124
+ api.core.actions.execute((0, _editorCommands.createNewLine)(start));
125
+ }
126
+ var codeBlock = view.state.schema.nodes.codeBlock;
127
+ var selection = view.state.selection;
128
+ var codeBlockParentNode = (0, _utils.findParentNodeOfType)(codeBlock)(selection);
129
+ if (codeBlockParentNode) {
130
+ // Slash command is not meant to be triggered inside code block, hence always insert slash in a new line following
131
+ api.core.actions.execute((0, _editorCommands.createNewLine)(codeBlockParentNode.pos));
132
+ } else if (isSelectionInsideNode) {
133
+ // text or element with be deselected and the / added immediately after the paragraph
134
+ // unless the selection is empty
135
+ var currentSelection = view.state.selection;
136
+ if ((0, _documentChecks.isInTextSelection)(view) && currentSelection.from !== currentSelection.to) {
137
+ var currentParagraphNode = (0, _utils.findParentNode)(function (node) {
138
+ return TEXT_PARENT_TYPES.includes(node.type.name);
139
+ })(currentSelection);
140
+ if (currentParagraphNode) {
141
+ var newPos =
142
+ //if the current selection is selected from right to left, then set the selection to the start of the paragraph
143
+ currentSelection.anchor === currentSelection.to ? currentParagraphNode.pos : currentParagraphNode.pos + currentParagraphNode.node.nodeSize - 1;
144
+ api.core.actions.execute(function (_ref5) {
145
+ var tr = _ref5.tr;
146
+ tr.setSelection(_state.TextSelection.create(view.state.selection.$from.doc, newPos));
147
+ return tr;
148
+ });
149
+ }
150
+ }
151
+ if ((0, _documentChecks.isNestedNodeSelected)(view)) {
152
+ // if the nested selected node is non-editable, then insert a newline below the selected node
153
+ if ((0, _documentChecks.isNonEditableBlock)(view.state.selection.from, view)) {
154
+ api.core.actions.execute((0, _editorCommands.createNewLine)(view.state.selection.from));
155
+ } else {
156
+ // otherwise need to force the selection to be at the start of the node, because
157
+ // prosemirror is keeping it as NodeSelection for nested nodes. Do this to keep it
158
+ // consistent NodeSelection for root level nodes.
159
+ api.core.actions.execute(function (_ref6) {
160
+ var tr = _ref6.tr;
161
+ (0, _editorCommands.createNewLine)(view.state.selection.from)({
162
+ tr: tr
163
+ });
164
+ tr.setSelection(_state.TextSelection.create(tr.doc, view.state.selection.from));
165
+ return tr;
166
+ });
167
+ }
168
+ }
169
+ if (currentSelection instanceof _cellSelection.CellSelection) {
170
+ // find the last inline position in the selection
171
+ var lastInlinePosition = _state.TextSelection.near(view.state.selection.$to, -1);
172
+ lastInlinePosition && api.core.actions.execute(function (_ref7) {
173
+ var tr = _ref7.tr;
174
+ if (!(lastInlinePosition instanceof _state.TextSelection)) {
175
+ // this will create a new line after the node
176
+ (0, _editorCommands.createNewLine)(lastInlinePosition.from)({
177
+ tr: tr
178
+ });
179
+ // this will find the next valid text position after the node
180
+ tr.setSelection(_state.TextSelection.create(tr.doc, lastInlinePosition.to));
181
+ } else {
182
+ tr.setSelection(lastInlinePosition);
183
+ }
184
+ return tr;
185
+ });
186
+ }
187
+ }
188
+ }
189
+ (_api$quickInsert = api.quickInsert) === null || _api$quickInsert === void 0 || _api$quickInsert.actions.openTypeAhead('blockControl', true);
190
+ };
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.VanillaTooltip = void 0;
8
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
9
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
10
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
+ var _core = require("@popperjs/core");
12
+ var _bindEventListener = require("bind-event-listener");
13
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
14
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
15
+ var startingOffset = {
16
+ name: 'offset',
17
+ options: {
18
+ offset: [0, 4]
19
+ }
20
+ };
21
+ var endingOffset = {
22
+ name: 'offset',
23
+ options: {
24
+ offset: [0, 8]
25
+ }
26
+ };
27
+
28
+ /**
29
+ * A tooltip component similar to "@atlaskit/tooltip" but built for vanilla scenarios
30
+ *
31
+ * Uses Popover API for accessibility + stacking context: https://developer.mozilla.org/en-US/docs/Web/API/Popover_API
32
+ * Uses popperJS for positioning
33
+ *
34
+ * @warning Still experimental. One day we can likely want to move this to a common package.
35
+ */
36
+ var VanillaTooltip = exports.VanillaTooltip = /*#__PURE__*/function () {
37
+ function VanillaTooltip(button, content,
38
+ /**
39
+ * Id associated to the tooltip - must be unique.
40
+ */
41
+ id) {
42
+ var _this = this;
43
+ var timeout = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 300;
44
+ (0, _classCallCheck2.default)(this, VanillaTooltip);
45
+ (0, _defineProperty2.default)(this, "listeners", []);
46
+ (0, _defineProperty2.default)(this, "shouldHidePopover", false);
47
+ (0, _defineProperty2.default)(this, "isDisplayed", false);
48
+ this.button = button;
49
+ this.timeout = timeout;
50
+ var tooltip = document.createElement('span');
51
+ tooltip.role = 'tooltip';
52
+ tooltip.popover = 'hint';
53
+ // Warning: Currently this is used for styling - only works in the block controls package
54
+ tooltip.className = 'blocks-quick-insert-tooltip';
55
+ tooltip.id = id;
56
+ tooltip.textContent = content;
57
+ this.tooltip = tooltip;
58
+
59
+ // Button preparation
60
+ button.appendChild(tooltip);
61
+ // Prepare the button to have the popover target and accessibility properties
62
+ button.setAttribute('popovertarget', tooltip.id);
63
+ button.setAttribute('aria-describedby', tooltip.id);
64
+ var showEvents = ['mouseenter', 'focus'];
65
+ var hideEvents = ['mouseleave', 'blur'];
66
+ showEvents.forEach(function (event) {
67
+ _this.listeners.push((0, _bindEventListener.bind)(button, {
68
+ type: event,
69
+ listener: function listener() {
70
+ return _this.show();
71
+ }
72
+ }));
73
+ });
74
+ hideEvents.forEach(function (event) {
75
+ _this.listeners.push((0, _bindEventListener.bind)(button, {
76
+ type: event,
77
+ listener: function listener() {
78
+ return _this.hide();
79
+ }
80
+ }));
81
+ });
82
+ this.listeners.push((0, _bindEventListener.bind)(window, {
83
+ type: 'keydown',
84
+ listener: function listener(e) {
85
+ if (e.key === 'Escape') {
86
+ _this.hide(true);
87
+ }
88
+ }
89
+ }));
90
+
91
+ // Hide the tooltip if the hide transition has completed
92
+ this.tooltip.ontransitionend = function () {
93
+ if (_this.shouldHidePopover) {
94
+ _this.tooltip.hidePopover();
95
+ }
96
+ };
97
+ }
98
+ return (0, _createClass2.default)(VanillaTooltip, [{
99
+ key: "createPopperInstance",
100
+ value: function createPopperInstance() {
101
+ this.popperInstance = (0, _core.createPopper)(this.button, this.tooltip, {
102
+ placement: 'top',
103
+ modifiers: [startingOffset]
104
+ });
105
+ }
106
+ }, {
107
+ key: "destroy",
108
+ value: function destroy() {
109
+ var _this$popperInstance;
110
+ (_this$popperInstance = this.popperInstance) === null || _this$popperInstance === void 0 || _this$popperInstance.destroy();
111
+ this.listeners.forEach(function (listener) {
112
+ listener();
113
+ });
114
+ }
115
+ }, {
116
+ key: "hide",
117
+ value: function hide() {
118
+ var _this2 = this;
119
+ var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
120
+ clearTimeout(this.currentTimeoutId);
121
+ this.shouldHidePopover = true;
122
+ // Disable the event listeners
123
+ this.currentTimeoutId = setTimeout(function () {
124
+ var _this2$popperInstance;
125
+ (_this2$popperInstance = _this2.popperInstance) === null || _this2$popperInstance === void 0 || _this2$popperInstance.setOptions(function (options) {
126
+ return _objectSpread(_objectSpread({}, options), {}, {
127
+ modifiers: [startingOffset, {
128
+ name: 'eventListeners',
129
+ enabled: false
130
+ }]
131
+ });
132
+ });
133
+ _this2.tooltip.style.opacity = '0';
134
+ _this2.isDisplayed = false;
135
+ // If transition animations are disabled immediately hide the popover
136
+ if (_this2.tooltip.style.transition === 'none') {
137
+ _this2.tooltip.hidePopover();
138
+ }
139
+ }, immediate ? 0 : this.timeout);
140
+ }
141
+ }, {
142
+ key: "show",
143
+ value: function show() {
144
+ var _this3 = this;
145
+ if (this.isDisplayed) {
146
+ return;
147
+ }
148
+ clearTimeout(this.currentTimeoutId);
149
+ this.shouldHidePopover = false;
150
+
151
+ // Make the tooltip visible - but hide until
152
+ this.tooltip.style.visibility = 'hidden';
153
+ this.tooltip.showPopover();
154
+
155
+ // Update its position
156
+ if (!this.popperInstance) {
157
+ this.createPopperInstance();
158
+ } else {
159
+ this.popperInstance.update();
160
+ }
161
+
162
+ // Enable the event listeners
163
+ this.currentTimeoutId = setTimeout(function () {
164
+ var _this3$popperInstance;
165
+ _this3.tooltip.style.opacity = '1';
166
+ _this3.tooltip.style.visibility = 'visible';
167
+ (_this3$popperInstance = _this3.popperInstance) === null || _this3$popperInstance === void 0 || _this3$popperInstance.setOptions(function (options) {
168
+ return _objectSpread(_objectSpread({}, options), {}, {
169
+ modifiers: [endingOffset, {
170
+ name: 'eventListeners',
171
+ enabled: true
172
+ }]
173
+ });
174
+ });
175
+ _this3.isDisplayed = true;
176
+ }, this.timeout);
177
+ }
178
+ }]);
179
+ }();