@atlaskit/editor-plugin-block-controls 3.1.2 → 3.1.3

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 (41) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cjs/blockControlsPlugin.js +15 -9
  3. package/dist/cjs/pm-plugins/decorations-quick-insert-button.js +40 -0
  4. package/dist/cjs/pm-plugins/handle-mouse-over.js +24 -5
  5. package/dist/cjs/pm-plugins/main.js +35 -6
  6. package/dist/cjs/pm-plugins/utils/widget-positions.js +25 -0
  7. package/dist/cjs/ui/block-menu.js +7 -4
  8. package/dist/cjs/ui/consts.js +18 -1
  9. package/dist/cjs/ui/drag-handle.js +5 -2
  10. package/dist/cjs/ui/quick-insert-button.js +164 -0
  11. package/dist/es2019/blockControlsPlugin.js +15 -9
  12. package/dist/es2019/pm-plugins/decorations-quick-insert-button.js +29 -0
  13. package/dist/es2019/pm-plugins/handle-mouse-over.js +24 -5
  14. package/dist/es2019/pm-plugins/main.js +35 -7
  15. package/dist/es2019/pm-plugins/utils/widget-positions.js +20 -0
  16. package/dist/es2019/ui/block-menu.js +7 -4
  17. package/dist/es2019/ui/consts.js +17 -0
  18. package/dist/es2019/ui/drag-handle.js +5 -2
  19. package/dist/es2019/ui/quick-insert-button.js +152 -0
  20. package/dist/esm/blockControlsPlugin.js +15 -9
  21. package/dist/esm/pm-plugins/decorations-quick-insert-button.js +33 -0
  22. package/dist/esm/pm-plugins/handle-mouse-over.js +24 -5
  23. package/dist/esm/pm-plugins/main.js +35 -6
  24. package/dist/esm/pm-plugins/utils/widget-positions.js +20 -0
  25. package/dist/esm/ui/block-menu.js +7 -4
  26. package/dist/esm/ui/consts.js +17 -0
  27. package/dist/esm/ui/drag-handle.js +5 -2
  28. package/dist/esm/ui/quick-insert-button.js +154 -0
  29. package/dist/types/blockControlsPluginType.d.ts +7 -1
  30. package/dist/types/pm-plugins/decorations-quick-insert-button.d.ts +7 -0
  31. package/dist/types/pm-plugins/main.d.ts +1 -0
  32. package/dist/types/pm-plugins/utils/widget-positions.d.ts +4 -0
  33. package/dist/types/ui/consts.d.ts +7 -0
  34. package/dist/types/ui/quick-insert-button.d.ts +17 -0
  35. package/dist/types-ts4.5/blockControlsPluginType.d.ts +7 -1
  36. package/dist/types-ts4.5/pm-plugins/decorations-quick-insert-button.d.ts +7 -0
  37. package/dist/types-ts4.5/pm-plugins/main.d.ts +1 -0
  38. package/dist/types-ts4.5/pm-plugins/utils/widget-positions.d.ts +4 -0
  39. package/dist/types-ts4.5/ui/consts.d.ts +7 -0
  40. package/dist/types-ts4.5/ui/quick-insert-button.d.ts +17 -0
  41. package/package.json +2 -2
@@ -0,0 +1,29 @@
1
+ import { createElement } from 'react';
2
+ import uuid from 'uuid';
3
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
4
+ import { TypeAheadControl } from '../ui/quick-insert-button';
5
+ const TYPE_QUICK_INSERT = 'INSERT_BUTTON';
6
+ export const findQuickInsertInsertButtonDecoration = (decorations, from, to) => {
7
+ return decorations.find(from, to, spec => spec.type === TYPE_QUICK_INSERT);
8
+ };
9
+ export const quickInsertButtonDecoration = (api, formatMessage, rootPos, anchorName, nodeType, nodeViewPortalProviderAPI, rootAnchorName, rootNodeType) => {
10
+ const key = uuid();
11
+ return Decoration.widget(rootPos, (view, getPos) => {
12
+ const element = document.createElement('span');
13
+ element.contentEditable = 'false';
14
+ nodeViewPortalProviderAPI.render(() => /*#__PURE__*/createElement(TypeAheadControl, {
15
+ api,
16
+ getPos,
17
+ formatMessage,
18
+ view,
19
+ nodeType,
20
+ anchorName,
21
+ rootAnchorName,
22
+ rootNodeType: rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType
23
+ }), element, key);
24
+ return element;
25
+ }, {
26
+ side: -1,
27
+ type: TYPE_QUICK_INSERT
28
+ });
29
+ };
@@ -87,16 +87,35 @@ export const handleMouseOver = (view, event, api) => {
87
87
  // Don't show drag handle for layout column in a single column layout
88
88
  return false;
89
89
  }
90
- let rootPos;
90
+ let targetPos;
91
91
  if (editorExperiment('nested-dnd', true)) {
92
- rootPos = view.state.doc.resolve(pos).pos;
92
+ targetPos = view.state.doc.resolve(pos).pos;
93
93
  } else {
94
- rootPos = view.state.doc.resolve(pos).start(1) - 1;
94
+ targetPos = view.state.doc.resolve(pos).start(1) - 1;
95
+ }
96
+ let rootAnchorName;
97
+ let rootNodeType;
98
+ let rootPos;
99
+ if (editorExperiment('platform_editor_controls', 'variant1')) {
100
+ rootPos = view.state.doc.resolve(pos).before(1);
101
+ if (targetPos !== rootPos) {
102
+ const rootDOM = view.nodeDOM(rootPos);
103
+ if (rootDOM instanceof HTMLElement) {
104
+ var _rootDOM$getAttribute, _rootDOM$getAttribute2;
105
+ rootAnchorName = (_rootDOM$getAttribute = rootDOM.getAttribute('data-drag-handler-anchor-name')) !== null && _rootDOM$getAttribute !== void 0 ? _rootDOM$getAttribute : undefined;
106
+ rootNodeType = (_rootDOM$getAttribute2 = rootDOM.getAttribute('data-drag-handler-node-type')) !== null && _rootDOM$getAttribute2 !== void 0 ? _rootDOM$getAttribute2 : undefined;
107
+ }
108
+ }
95
109
  }
96
110
  const nodeType = rootElement.getAttribute('data-drag-handler-node-type');
97
111
  if (nodeType) {
98
- var _api$core, _api$blockControls2;
99
- api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.showDragHandleAt(rootPos, anchorName, nodeType));
112
+ if (editorExperiment('platform_editor_controls', 'variant1')) {
113
+ var _api$core, _api$blockControls2, _rootPos, _rootAnchorName, _rootNodeType;
114
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.showDragHandleAt(targetPos, anchorName, nodeType, undefined, (_rootPos = rootPos) !== null && _rootPos !== void 0 ? _rootPos : targetPos, (_rootAnchorName = rootAnchorName) !== null && _rootAnchorName !== void 0 ? _rootAnchorName : anchorName, (_rootNodeType = rootNodeType) !== null && _rootNodeType !== void 0 ? _rootNodeType : nodeType));
115
+ } else {
116
+ var _api$core2, _api$blockControls3;
117
+ api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands.showDragHandleAt(targetPos, anchorName, nodeType));
118
+ }
100
119
  }
101
120
  }
102
121
  };
@@ -17,6 +17,7 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
17
17
  import { findNodeDecs, nodeDecorations } from './decorations-anchor';
18
18
  import { dragHandleDecoration, emptyParagraphNodeDecorations, findHandleDec } from './decorations-drag-handle';
19
19
  import { dropTargetDecorations, findDropTargetDecs } from './decorations-drop-target';
20
+ import { findQuickInsertInsertButtonDecoration, quickInsertButtonDecoration } from './decorations-quick-insert-button';
20
21
  import { handleMouseOver } from './handle-mouse-over';
21
22
  import { boundKeydownHandler } from './keymap';
22
23
  import { defaultActiveAnchorTracker } from './utils/active-anchor-tracker';
@@ -153,7 +154,7 @@ export const getDecorations = state => {
153
154
  return (_key$getState = key.getState(state)) === null || _key$getState === void 0 ? void 0 : _key$getState.decorations;
154
155
  };
155
156
  export const newApply = (api, formatMessage, tr, currentState, newState, flags, nodeViewPortalProviderAPI, anchorRectCache) => {
156
- var _meta$multiSelectDnD, _meta$activeNode, _activeNode, _activeNode2, _meta$activeNode$hand, _meta$isDragging, _meta$isDragging2, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging, _meta$isShiftDown;
157
+ var _meta$multiSelectDnD, _meta$activeNode, _activeNode, _activeNode2, _meta$activeNode$hand, _meta$isDragging, _meta$isDragging2, _meta$toggleMenu, _meta$editorHeight, _meta$editorWidthLeft, _meta$editorWidthRigh, _meta$isPMDragging, _meta$isShiftDown;
157
158
  let {
158
159
  activeNode,
159
160
  decorations,
@@ -166,7 +167,7 @@ export const newApply = (api, formatMessage, tr, currentState, newState, flags,
166
167
  editorWidthRight,
167
168
  isDragging,
168
169
  isMenuOpen,
169
- // NOT USED
170
+ menuTriggerBy,
170
171
  isPMDragging,
171
172
  isShiftDown
172
173
  } = currentState;
@@ -181,7 +182,10 @@ export const newApply = (api, formatMessage, tr, currentState, newState, flags,
181
182
  activeNode = {
182
183
  pos: mappedPos.pos,
183
184
  anchorName: activeNode.anchorName,
184
- nodeType: activeNode.nodeType
185
+ nodeType: activeNode.nodeType,
186
+ rootPos: activeNode.rootPos,
187
+ rootAnchorName: activeNode.rootAnchorName,
188
+ rootNodeType: activeNode.rootNodeType
185
189
  };
186
190
  }
187
191
  if (multiSelectDnD && flags.isMultiSelectEnabled) {
@@ -252,12 +256,25 @@ export const newApply = (api, formatMessage, tr, currentState, newState, flags,
252
256
  var _activeNode3, _activeNode4;
253
257
  const oldHandle = findHandleDec(decorations, (_activeNode3 = activeNode) === null || _activeNode3 === void 0 ? void 0 : _activeNode3.pos, (_activeNode4 = activeNode) === null || _activeNode4 === void 0 ? void 0 : _activeNode4.pos);
254
258
  decorations = decorations.remove(oldHandle);
259
+ if (editorExperiment('platform_editor_controls', 'variant1')) {
260
+ var _activeNode5, _activeNode6;
261
+ const oldQuickInsertButton = findQuickInsertInsertButtonDecoration(decorations, (_activeNode5 = activeNode) === null || _activeNode5 === void 0 ? void 0 : _activeNode5.rootPos, (_activeNode6 = activeNode) === null || _activeNode6 === void 0 ? void 0 : _activeNode6.rootPos);
262
+ decorations = decorations.remove(oldQuickInsertButton);
263
+ }
255
264
  } else if (api && shouldRecreateHandle) {
256
- var _activeNode5, _activeNode6;
257
- const oldHandle = findHandleDec(decorations, (_activeNode5 = activeNode) === null || _activeNode5 === void 0 ? void 0 : _activeNode5.pos, (_activeNode6 = activeNode) === null || _activeNode6 === void 0 ? void 0 : _activeNode6.pos);
265
+ var _activeNode7, _activeNode8;
266
+ const oldHandle = findHandleDec(decorations, (_activeNode7 = activeNode) === null || _activeNode7 === void 0 ? void 0 : _activeNode7.pos, (_activeNode8 = activeNode) === null || _activeNode8 === void 0 ? void 0 : _activeNode8.pos);
258
267
  decorations = decorations.remove(oldHandle);
259
268
  const handleDec = dragHandleDecoration(api, formatMessage, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.pos, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.anchorName, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.nodeType, nodeViewPortalProviderAPI, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.handleOptions);
260
- decorations = decorations.add(newState.doc, [handleDec]);
269
+ if (editorExperiment('platform_editor_controls', 'variant1')) {
270
+ var _activeNode9, _activeNode10;
271
+ const oldQuickInsertButton = findQuickInsertInsertButtonDecoration(decorations, (_activeNode9 = activeNode) === null || _activeNode9 === void 0 ? void 0 : _activeNode9.rootPos, (_activeNode10 = activeNode) === null || _activeNode10 === void 0 ? void 0 : _activeNode10.rootPos);
272
+ decorations = decorations.remove(oldQuickInsertButton);
273
+ const quickInsertButton = quickInsertButtonDecoration(api, formatMessage, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.rootPos, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.anchorName, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.nodeType, nodeViewPortalProviderAPI, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.rootAnchorName, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.rootNodeType);
274
+ decorations = decorations.add(newState.doc, [handleDec, quickInsertButton]);
275
+ } else {
276
+ decorations = decorations.add(newState.doc, [handleDec]);
277
+ }
261
278
  }
262
279
 
263
280
  // Drop targets may be missing when the node count is being changed during a drag
@@ -284,12 +301,23 @@ export const newApply = (api, formatMessage, tr, currentState, newState, flags,
284
301
  }
285
302
  }
286
303
  const newActiveNode = isEmptyDoc || !(meta !== null && meta !== void 0 && meta.activeNode) && findHandleDec(decorations, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.pos, latestActiveNode === null || latestActiveNode === void 0 ? void 0 : latestActiveNode.pos).length === 0 ? null : latestActiveNode;
287
- const isMenuOpenNew = editorExperiment('platform_editor_controls', 'variant1') ? meta !== null && meta !== void 0 && meta.closeMenu ? false : meta !== null && meta !== void 0 && meta.toggleMenu ? !isMenuOpen : isMenuOpen : meta !== null && meta !== void 0 && meta.toggleMenu ? !isMenuOpen : isMenuOpen;
304
+ let isMenuOpenNew = isMenuOpen;
305
+ if (editorExperiment('platform_editor_controls', 'variant1')) {
306
+ if (meta !== null && meta !== void 0 && meta.closeMenu) {
307
+ isMenuOpenNew = false;
308
+ } else if (meta !== null && meta !== void 0 && meta.toggleMenu) {
309
+ const isSameAnchor = (meta === null || meta === void 0 ? void 0 : meta.toggleMenu.anchorName) === menuTriggerBy;
310
+ isMenuOpenNew = menuTriggerBy === undefined || isSameAnchor || !isMenuOpen && !isSameAnchor ? !isMenuOpen : isMenuOpen;
311
+ }
312
+ } else if (meta !== null && meta !== void 0 && meta.toggleMenu) {
313
+ isMenuOpenNew = !isMenuOpen;
314
+ }
288
315
  return {
289
316
  decorations,
290
317
  activeNode: newActiveNode,
291
318
  isDragging: (_meta$isDragging2 = meta === null || meta === void 0 ? void 0 : meta.isDragging) !== null && _meta$isDragging2 !== void 0 ? _meta$isDragging2 : isDragging,
292
319
  isMenuOpen: isMenuOpenNew,
320
+ menuTriggerBy: editorExperiment('platform_editor_controls', 'variant1') ? (meta === null || meta === void 0 ? void 0 : (_meta$toggleMenu = meta.toggleMenu) === null || _meta$toggleMenu === void 0 ? void 0 : _meta$toggleMenu.anchorName) || menuTriggerBy : undefined,
293
321
  editorHeight: (_meta$editorHeight = meta === null || meta === void 0 ? void 0 : meta.editorHeight) !== null && _meta$editorHeight !== void 0 ? _meta$editorHeight : editorHeight,
294
322
  editorWidthLeft: (_meta$editorWidthLeft = meta === null || meta === void 0 ? void 0 : meta.editorWidthLeft) !== null && _meta$editorWidthLeft !== void 0 ? _meta$editorWidthLeft : editorWidthLeft,
295
323
  editorWidthRight: (_meta$editorWidthRigh = meta === null || meta === void 0 ? void 0 : meta.editorWidthRight) !== null && _meta$editorWidthRigh !== void 0 ? _meta$editorWidthRigh : editorWidthRight,
@@ -0,0 +1,20 @@
1
+ import { rootElementGap } from '../../ui/consts';
2
+
3
+ // Adapted from `src/pm-plugins/utils/drag-handle-positions.ts`
4
+ // CHANGES - removed parentNodeType, use only for positioning widgets for top level element
5
+ // CHANGES - removed layout
6
+ // CHANGES - added overrides for constants for widget dimensions
7
+ export const getLeftPositionForRootElement = (dom, nodeType, widgetDimensions, innerContainer, macroInteractionUpdates) => {
8
+ if (!dom) {
9
+ return 'auto';
10
+ }
11
+ if (!innerContainer) {
12
+ return `${dom.offsetLeft - rootElementGap(nodeType) - widgetDimensions.width}px`;
13
+ }
14
+
15
+ // There is a showMacroInteractionDesignUpdates prop in extension node wrapper that can add a relative span under the top level div
16
+ // We need to adjust the left offset position of the drag handle to account for the relative span
17
+ const relativeSpan = macroInteractionUpdates ? dom.querySelector('span.relative') : null;
18
+ const leftAdjustment = relativeSpan ? relativeSpan.offsetLeft : 0;
19
+ return getComputedStyle(innerContainer).transform === 'none' ? `${innerContainer.offsetLeft + leftAdjustment - rootElementGap(nodeType) - widgetDimensions.width}px` : `${innerContainer.offsetLeft + leftAdjustment - innerContainer.offsetWidth / 2 - rootElementGap(nodeType) - widgetDimensions.width}px`;
20
+ };
@@ -6,7 +6,6 @@ import { ArrowKeyNavigationType, DropdownMenu } from '@atlaskit/editor-common/ui
6
6
  import { akEditorFloatingOverlapPanelZIndex } from '@atlaskit/editor-shared-styles';
7
7
  import { getBlockMenuItems, menuItemsCallback } from './block-menu-items';
8
8
  import { BLOCK_MENU_WIDTH } from './consts';
9
- const dragHandleSelector = '[data-blocks-drag-handle-container="true"] button';
10
9
  const BlockMenu = ({
11
10
  editorView,
12
11
  mountPoint,
@@ -23,7 +22,8 @@ const BlockMenu = ({
23
22
  if (!(blockControlsState !== null && blockControlsState !== void 0 && blockControlsState.isMenuOpen)) {
24
23
  return null;
25
24
  }
26
- const targetHandleRef = document.querySelector(dragHandleSelector);
25
+ const activeNodeSelector = `[data-drag-handler-anchor-name=${blockControlsState === null || blockControlsState === void 0 ? void 0 : blockControlsState.menuTriggerBy}]`;
26
+ const targetHandleRef = document.querySelector(activeNodeSelector);
27
27
  const items = getBlockMenuItems(formatMessage);
28
28
  const handleOpenChange = payload => {
29
29
  if (!(payload !== null && payload !== void 0 && payload.isOpen)) {
@@ -38,10 +38,13 @@ const BlockMenu = ({
38
38
  if (editorView) {
39
39
  var _menuItemsCallback, _menuItemsCallback$ca;
40
40
  (_menuItemsCallback = menuItemsCallback[item.value.name]) === null || _menuItemsCallback === void 0 ? void 0 : (_menuItemsCallback$ca = _menuItemsCallback.call(menuItemsCallback, api, formatMessage)) === null || _menuItemsCallback$ca === void 0 ? void 0 : _menuItemsCallback$ca(editorView.state, editorView.dispatch, editorView);
41
+ api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.toggleBlockMenu({
42
+ closeMenu: true
43
+ }));
41
44
  }
42
45
  };
43
46
  return /*#__PURE__*/React.createElement(Popup, {
44
- alignX: 'right',
47
+ alignX: 'left',
45
48
  alignY: 'start'
46
49
  // Ignored via go/ees005
47
50
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
@@ -51,7 +54,7 @@ const BlockMenu = ({
51
54
  zIndex: akEditorFloatingOverlapPanelZIndex,
52
55
  forcePlacement: true,
53
56
  stick: true,
54
- offset: [-18, 8]
57
+ offset: [-6, 8]
55
58
  }, /*#__PURE__*/React.createElement(DropdownMenu, {
56
59
  mountTo: mountPoint,
57
60
  boundariesElement: boundariesElement,
@@ -26,6 +26,12 @@ export const DRAG_HANDLE_PARAGRAPH_TOP_ADJUSTMENT = 2;
26
26
  * so we allow for some leniency to capture them all. e.g. Table is depth 3.
27
27
  */
28
28
  export const DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH = 3;
29
+ export const QUICK_INSERT_HEIGHT = 24;
30
+ export const QUICK_INSERT_WIDTH = 24;
31
+ export const QUICK_INSERT_DIMENSIONS = {
32
+ width: QUICK_INSERT_WIDTH,
33
+ height: QUICK_INSERT_HEIGHT
34
+ };
29
35
  const nodeTypeExcludeList = ['embedCard', 'mediaSingle', 'table'];
30
36
  export const dragHandleGap = (nodeType, parentNodeType) => {
31
37
  if (nodeType === 'layoutSection' && fg('platform_editor_advanced_layouts_post_fix_patch_2')) {
@@ -42,6 +48,17 @@ export const dragHandleGap = (nodeType, parentNodeType) => {
42
48
  }
43
49
  return DRAG_HANDLE_DEFAULT_GAP;
44
50
  };
51
+
52
+ // use for returning hap only for root level elements
53
+ export const rootElementGap = nodeType => {
54
+ if (nodeTypeExcludeList.includes(nodeType)) {
55
+ return DRAG_HANDLE_MAX_GAP;
56
+ }
57
+ if (nodeType === 'layoutSection') {
58
+ return DRAG_HANDLE_MAX_GAP + 12;
59
+ }
60
+ return DRAG_HANDLE_DEFAULT_GAP;
61
+ };
45
62
  export const getNestedNodeLeftPaddingMargin = nodeType => {
46
63
  switch (nodeType) {
47
64
  case 'bodiedExtension':
@@ -173,9 +173,12 @@ export const DragHandle = ({
173
173
  tr = selectNode(tr, startPos, nodeType);
174
174
  if (editorExperiment('platform_editor_controls', 'variant1')) {
175
175
  var _api$blockControls;
176
- api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.commands.toggleBlockMenu()({
176
+ api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.commands.toggleBlockMenu({
177
+ anchorName
178
+ })({
177
179
  tr
178
180
  });
181
+ e.stopPropagation();
179
182
  }
180
183
  } else if (isTopLevelNode && $anchor.depth <= DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH && e.shiftKey) {
181
184
  var _api$blockControls2;
@@ -202,7 +205,7 @@ export const DragHandle = ({
202
205
  return tr;
203
206
  });
204
207
  view.focus();
205
- }, [isMultiSelect, api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions, api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions, api === null || api === void 0 ? void 0 : (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands, view, dragHandleSelected, getPos, multiSelectDnD === null || multiSelectDnD === void 0 ? void 0 : multiSelectDnD.anchor, isTopLevelNode, nodeType]);
208
+ }, [isMultiSelect, api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions, api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions, api === null || api === void 0 ? void 0 : (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands, view, dragHandleSelected, getPos, multiSelectDnD === null || multiSelectDnD === void 0 ? void 0 : multiSelectDnD.anchor, isTopLevelNode, nodeType, anchorName]);
206
209
 
207
210
  // TODO - This needs to be investigated further. Drag preview generation is not always working
208
211
  // as expected with a node selection. This workaround sets the selection to the node on mouseDown,
@@ -0,0 +1,152 @@
1
+ import React, { useCallback, useEffect, useState } from 'react';
2
+ import { bind } from 'bind-event-listener';
3
+ import { ToolTipContent } from '@atlaskit/editor-common/keymaps';
4
+ import { blockControlsMessages as messages } from '@atlaskit/editor-common/messages';
5
+ import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
6
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
7
+ import EditorAddIcon from '@atlaskit/icon/glyph/editor/add';
8
+ import { Box, Pressable, xcss } from '@atlaskit/primitives';
9
+ import Tooltip from '@atlaskit/tooltip';
10
+ import { getTopPosition } from '../pm-plugins/utils/drag-handle-positions';
11
+ import { getLeftPositionForRootElement } from '../pm-plugins/utils/widget-positions';
12
+ import { QUICK_INSERT_DIMENSIONS, rootElementGap, topPositionAdjustment } from './consts';
13
+ const buttonStyles = xcss({
14
+ boxSizing: 'border-box',
15
+ display: 'flex',
16
+ flexDirection: 'column',
17
+ justifyContent: 'center',
18
+ alignItems: 'center',
19
+ height: "var(--ds-space-300, 24px)",
20
+ width: "var(--ds-space-300, 24px)",
21
+ border: 'none',
22
+ backgroundColor: 'color.background.neutral',
23
+ borderRadius: '50%',
24
+ color: 'color.text.accent.gray',
25
+ zIndex: 'card',
26
+ outline: 'none',
27
+ ':hover': {
28
+ backgroundColor: 'color.background.neutral.hovered'
29
+ },
30
+ ':active': {
31
+ backgroundColor: 'color.background.neutral.pressed'
32
+ },
33
+ ':focus': {
34
+ outline: `2px solid ${"var(--ds-border-focused, #388BFF)"}`
35
+ }
36
+ });
37
+ const containerStaticStyles = xcss({
38
+ position: 'absolute',
39
+ zIndex: 'card'
40
+ });
41
+
42
+ // TODO: Share prop types between DragHandle - generic enough to create a type for block control decoration
43
+
44
+ export const TypeAheadControl = ({
45
+ view,
46
+ api,
47
+ formatMessage,
48
+ getPos,
49
+ nodeType,
50
+ anchorName,
51
+ rootAnchorName,
52
+ rootNodeType
53
+ }) => {
54
+ const macroInteractionUpdates = useSharedPluginStateSelector(api, 'featureFlags.macroInteractionUpdates');
55
+ const [positionStyles, setPositionStyles] = useState({});
56
+
57
+ // Adapted from `src/ui/drag-handle.tsx` as positioning logic is similar
58
+ // CHANGES - added an offset so quick insert button can be positioned beside drag handle
59
+ // CHANGES - removed `editorExperiment('nested-dnd', true)` check and rootNodeType calculation
60
+ // CHANGES - replace anchorName with rootAnchorName
61
+ // CHANGES - `removed editorExperiment('advanced_layouts', true) && isLayoutColumn` checks as quick insert button will not be positioned for layout column
62
+ const calculatePosition = useCallback(() => {
63
+ const supportsAnchor = CSS.supports('top', `anchor(${rootAnchorName} start)`) && CSS.supports('left', `anchor(${rootAnchorName} start)`);
64
+ const dom = view.dom.querySelector(`[data-drag-handler-anchor-name="${rootAnchorName}"]`);
65
+ const hasResizer = rootNodeType === 'table' || rootNodeType === 'mediaSingle';
66
+ const isExtension = rootNodeType === 'extension' || rootNodeType === 'bodiedExtension';
67
+ const isBlockCard = rootNodeType === 'blockCard';
68
+ const isEmbedCard = rootNodeType === 'embedCard';
69
+ const isMacroInteractionUpdates = macroInteractionUpdates && isExtension;
70
+ let innerContainer = null;
71
+ if (dom) {
72
+ if (isEmbedCard) {
73
+ innerContainer = dom.querySelector('.rich-media-item');
74
+ } else if (hasResizer) {
75
+ innerContainer = dom.querySelector('.resizer-item');
76
+ } else if (isExtension) {
77
+ innerContainer = dom.querySelector('.extension-container[data-layout]');
78
+ } else if (isBlockCard) {
79
+ //specific to datasource blockCard
80
+ innerContainer = dom.querySelector('.datasourceView-content-inner-wrap');
81
+ }
82
+ }
83
+ const isEdgeCase = (hasResizer || isExtension || isEmbedCard || isBlockCard) && innerContainer;
84
+ const neighboringWidthOffset = anchorName === rootAnchorName ? '-16px' : '0px';
85
+ if (supportsAnchor) {
86
+ return {
87
+ left: isEdgeCase ? `calc(anchor(${rootAnchorName} start) + ${getLeftPositionForRootElement(dom, rootNodeType, QUICK_INSERT_DIMENSIONS, innerContainer, isMacroInteractionUpdates)} + ${neighboringWidthOffset})` : `calc(anchor(${rootAnchorName} start) - ${QUICK_INSERT_DIMENSIONS.width}px - ${rootElementGap(rootNodeType)}px + ${neighboringWidthOffset})`,
88
+ top: `calc(anchor(${rootAnchorName} start) + ${topPositionAdjustment(rootNodeType)}px)`
89
+ };
90
+ }
91
+ return {
92
+ left: isEdgeCase ? `calc(${(dom === null || dom === void 0 ? void 0 : dom.offsetLeft) || 0}px + ${getLeftPositionForRootElement(dom, rootNodeType, QUICK_INSERT_DIMENSIONS, innerContainer, isMacroInteractionUpdates)} + ${neighboringWidthOffset})` : `calc(${getLeftPositionForRootElement(dom, rootNodeType, QUICK_INSERT_DIMENSIONS, innerContainer, isMacroInteractionUpdates)} + ${neighboringWidthOffset})`,
93
+ top: getTopPosition(dom, rootNodeType)
94
+ };
95
+ }, [rootAnchorName, view.dom, rootNodeType, macroInteractionUpdates, anchorName]);
96
+ useEffect(() => {
97
+ let cleanUpTransitionListener;
98
+ if (rootNodeType === 'extension' || rootNodeType === 'embedCard') {
99
+ const dom = view.dom.querySelector(`[data-drag-handler-anchor-name="${rootAnchorName}"]`);
100
+ if (!dom) {
101
+ return;
102
+ }
103
+ cleanUpTransitionListener = bind(dom, {
104
+ type: 'transitionend',
105
+ listener: () => {
106
+ setPositionStyles(calculatePosition());
107
+ }
108
+ });
109
+ }
110
+ const calcPos = requestAnimationFrame(() => {
111
+ setPositionStyles(calculatePosition());
112
+ });
113
+ return () => {
114
+ var _cleanUpTransitionLis;
115
+ cancelAnimationFrame(calcPos);
116
+ (_cleanUpTransitionLis = cleanUpTransitionListener) === null || _cleanUpTransitionLis === void 0 ? void 0 : _cleanUpTransitionLis();
117
+ };
118
+ }, [calculatePosition, view.dom, rootAnchorName, rootNodeType]);
119
+ return (
120
+ /*#__PURE__*/
121
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
122
+ React.createElement(Box, {
123
+ style: positionStyles,
124
+ xcss: [containerStaticStyles]
125
+ }, /*#__PURE__*/React.createElement(Tooltip, {
126
+ content: /*#__PURE__*/React.createElement(ToolTipContent, {
127
+ description: formatMessage(messages.insert),
128
+ shortcutOverride: "/"
129
+ })
130
+ }, /*#__PURE__*/React.createElement(Pressable, {
131
+ type: "button",
132
+ "aria-label": formatMessage(messages.insert),
133
+ xcss: [buttonStyles],
134
+ onClick: () => {
135
+ var _api$core, _api$quickInsert;
136
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
137
+ tr
138
+ }) => {
139
+ const start = getPos();
140
+ if (!start) {
141
+ return null;
142
+ }
143
+ return tr.setSelection(TextSelection.create(tr.doc, start));
144
+ });
145
+ api === null || api === void 0 ? void 0 : (_api$quickInsert = api.quickInsert) === null || _api$quickInsert === void 0 ? void 0 : _api$quickInsert.actions.openTypeAhead('blockControl');
146
+ }
147
+ }, /*#__PURE__*/React.createElement(EditorAddIcon, {
148
+ label: "add",
149
+ size: "medium"
150
+ }))))
151
+ );
152
+ };
@@ -29,7 +29,7 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
29
29
  commands: {
30
30
  moveNode: moveNode(api),
31
31
  moveToLayout: moveToLayout(api),
32
- showDragHandleAt: function showDragHandleAt(pos, anchorName, nodeType, handleOptions) {
32
+ showDragHandleAt: function showDragHandleAt(pos, anchorName, nodeType, handleOptions, rootPos, rootAnchorName, rootNodeType) {
33
33
  return function (_ref3) {
34
34
  var tr = _ref3.tr;
35
35
  var currMeta = tr.getMeta(key);
@@ -38,7 +38,10 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
38
38
  pos: pos,
39
39
  anchorName: anchorName,
40
40
  nodeType: nodeType,
41
- handleOptions: handleOptions
41
+ handleOptions: handleOptions,
42
+ rootPos: rootPos,
43
+ rootAnchorName: rootAnchorName,
44
+ rootNodeType: rootNodeType
42
45
  },
43
46
  closeMenu: editorExperiment('platform_editor_controls', 'variant1') ? true : undefined
44
47
  }));
@@ -56,7 +59,9 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
56
59
  return tr;
57
60
  }
58
61
  tr.setMeta(key, _objectSpread(_objectSpread({}, currMeta), {}, {
59
- toggleMenu: true
62
+ toggleMenu: {
63
+ anchorName: options === null || options === void 0 ? void 0 : options.anchorName
64
+ }
60
65
  }));
61
66
  return tr;
62
67
  };
@@ -130,17 +135,18 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
130
135
  }
131
136
  },
132
137
  getSharedState: function getSharedState(editorState) {
133
- var _key$getState$isMenuO, _key$getState, _key$getState$activeN, _key$getState2, _key$getState$isDragg, _key$getState3, _key$getState$isPMDra, _key$getState4, _key$getState$multiSe, _key$getState5, _key$getState$isShift, _key$getState6;
138
+ var _key$getState$isMenuO, _key$getState, _key$getState$menuTri, _key$getState2, _key$getState$activeN, _key$getState3, _key$getState$isDragg, _key$getState4, _key$getState$isPMDra, _key$getState5, _key$getState$multiSe, _key$getState6, _key$getState$isShift, _key$getState7;
134
139
  if (!editorState) {
135
140
  return undefined;
136
141
  }
137
142
  return {
138
143
  isMenuOpen: (_key$getState$isMenuO = (_key$getState = key.getState(editorState)) === null || _key$getState === void 0 ? void 0 : _key$getState.isMenuOpen) !== null && _key$getState$isMenuO !== void 0 ? _key$getState$isMenuO : false,
139
- activeNode: (_key$getState$activeN = (_key$getState2 = key.getState(editorState)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.activeNode) !== null && _key$getState$activeN !== void 0 ? _key$getState$activeN : undefined,
140
- isDragging: (_key$getState$isDragg = (_key$getState3 = key.getState(editorState)) === null || _key$getState3 === void 0 ? void 0 : _key$getState3.isDragging) !== null && _key$getState$isDragg !== void 0 ? _key$getState$isDragg : false,
141
- isPMDragging: (_key$getState$isPMDra = (_key$getState4 = key.getState(editorState)) === null || _key$getState4 === void 0 ? void 0 : _key$getState4.isPMDragging) !== null && _key$getState$isPMDra !== void 0 ? _key$getState$isPMDra : false,
142
- multiSelectDnD: (_key$getState$multiSe = (_key$getState5 = key.getState(editorState)) === null || _key$getState5 === void 0 ? void 0 : _key$getState5.multiSelectDnD) !== null && _key$getState$multiSe !== void 0 ? _key$getState$multiSe : undefined,
143
- isShiftDown: (_key$getState$isShift = (_key$getState6 = key.getState(editorState)) === null || _key$getState6 === void 0 ? void 0 : _key$getState6.isShiftDown) !== null && _key$getState$isShift !== void 0 ? _key$getState$isShift : undefined
144
+ menuTriggerBy: (_key$getState$menuTri = (_key$getState2 = key.getState(editorState)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.menuTriggerBy) !== null && _key$getState$menuTri !== void 0 ? _key$getState$menuTri : undefined,
145
+ activeNode: (_key$getState$activeN = (_key$getState3 = key.getState(editorState)) === null || _key$getState3 === void 0 ? void 0 : _key$getState3.activeNode) !== null && _key$getState$activeN !== void 0 ? _key$getState$activeN : undefined,
146
+ isDragging: (_key$getState$isDragg = (_key$getState4 = key.getState(editorState)) === null || _key$getState4 === void 0 ? void 0 : _key$getState4.isDragging) !== null && _key$getState$isDragg !== void 0 ? _key$getState$isDragg : false,
147
+ isPMDragging: (_key$getState$isPMDra = (_key$getState5 = key.getState(editorState)) === null || _key$getState5 === void 0 ? void 0 : _key$getState5.isPMDragging) !== null && _key$getState$isPMDra !== void 0 ? _key$getState$isPMDra : false,
148
+ multiSelectDnD: (_key$getState$multiSe = (_key$getState6 = key.getState(editorState)) === null || _key$getState6 === void 0 ? void 0 : _key$getState6.multiSelectDnD) !== null && _key$getState$multiSe !== void 0 ? _key$getState$multiSe : undefined,
149
+ isShiftDown: (_key$getState$isShift = (_key$getState7 = key.getState(editorState)) === null || _key$getState7 === void 0 ? void 0 : _key$getState7.isShiftDown) !== null && _key$getState$isShift !== void 0 ? _key$getState$isShift : undefined
144
150
  };
145
151
  },
146
152
  contentComponent: function contentComponent(_ref7) {
@@ -0,0 +1,33 @@
1
+ import { createElement } from 'react';
2
+ import uuid from 'uuid';
3
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
4
+ import { TypeAheadControl } from '../ui/quick-insert-button';
5
+ var TYPE_QUICK_INSERT = 'INSERT_BUTTON';
6
+ export var findQuickInsertInsertButtonDecoration = function findQuickInsertInsertButtonDecoration(decorations, from, to) {
7
+ return decorations.find(from, to, function (spec) {
8
+ return spec.type === TYPE_QUICK_INSERT;
9
+ });
10
+ };
11
+ export var quickInsertButtonDecoration = function quickInsertButtonDecoration(api, formatMessage, rootPos, anchorName, nodeType, nodeViewPortalProviderAPI, rootAnchorName, rootNodeType) {
12
+ var key = uuid();
13
+ return Decoration.widget(rootPos, function (view, getPos) {
14
+ var element = document.createElement('span');
15
+ element.contentEditable = 'false';
16
+ nodeViewPortalProviderAPI.render(function () {
17
+ return /*#__PURE__*/createElement(TypeAheadControl, {
18
+ api: api,
19
+ getPos: getPos,
20
+ formatMessage: formatMessage,
21
+ view: view,
22
+ nodeType: nodeType,
23
+ anchorName: anchorName,
24
+ rootAnchorName: rootAnchorName,
25
+ rootNodeType: rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType
26
+ });
27
+ }, element, key);
28
+ return element;
29
+ }, {
30
+ side: -1,
31
+ type: TYPE_QUICK_INSERT
32
+ });
33
+ };
@@ -86,16 +86,35 @@ export var handleMouseOver = function handleMouseOver(view, event, api) {
86
86
  // Don't show drag handle for layout column in a single column layout
87
87
  return false;
88
88
  }
89
- var rootPos;
89
+ var targetPos;
90
90
  if (editorExperiment('nested-dnd', true)) {
91
- rootPos = view.state.doc.resolve(pos).pos;
91
+ targetPos = view.state.doc.resolve(pos).pos;
92
92
  } else {
93
- rootPos = view.state.doc.resolve(pos).start(1) - 1;
93
+ targetPos = view.state.doc.resolve(pos).start(1) - 1;
94
+ }
95
+ var rootAnchorName;
96
+ var rootNodeType;
97
+ var rootPos;
98
+ if (editorExperiment('platform_editor_controls', 'variant1')) {
99
+ rootPos = view.state.doc.resolve(pos).before(1);
100
+ if (targetPos !== rootPos) {
101
+ var rootDOM = view.nodeDOM(rootPos);
102
+ if (rootDOM instanceof HTMLElement) {
103
+ var _rootDOM$getAttribute, _rootDOM$getAttribute2;
104
+ rootAnchorName = (_rootDOM$getAttribute = rootDOM.getAttribute('data-drag-handler-anchor-name')) !== null && _rootDOM$getAttribute !== void 0 ? _rootDOM$getAttribute : undefined;
105
+ rootNodeType = (_rootDOM$getAttribute2 = rootDOM.getAttribute('data-drag-handler-node-type')) !== null && _rootDOM$getAttribute2 !== void 0 ? _rootDOM$getAttribute2 : undefined;
106
+ }
107
+ }
94
108
  }
95
109
  var nodeType = rootElement.getAttribute('data-drag-handler-node-type');
96
110
  if (nodeType) {
97
- var _api$core, _api$blockControls2;
98
- api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.showDragHandleAt(rootPos, anchorName, nodeType));
111
+ if (editorExperiment('platform_editor_controls', 'variant1')) {
112
+ var _api$core, _api$blockControls2, _rootPos, _rootAnchorName, _rootNodeType;
113
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.commands.showDragHandleAt(targetPos, anchorName, nodeType, undefined, (_rootPos = rootPos) !== null && _rootPos !== void 0 ? _rootPos : targetPos, (_rootAnchorName = rootAnchorName) !== null && _rootAnchorName !== void 0 ? _rootAnchorName : anchorName, (_rootNodeType = rootNodeType) !== null && _rootNodeType !== void 0 ? _rootNodeType : nodeType));
114
+ } else {
115
+ var _api$core2, _api$blockControls3;
116
+ api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.commands.showDragHandleAt(targetPos, anchorName, nodeType));
117
+ }
99
118
  }
100
119
  }
101
120
  };