@atlaskit/editor-plugin-block-controls 8.7.2 → 8.8.1

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 (55) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/blockControlsPlugin.js +14 -3
  3. package/dist/cjs/pm-plugins/decorations-drag-handle.js +3 -0
  4. package/dist/cjs/pm-plugins/decorations-quick-insert-button.js +3 -0
  5. package/dist/cjs/pm-plugins/handle-mouse-over.js +27 -11
  6. package/dist/cjs/pm-plugins/interaction-tracking/commands.js +12 -1
  7. package/dist/cjs/pm-plugins/interaction-tracking/handle-mouse-move.js +96 -1
  8. package/dist/cjs/pm-plugins/interaction-tracking/pm-plugin.js +92 -3
  9. package/dist/cjs/pm-plugins/main.js +129 -25
  10. package/dist/cjs/pm-plugins/vanilla-quick-insert.js +36 -13
  11. package/dist/cjs/ui/drag-handle.js +19 -9
  12. package/dist/cjs/ui/global-styles.js +9 -4
  13. package/dist/cjs/ui/quick-insert-button.js +16 -3
  14. package/dist/cjs/ui/visibility-container.js +70 -9
  15. package/dist/es2019/blockControlsPlugin.js +12 -3
  16. package/dist/es2019/pm-plugins/decorations-drag-handle.js +3 -0
  17. package/dist/es2019/pm-plugins/decorations-quick-insert-button.js +3 -0
  18. package/dist/es2019/pm-plugins/handle-mouse-over.js +27 -11
  19. package/dist/es2019/pm-plugins/interaction-tracking/commands.js +11 -0
  20. package/dist/es2019/pm-plugins/interaction-tracking/handle-mouse-move.js +98 -3
  21. package/dist/es2019/pm-plugins/interaction-tracking/pm-plugin.js +89 -4
  22. package/dist/es2019/pm-plugins/main.js +73 -18
  23. package/dist/es2019/pm-plugins/vanilla-quick-insert.js +27 -3
  24. package/dist/es2019/ui/drag-handle.js +19 -9
  25. package/dist/es2019/ui/global-styles.js +9 -3
  26. package/dist/es2019/ui/quick-insert-button.js +17 -3
  27. package/dist/es2019/ui/visibility-container.js +65 -9
  28. package/dist/esm/blockControlsPlugin.js +14 -3
  29. package/dist/esm/pm-plugins/decorations-drag-handle.js +3 -0
  30. package/dist/esm/pm-plugins/decorations-quick-insert-button.js +3 -0
  31. package/dist/esm/pm-plugins/handle-mouse-over.js +27 -11
  32. package/dist/esm/pm-plugins/interaction-tracking/commands.js +11 -0
  33. package/dist/esm/pm-plugins/interaction-tracking/handle-mouse-move.js +98 -2
  34. package/dist/esm/pm-plugins/interaction-tracking/pm-plugin.js +93 -3
  35. package/dist/esm/pm-plugins/main.js +129 -25
  36. package/dist/esm/pm-plugins/vanilla-quick-insert.js +36 -13
  37. package/dist/esm/ui/drag-handle.js +19 -9
  38. package/dist/esm/ui/global-styles.js +9 -4
  39. package/dist/esm/ui/quick-insert-button.js +16 -3
  40. package/dist/esm/ui/visibility-container.js +68 -9
  41. package/dist/types/blockControlsPluginType.d.ts +25 -1
  42. package/dist/types/index.d.ts +1 -1
  43. package/dist/types/pm-plugins/interaction-tracking/commands.d.ts +2 -0
  44. package/dist/types/pm-plugins/interaction-tracking/handle-mouse-move.d.ts +2 -2
  45. package/dist/types/pm-plugins/interaction-tracking/pm-plugin.d.ts +5 -1
  46. package/dist/types/pm-plugins/main.d.ts +2 -2
  47. package/dist/types/ui/visibility-container.d.ts +2 -1
  48. package/dist/types-ts4.5/blockControlsPluginType.d.ts +27 -1
  49. package/dist/types-ts4.5/index.d.ts +1 -1
  50. package/dist/types-ts4.5/pm-plugins/interaction-tracking/commands.d.ts +2 -0
  51. package/dist/types-ts4.5/pm-plugins/interaction-tracking/handle-mouse-move.d.ts +2 -2
  52. package/dist/types-ts4.5/pm-plugins/interaction-tracking/pm-plugin.d.ts +5 -1
  53. package/dist/types-ts4.5/pm-plugins/main.d.ts +2 -2
  54. package/dist/types-ts4.5/ui/visibility-container.d.ts +2 -1
  55. package/package.json +7 -9
@@ -5,6 +5,7 @@ import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
5
5
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
6
6
  import { findParentNode, findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
7
7
  import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
8
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
8
9
  import { isInTextSelection, isNestedNodeSelected, isNonEditableBlock, isSelectionInNode } from '../ui/utils/document-checks';
9
10
  import { createNewLine } from '../ui/utils/editor-commands';
10
11
  import { calculatePosition } from './quick-insert-calculate-position';
@@ -55,7 +56,7 @@ const vanillaQuickInsert = ({
55
56
  * Create a Node which contains the quick insert button
56
57
  */
57
58
  export const createVanillaButton = props => {
58
- var _props$api$typeAhead, _props$api$typeAhead$, _props$api$blockContr, _props$api$blockContr2, _props$api$typeAhead2, _props$api$blockContr3;
59
+ var _props$api$typeAhead, _props$api$typeAhead$, _props$api$blockContr, _props$api$blockContr2, _props$api$blockContr3, _props$api$blockContr4, _props$api$blockContr5, _props$api$blockContr6, _props$api$blockContr7, _props$api$editorView, _props$api$editorView2, _props$api$typeAhead2, _props$api$blockContr8;
59
60
  const {
60
61
  dom
61
62
  } = DOMSerializer.renderSpec(document, vanillaQuickInsert(props));
@@ -73,11 +74,18 @@ export const createVanillaButton = props => {
73
74
  // Dynamically control the visibility of the node
74
75
  let isTypeAheadOpen = (_props$api$typeAhead = props.api.typeAhead) === null || _props$api$typeAhead === void 0 ? void 0 : (_props$api$typeAhead$ = _props$api$typeAhead.sharedState.currentState()) === null || _props$api$typeAhead$ === void 0 ? void 0 : _props$api$typeAhead$.isOpen;
75
76
  let isEditing = (_props$api$blockContr = props.api.blockControls) === null || _props$api$blockContr === void 0 ? void 0 : (_props$api$blockContr2 = _props$api$blockContr.sharedState.currentState()) === null || _props$api$blockContr2 === void 0 ? void 0 : _props$api$blockContr2.isEditing;
77
+ let hoverSide = (_props$api$blockContr3 = props.api.blockControls) === null || _props$api$blockContr3 === void 0 ? void 0 : (_props$api$blockContr4 = _props$api$blockContr3.sharedState.currentState()) === null || _props$api$blockContr4 === void 0 ? void 0 : _props$api$blockContr4.hoverSide;
78
+ let rightSideControlsEnabled = (_props$api$blockContr5 = (_props$api$blockContr6 = props.api.blockControls) === null || _props$api$blockContr6 === void 0 ? void 0 : (_props$api$blockContr7 = _props$api$blockContr6.sharedState.currentState()) === null || _props$api$blockContr7 === void 0 ? void 0 : _props$api$blockContr7.rightSideControlsEnabled) !== null && _props$api$blockContr5 !== void 0 ? _props$api$blockContr5 : false;
79
+ let editorViewMode = (_props$api$editorView = props.api.editorViewMode) === null || _props$api$editorView === void 0 ? void 0 : (_props$api$editorView2 = _props$api$editorView.sharedState.currentState()) === null || _props$api$editorView2 === void 0 ? void 0 : _props$api$editorView2.mode;
76
80
  const changeDOMVisibility = () => {
77
81
  if (!(dom instanceof HTMLElement)) {
78
82
  return;
79
83
  }
80
- if (isTypeAheadOpen || isEditing) {
84
+ const isViewMode = editorViewMode === 'view';
85
+ const shouldRestrictBySide = rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true) && !isViewMode;
86
+ // Only restrict by side when hoverSide is known. When undefined, show quick insert.
87
+ const sideHidden = shouldRestrictBySide && hoverSide !== undefined ? hoverSide !== 'left' : false;
88
+ if (isTypeAheadOpen || isEditing || sideHidden) {
81
89
  dom.classList.add('blocks-quick-insert-invisible-container');
82
90
  dom.classList.remove('blocks-quick-insert-visible-container');
83
91
  } else {
@@ -92,12 +100,28 @@ export const createVanillaButton = props => {
92
100
  isTypeAheadOpen = nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.isOpen;
93
101
  changeDOMVisibility();
94
102
  }));
95
- props.cleanupCallbacks.push((_props$api$blockContr3 = props.api.blockControls) === null || _props$api$blockContr3 === void 0 ? void 0 : _props$api$blockContr3.sharedState.onChange(({
103
+ props.cleanupCallbacks.push((_props$api$blockContr8 = props.api.blockControls) === null || _props$api$blockContr8 === void 0 ? void 0 : _props$api$blockContr8.sharedState.onChange(({
96
104
  nextSharedState
97
105
  }) => {
106
+ var _nextSharedState$righ;
98
107
  isEditing = nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.isEditing;
108
+ hoverSide = nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.hoverSide;
109
+ rightSideControlsEnabled = (_nextSharedState$righ = nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.rightSideControlsEnabled) !== null && _nextSharedState$righ !== void 0 ? _nextSharedState$righ : false;
99
110
  changeDOMVisibility();
100
111
  }));
112
+ // Only subscribe to view mode when right-side controls are enabled (editorViewMode affects side restriction)
113
+ if (rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true)) {
114
+ var _props$api$editorView3, _props$api$editorView4, _props$api$editorView5;
115
+ const unsubscribeViewMode = (_props$api$editorView3 = props.api.editorViewMode) === null || _props$api$editorView3 === void 0 ? void 0 : (_props$api$editorView4 = (_props$api$editorView5 = _props$api$editorView3.sharedState).onChange) === null || _props$api$editorView4 === void 0 ? void 0 : _props$api$editorView4.call(_props$api$editorView5, ({
116
+ nextSharedState
117
+ }) => {
118
+ editorViewMode = nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.mode;
119
+ changeDOMVisibility();
120
+ });
121
+ if (unsubscribeViewMode) {
122
+ props.cleanupCallbacks.push(unsubscribeViewMode);
123
+ }
124
+ }
101
125
  return dom;
102
126
  };
103
127
  const TEXT_PARENT_TYPES = ['paragraph', 'heading', 'blockquote', 'taskItem', 'decisionItem'];
@@ -16,7 +16,6 @@ import { dragToMoveDown, dragToMoveLeft, dragToMoveRight, dragToMoveUp, getAriaK
16
16
  import { blockControlsMessages } from '@atlaskit/editor-common/messages';
17
17
  import { expandToBlockRange, isMultiBlockRange } from '@atlaskit/editor-common/selection';
18
18
  import { DRAG_HANDLE_WIDTH, tableControlsSpacing } from '@atlaskit/editor-common/styles';
19
- import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
20
19
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
21
20
  import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
22
21
  import { akEditorFullPageNarrowBreakout, akEditorTableToolbarSize, relativeSizeToBaseFontSize } from '@atlaskit/editor-shared-styles/consts';
@@ -415,16 +414,19 @@ export const DragHandle = ({
415
414
  });
416
415
  const [isFocused, setIsFocused] = useState(Boolean(handleOptions === null || handleOptions === void 0 ? void 0 : handleOptions.isFocused));
417
416
  const {
418
- macroInteractionUpdates
419
- } = useSharedPluginStateWithSelector(api, ['featureFlags'], states => {
420
- var _states$featureFlagsS;
417
+ macroInteractionUpdates,
418
+ selection,
419
+ isShiftDown,
420
+ interactionState
421
+ } = useSharedPluginStateWithSelector(api, ['featureFlags', 'selection', 'blockControls', 'interaction'], states => {
422
+ var _states$featureFlagsS, _states$selectionStat, _states$blockControls, _states$interactionSt;
421
423
  return {
422
- macroInteractionUpdates: (_states$featureFlagsS = states.featureFlagsState) === null || _states$featureFlagsS === void 0 ? void 0 : _states$featureFlagsS.macroInteractionUpdates
424
+ macroInteractionUpdates: (_states$featureFlagsS = states.featureFlagsState) === null || _states$featureFlagsS === void 0 ? void 0 : _states$featureFlagsS.macroInteractionUpdates,
425
+ selection: (_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection,
426
+ isShiftDown: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.isShiftDown,
427
+ interactionState: (_states$interactionSt = states.interactionState) === null || _states$interactionSt === void 0 ? void 0 : _states$interactionSt.interactionState
423
428
  };
424
429
  });
425
- const selection = useSharedPluginStateSelector(api, 'selection.selection');
426
- const isShiftDown = useSharedPluginStateSelector(api, 'blockControls.isShiftDown');
427
- const interactionState = useSharedPluginStateSelector(api, 'interaction.interactionState');
428
430
  const start = getPos();
429
431
  const isLayoutColumn = nodeType === 'layoutColumn';
430
432
  const isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true);
@@ -1110,6 +1112,7 @@ export const DragHandle = ({
1110
1112
  onDrop: handleOnDrop,
1111
1113
  disabled: dragHandleDisabled,
1112
1114
  "data-editor-block-ctrl-drag-handle": true,
1115
+ "data-blocks-drag-handle": expValEquals('confluence_remix_icon_right_side', 'isEnabled', true) || undefined,
1113
1116
  "data-testid": "block-ctrl-drag-handle",
1114
1117
  "aria-label": dragHandleAriaLabel,
1115
1118
  onBlur: expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true) ? () => setIsFocused(false) : undefined
@@ -1187,8 +1190,15 @@ export const DragHandleWithVisibility = ({
1187
1190
  isTopLevelNode,
1188
1191
  anchorRectCache
1189
1192
  }) => {
1193
+ const rightSideControlsEnabled = useSharedPluginStateWithSelector(api, ['blockControls'], states => {
1194
+ var _states$blockControls2, _states$blockControls3;
1195
+ return {
1196
+ rightSideControlsEnabled: (_states$blockControls2 = (_states$blockControls3 = states.blockControlsState) === null || _states$blockControls3 === void 0 ? void 0 : _states$blockControls3.rightSideControlsEnabled) !== null && _states$blockControls2 !== void 0 ? _states$blockControls2 : false
1197
+ };
1198
+ }).rightSideControlsEnabled;
1190
1199
  return jsx(VisibilityContainer, {
1191
- api: api
1200
+ api: api,
1201
+ controlSide: rightSideControlsEnabled ? 'left' : undefined
1192
1202
  }, jsx(DragHandle, {
1193
1203
  view: view,
1194
1204
  api: api,
@@ -4,9 +4,9 @@
4
4
  */
5
5
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-global-styles, @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
6
6
  import { css, Global, jsx } from '@emotion/react';
7
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
7
8
  import { ANCHOR_VARIABLE_NAME, DRAG_HANDLE_WIDTH, isCSSAnchorSupported, tableControlsSpacing } from '@atlaskit/editor-common/styles';
8
9
  import { areToolbarFlagsEnabled } from '@atlaskit/editor-common/toolbar-flag-check';
9
- import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
10
10
  import { ZERO_WIDTH_SPACE } from '@atlaskit/editor-common/whitespace';
11
11
  import { akEditorBreakoutPadding, akEditorCalculatedWideLayoutWidth, akEditorCalculatedWideLayoutWidthSmallViewport, akEditorFullPageNarrowBreakout, akEditorGutterPaddingDynamic, akEditorGutterPaddingReduced } from '@atlaskit/editor-shared-styles';
12
12
  import { layers } from '@atlaskit/theme/constants';
@@ -544,9 +544,15 @@ const dragAnchorStyles = css({
544
544
  export const GlobalStylesWrapper = ({
545
545
  api
546
546
  }) => {
547
- const isDragging = useSharedPluginStateSelector(api, 'blockControls.isDragging', {
548
- disabled: !expValEquals('platform_editor_block_controls_perf_optimization', 'isEnabled', true)
547
+ const {
548
+ isDragging: isDraggingFromState
549
+ } = useSharedPluginStateWithSelector(api, ['blockControls'], states => {
550
+ var _states$blockControls;
551
+ return {
552
+ isDragging: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.isDragging
553
+ };
549
554
  });
555
+ const isDragging = expValEquals('platform_editor_block_controls_perf_optimization', 'isEnabled', true) ? isDraggingFromState : false;
550
556
  const shouldRenderAnchors = isCSSAnchorSupported() && expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true);
551
557
  const toolbarFlagsEnabled = areToolbarFlagsEnabled(Boolean(api === null || api === void 0 ? void 0 : api.toolbar));
552
558
  return jsx(Global, {
@@ -8,10 +8,10 @@ import React, { useCallback, useEffect, useState } from 'react';
8
8
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
9
9
  import { css, jsx } from '@emotion/react';
10
10
  import { bind } from 'bind-event-listener';
11
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
11
12
  import { ToolTipContent } from '@atlaskit/editor-common/keymaps';
12
13
  import { blockControlsMessages as messages } from '@atlaskit/editor-common/messages';
13
14
  import { tableControlsSpacing } from '@atlaskit/editor-common/styles';
14
- import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
15
15
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
16
16
  import { findParentNode, findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
17
17
  import { relativeSizeToBaseFontSize } from '@atlaskit/editor-shared-styles';
@@ -152,7 +152,14 @@ export const TypeAheadControl = ({
152
152
  rootNodeType,
153
153
  anchorRectCache
154
154
  }) => {
155
- const macroInteractionUpdates = useSharedPluginStateSelector(api, 'featureFlags.macroInteractionUpdates');
155
+ const {
156
+ macroInteractionUpdates
157
+ } = useSharedPluginStateWithSelector(api, ['featureFlags'], states => {
158
+ var _states$featureFlagsS;
159
+ return {
160
+ macroInteractionUpdates: (_states$featureFlagsS = states.featureFlagsState) === null || _states$featureFlagsS === void 0 ? void 0 : _states$featureFlagsS.macroInteractionUpdates
161
+ };
162
+ });
156
163
  const [positionStyles, setPositionStyles] = useState({
157
164
  display: 'none'
158
165
  });
@@ -359,8 +366,15 @@ export const QuickInsertWithVisibility = ({
359
366
  rootNodeType,
360
367
  anchorRectCache
361
368
  }) => {
369
+ const rightSideControlsEnabled = useSharedPluginStateWithSelector(api, ['blockControls'], states => {
370
+ var _states$blockControls, _states$blockControls2;
371
+ return {
372
+ rightSideControlsEnabled: (_states$blockControls = (_states$blockControls2 = states.blockControlsState) === null || _states$blockControls2 === void 0 ? void 0 : _states$blockControls2.rightSideControlsEnabled) !== null && _states$blockControls !== void 0 ? _states$blockControls : false
373
+ };
374
+ }).rightSideControlsEnabled;
362
375
  return jsx(VisibilityContainer, {
363
- api: api
376
+ api: api,
377
+ controlSide: rightSideControlsEnabled ? 'left' : undefined
364
378
  }, jsx(TypeAheadControl, {
365
379
  view: view,
366
380
  api: api,
@@ -2,15 +2,17 @@
2
2
  * @jsxRuntime classic
3
3
  * @jsx jsx
4
4
  */
5
- import React from 'react';
5
+ import React, { useEffect, useRef, useState } from 'react';
6
6
 
7
7
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
8
8
  import { css, jsx } from '@emotion/react';
9
- import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
9
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
10
10
  import { akEditorFullPageNarrowBreakout } from '@atlaskit/editor-shared-styles';
11
11
  // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
12
12
  import { Box, xcss } from '@atlaskit/primitives';
13
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
13
14
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
15
+ const RIGHT_CONTROL_HIDE_DELAY_MS = 150;
14
16
  const baseStyles = xcss({
15
17
  transition: 'opacity 0.1s ease-in-out, visibility 0.1s ease-in-out'
16
18
  });
@@ -40,15 +42,69 @@ const hiddenStylesCSS = css({
40
42
  });
41
43
  export const VisibilityContainer = ({
42
44
  api,
43
- children
45
+ children,
46
+ controlSide
44
47
  }) => {
45
- const isTypeAheadOpen = useSharedPluginStateSelector(api, 'typeAhead.isOpen');
46
- const isEditing = useSharedPluginStateSelector(api, 'blockControls.isEditing');
47
- const isMouseOut = useSharedPluginStateSelector(api, 'blockControls.isMouseOut');
48
+ const {
49
+ isTypeAheadOpen,
50
+ isEditing,
51
+ isMouseOut,
52
+ hoverSide,
53
+ editorViewMode,
54
+ userIntent,
55
+ rightSideControlsEnabled
56
+ } = useSharedPluginStateWithSelector(api, ['typeAhead', 'blockControls', 'editorViewMode', 'userIntent'], states => {
57
+ var _states$typeAheadStat, _states$blockControls, _states$blockControls2, _states$blockControls3, _states$editorViewMod, _states$userIntentSta, _states$blockControls4;
58
+ return {
59
+ isTypeAheadOpen: (_states$typeAheadStat = states.typeAheadState) === null || _states$typeAheadStat === void 0 ? void 0 : _states$typeAheadStat.isOpen,
60
+ isEditing: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.isEditing,
61
+ isMouseOut: (_states$blockControls2 = states.blockControlsState) === null || _states$blockControls2 === void 0 ? void 0 : _states$blockControls2.isMouseOut,
62
+ hoverSide: (_states$blockControls3 = states.blockControlsState) === null || _states$blockControls3 === void 0 ? void 0 : _states$blockControls3.hoverSide,
63
+ editorViewMode: (_states$editorViewMod = states.editorViewModeState) === null || _states$editorViewMod === void 0 ? void 0 : _states$editorViewMod.mode,
64
+ userIntent: (_states$userIntentSta = states.userIntentState) === null || _states$userIntentSta === void 0 ? void 0 : _states$userIntentSta.currentUserIntent,
65
+ rightSideControlsEnabled: (_states$blockControls4 = states.blockControlsState) === null || _states$blockControls4 === void 0 ? void 0 : _states$blockControls4.rightSideControlsEnabled
66
+ };
67
+ });
68
+ const isViewMode = editorViewMode === 'view';
69
+ const shouldRestrictBySide = rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true) && controlSide !== undefined && !isViewMode;
70
+ // Only restrict by side when hoverSide is known (after mousemove). When undefined, show both
71
+ // controls so drag handle is visible on load and for keyboard-only users.
72
+ const sideHidden = shouldRestrictBySide && hoverSide !== undefined ? hoverSide !== controlSide : false;
73
+ // In view mode with right-side controls, we delay hiding on isMouseOut (see below) so the right-edge
74
+ // button stays visible when the user moves from the block toward the button (e.g. in edit/live
75
+ // pages), avoiding flicker as the mouse crosses boundaries.
76
+ const hideOnMouseOut = isMouseOut;
77
+ const shouldHideImmediate = isTypeAheadOpen || isEditing || hideOnMouseOut || userIntent === 'aiStreaming' || sideHidden;
48
78
 
49
- // when ai streaming, hide the block controls
50
- const userIntent = useSharedPluginStateSelector(api, 'userIntent.currentUserIntent');
51
- const shouldHide = isTypeAheadOpen || isEditing || isMouseOut || userIntent === 'aiStreaming';
79
+ // Delay hiding the right control in view mode to reduce flickering when moving from block
80
+ // toward the right-edge button (avoids rapid show/hide as mouse crosses boundaries).
81
+ const isRightControlViewMode = isViewMode && rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true) && controlSide === 'right';
82
+ // When in right-control view mode, we delay hiding so start visible; useEffect will update after delay
83
+ const [delayedShouldHide, setDelayedShouldHide] = useState(false);
84
+ const hideTimeoutRef = useRef(null);
85
+ useEffect(() => {
86
+ if (!isRightControlViewMode) {
87
+ return;
88
+ }
89
+ if (!shouldHideImmediate) {
90
+ if (hideTimeoutRef.current) {
91
+ clearTimeout(hideTimeoutRef.current);
92
+ hideTimeoutRef.current = null;
93
+ }
94
+ setDelayedShouldHide(false);
95
+ return;
96
+ }
97
+ hideTimeoutRef.current = setTimeout(() => {
98
+ hideTimeoutRef.current = null;
99
+ setDelayedShouldHide(true);
100
+ }, RIGHT_CONTROL_HIDE_DELAY_MS);
101
+ return () => {
102
+ if (hideTimeoutRef.current) {
103
+ clearTimeout(hideTimeoutRef.current);
104
+ }
105
+ };
106
+ }, [shouldHideImmediate, isRightControlViewMode]);
107
+ const shouldHide = isRightControlViewMode ? delayedShouldHide : shouldHideImmediate;
52
108
  if (editorExperiment('platform_editor_preview_panel_responsiveness', true, {
53
109
  exposure: true
54
110
  })) {
@@ -6,6 +6,7 @@ import { expandSelectionBounds } from '@atlaskit/editor-common/selection';
6
6
  import { areToolbarFlagsEnabled } from '@atlaskit/editor-common/toolbar-flag-check';
7
7
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
8
8
  import { fg } from '@atlaskit/platform-feature-flags';
9
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
9
10
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
10
11
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
11
12
  import { handleKeyDownWithPreservedSelection } from './editor-commands/handle-key-down-with-preserved-selection';
@@ -23,8 +24,11 @@ import { createSelectionPreservationPlugin } from './pm-plugins/selection-preser
23
24
  import { selectNode } from './pm-plugins/utils/getSelection';
24
25
  import { GlobalStylesWrapper } from './ui/global-styles';
25
26
  export var blockControlsPlugin = function blockControlsPlugin(_ref) {
26
- var api = _ref.api;
27
+ var _config$rightSideCont;
28
+ var api = _ref.api,
29
+ config = _ref.config;
27
30
  var nodeDecorationRegistry = [];
31
+ var rightSideControlsEnabled = (_config$rightSideCont = config === null || config === void 0 ? void 0 : config.rightSideControlsEnabled) !== null && _config$rightSideCont !== void 0 ? _config$rightSideCont : false;
28
32
  return {
29
33
  name: 'blockControls',
30
34
  actions: {
@@ -46,13 +50,15 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
46
50
  plugin: function plugin(_ref2) {
47
51
  var getIntl = _ref2.getIntl,
48
52
  nodeViewPortalProviderAPI = _ref2.nodeViewPortalProviderAPI;
49
- return createPlugin(api, getIntl, nodeViewPortalProviderAPI, nodeDecorationRegistry);
53
+ return createPlugin(api, getIntl, nodeViewPortalProviderAPI, nodeDecorationRegistry, rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true));
50
54
  }
51
55
  }];
52
56
  if (editorExperiment('platform_editor_controls', 'variant1')) {
53
57
  pmPlugins.push({
54
58
  name: 'blockControlsInteractionTrackingPlugin',
55
- plugin: createInteractionTrackingPlugin
59
+ plugin: function plugin() {
60
+ return createInteractionTrackingPlugin(rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true));
61
+ }
56
62
  });
57
63
  }
58
64
  if (expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true)) {
@@ -325,6 +331,11 @@ export var blockControlsPlugin = function blockControlsPlugin(_ref) {
325
331
  if (editorExperiment('platform_editor_controls', 'variant1')) {
326
332
  var _interactionTrackingP2, _interactionTrackingP3;
327
333
  sharedState.isMouseOut = (_interactionTrackingP2 = (_interactionTrackingP3 = interactionTrackingPluginKey.getState(editorState)) === null || _interactionTrackingP3 === void 0 ? void 0 : _interactionTrackingP3.isMouseOut) !== null && _interactionTrackingP2 !== void 0 ? _interactionTrackingP2 : false;
334
+ sharedState.rightSideControlsEnabled = rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true);
335
+ if (rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true)) {
336
+ var _interactionTrackingP4;
337
+ sharedState.hoverSide = (_interactionTrackingP4 = interactionTrackingPluginKey.getState(editorState)) === null || _interactionTrackingP4 === void 0 ? void 0 : _interactionTrackingP4.hoverSide;
338
+ }
328
339
  }
329
340
  if (expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true)) {
330
341
  var _selectionPreservatio;
@@ -77,6 +77,9 @@ export var dragHandleDecoration = function dragHandleDecoration(_ref) {
77
77
  var element = document.createElement('span');
78
78
  // inline decoration causes focus issues when refocusing Editor into first line
79
79
  element.style.display = 'block';
80
+ if (expValEquals('confluence_remix_icon_right_side', 'isEnabled', true)) {
81
+ element.setAttribute('data-blocks-decorator-widget', 'true');
82
+ }
80
83
  element.setAttribute('data-testid', 'block-ctrl-decorator-widget');
81
84
  element.setAttribute('data-blocks-drag-handle-container', 'true');
82
85
  element.setAttribute('data-blocks-drag-handle-key', key);
@@ -68,6 +68,9 @@ export var quickInsertButtonDecoration = function quickInsertButtonDecoration(_r
68
68
  }
69
69
  element.contentEditable = 'false';
70
70
  element.setAttribute('data-blocks-quick-insert-container', 'true');
71
+ if (expValEquals('confluence_remix_icon_right_side', 'isEnabled', true)) {
72
+ element.setAttribute('data-blocks-quick-insert-button', 'true');
73
+ }
71
74
  element.setAttribute('data-testid', 'block-ctrl-quick-insert-button');
72
75
  if (editorExperiment('platform_editor_block_control_optimise_render', true, {
73
76
  exposure: true
@@ -38,7 +38,7 @@ var getDefaultNodeSelector = memoizeOne(function () {
38
38
  return getNodeSelector([].concat(_toConsumableArray(IGNORE_NODES_NEXT), ['media']), [].concat(_toConsumableArray(IGNORE_NODE_DESCENDANTS_ADVANCED_LAYOUT), ['table']));
39
39
  });
40
40
  export var handleMouseOver = function handleMouseOver(view, event, api) {
41
- var _api$blockControls, _api$editorDisabled, _target$classList;
41
+ var _api$blockControls, _api$editorDisabled, _api$editorViewMode, _api$blockControls$sh, _api$blockControls2, _target$classList;
42
42
  var _ref = (api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
43
43
  isDragging = _ref.isDragging,
44
44
  activeNode = _ref.activeNode,
@@ -49,10 +49,14 @@ export var handleMouseOver = function handleMouseOver(view, event, api) {
49
49
  editorDisabled: false
50
50
  },
51
51
  editorDisabled = _ref2.editorDisabled;
52
+ var editorViewMode = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode;
53
+ var isViewMode = editorViewMode === 'view';
52
54
  var toolbarFlagsEnabled = areToolbarFlagsEnabled(Boolean(api === null || api === void 0 ? void 0 : api.toolbar));
53
55
 
54
- // We shouldn't be firing mouse over transactions when the editor is disabled
55
- if (editorDisabled) {
56
+ // We shouldn't be firing mouse over transactions when the editor is disabled,
57
+ // except in view mode when right-side controls are enabled (show controls on block hover)
58
+ var rightSideControlsEnabled = (_api$blockControls$sh = api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || (_api$blockControls2 = _api$blockControls2.sharedState.currentState()) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.rightSideControlsEnabled) !== null && _api$blockControls$sh !== void 0 ? _api$blockControls$sh : false;
59
+ if (editorDisabled && (!isViewMode || !(rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true)))) {
56
60
  return false;
57
61
  }
58
62
 
@@ -75,6 +79,18 @@ export var handleMouseOver = function handleMouseOver(view, event, api) {
75
79
  return false;
76
80
  }
77
81
  var rootElement = target === null || target === void 0 ? void 0 : target.closest(isNativeAnchorSupported ? getDefaultNodeSelector() : "[data-drag-handler-anchor-name]");
82
+
83
+ // When hovering over the right-edge button (rendered in a portal outside the block), resolve the
84
+ // block from the container's anchor so activeNode stays set and the button remains visible.
85
+ if (!rootElement && rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true)) {
86
+ var rightEdgeContainer = target === null || target === void 0 ? void 0 : target.closest('[data-blocks-right-edge-button-container]');
87
+ if (rightEdgeContainer) {
88
+ var anchor = rightEdgeContainer.getAttribute('data-blocks-right-edge-button-anchor');
89
+ if (anchor) {
90
+ rootElement = view.dom.querySelector("[".concat(getAnchorAttrName(), "=\"").concat(CSS.escape(anchor), "\"]"));
91
+ }
92
+ }
93
+ }
78
94
  if (rootElement) {
79
95
  var _rootElement$parentEl;
80
96
  // We want to exlude handles from showing for empty paragraph and heading nodes
@@ -183,22 +199,22 @@ export var handleMouseOver = function handleMouseOver(view, event, api) {
183
199
  // as when it is a multi-selection, the showDragHandleAt command interfere with selection
184
200
  // sometimes makes the multi-selection not continous after block menu is opened with keyboard
185
201
  if (!(isMultipleSelected && isMenuOpen && blockMenuOptions !== null && blockMenuOptions !== void 0 && blockMenuOptions.openedViaKeyboard)) {
186
- var _api$core, _api$blockControls2;
187
- 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 !== null && rootPos !== void 0 ? rootPos : targetPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType));
202
+ var _api$core, _api$blockControls3;
203
+ api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.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, undefined, rootPos !== null && rootPos !== void 0 ? rootPos : targetPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType));
188
204
  }
189
205
  } else {
190
- var _api$core2, _api$blockControls3;
191
- 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, undefined, rootPos !== null && rootPos !== void 0 ? rootPos : targetPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType));
206
+ var _api$core2, _api$blockControls4;
207
+ api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 ? void 0 : _api$blockControls4.commands.showDragHandleAt(targetPos, anchorName, nodeType, undefined, rootPos !== null && rootPos !== void 0 ? rootPos : targetPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType));
192
208
  }
193
209
  } else {
194
- var _api$core3, _api$blockControls4;
195
- api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 ? void 0 : _api$blockControls4.commands.showDragHandleAt(targetPos, anchorName, nodeType));
210
+ var _api$core3, _api$blockControls5;
211
+ api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(api === null || api === void 0 || (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 ? void 0 : _api$blockControls5.commands.showDragHandleAt(targetPos, anchorName, nodeType));
196
212
  }
197
213
  if (expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true)) {
198
214
  var _api$userIntent;
199
215
  if (isMenuOpen && originalAnchorName && (api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 || (_api$userIntent = _api$userIntent.sharedState.currentState()) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.currentUserIntent) === 'blockMenuOpen') {
200
- var _api$core4, _api$blockControls5;
201
- api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(api === null || api === void 0 || (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 ? void 0 : _api$blockControls5.commands.toggleBlockMenu());
216
+ var _api$core4, _api$blockControls6;
217
+ api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(api === null || api === void 0 || (_api$blockControls6 = api.blockControls) === null || _api$blockControls6 === void 0 ? void 0 : _api$blockControls6.commands.toggleBlockMenu());
202
218
  }
203
219
  }
204
220
  }
@@ -18,4 +18,15 @@ export var mouseEnter = function mouseEnter(view) {
18
18
  view.dispatch(view.state.tr.setMeta(interactionTrackingPluginKey, {
19
19
  type: 'mouseEnter'
20
20
  }));
21
+ };
22
+ export var setHoverSide = function setHoverSide(view, side) {
23
+ view.dispatch(view.state.tr.setMeta(interactionTrackingPluginKey, {
24
+ type: 'setHoverSide',
25
+ side: side
26
+ }));
27
+ };
28
+ export var clearHoverSide = function clearHoverSide(view) {
29
+ view.dispatch(view.state.tr.setMeta(interactionTrackingPluginKey, {
30
+ type: 'clearHoverSide'
31
+ }));
21
32
  };
@@ -1,14 +1,110 @@
1
- import { mouseEnter, mouseLeave, stopEditing } from './commands';
1
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
2
+ import { clearHoverSide, mouseEnter, mouseLeave, setHoverSide, stopEditing } from './commands';
2
3
  import { getInteractionTrackingState } from './pm-plugin';
3
- export var handleMouseMove = function handleMouseMove(view) {
4
+
5
+ /** Per-view pending hover state; avoids cross-editor singleton. */
6
+ var pendingByView = new WeakMap();
7
+
8
+ /** Per-view RAF handle so clearPendingHoverSide cancels only that view's callback. */
9
+ var rafIdByView = new WeakMap();
10
+ var cancelScheduledProcessForView = function cancelScheduledProcessForView(view) {
11
+ var id = rafIdByView.get(view);
12
+ if (id !== undefined) {
13
+ cancelAnimationFrame(id);
14
+ rafIdByView.delete(view);
15
+ }
16
+ };
17
+ var clearPendingHoverSide = function clearPendingHoverSide(view) {
18
+ pendingByView.delete(view);
19
+ cancelScheduledProcessForView(view);
20
+ };
21
+ var BLOCK_SELECTORS = '[data-node-anchor], [data-drag-handler-anchor-name]';
22
+ var TABLE_SELECTOR = '[data-prosemirror-node-name="table"]';
23
+ var RIGHT_EDGE_SELECTOR = '[data-blocks-right-edge-button-container]';
24
+ var isInsideTable = function isInsideTable(element) {
25
+ var _element$getAttribute;
26
+ return element.closest(TABLE_SELECTOR) !== null || ((_element$getAttribute = element.getAttribute) === null || _element$getAttribute === void 0 ? void 0 : _element$getAttribute.call(element, 'data-prosemirror-node-name')) === 'table';
27
+ };
28
+ var processHoverSide = function processHoverSide(view) {
29
+ var event = pendingByView.get(view);
30
+ if (!event) {
31
+ return;
32
+ }
33
+ pendingByView.delete(view);
34
+ rafIdByView.delete(view);
35
+ var editorContentArea = view.dom.closest('.ak-editor-content-area');
36
+ if (!(editorContentArea instanceof HTMLElement)) {
37
+ return;
38
+ }
39
+ var state = getInteractionTrackingState(view.state);
40
+ var target = event.target instanceof HTMLElement ? event.target : null;
41
+
42
+ // When hovering over block controls directly, infer side from which control we're over.
43
+ // This is more reliable than bounds when controls are in portals outside the editor DOM.
44
+ var rightEdgeElement = target === null || target === void 0 ? void 0 : target.closest(RIGHT_EDGE_SELECTOR);
45
+ if (rightEdgeElement) {
46
+ if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'right') {
47
+ setHoverSide(view, 'right');
48
+ }
49
+ return;
50
+ }
51
+ var leftControlElement = target === null || target === void 0 ? void 0 : target.closest('[data-blocks-drag-handle-container], [data-testid="block-ctrl-drag-handle"], [data-testid="block-ctrl-drag-handle-container"], [data-testid="block-ctrl-decorator-widget"], [data-testid="block-ctrl-quick-insert-button"]');
52
+ if (leftControlElement) {
53
+ if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'left') {
54
+ setHoverSide(view, 'left');
55
+ }
56
+ return;
57
+ }
58
+
59
+ // Use the hovered block's midpoint when hovering over block content.
60
+ var blockElement = target === null || target === void 0 ? void 0 : target.closest(BLOCK_SELECTORS);
61
+ var boundsElement = blockElement instanceof HTMLElement ? blockElement : editorContentArea;
62
+
63
+ // Tables show block controls at table level; don't restrict by side so drag handle
64
+ // stays visible when hovering anywhere in the table (e.g. paragraph in second cell).
65
+ if (isInsideTable(boundsElement)) {
66
+ if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== undefined) {
67
+ clearHoverSide(view);
68
+ }
69
+ return;
70
+ }
71
+ var _boundsElement$getBou = boundsElement.getBoundingClientRect(),
72
+ left = _boundsElement$getBou.left,
73
+ right = _boundsElement$getBou.right;
74
+ var midpoint = (left + right) / 2;
75
+ var nextHoverSide = event.clientX > midpoint ? 'right' : 'left';
76
+ if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== nextHoverSide) {
77
+ setHoverSide(view, nextHoverSide);
78
+ }
79
+ };
80
+ export var handleMouseMove = function handleMouseMove(view, event) {
81
+ var rightSideControlsEnabled = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
4
82
  var state = getInteractionTrackingState(view.state);
5
83
  // if user has stopped editing and moved their mouse, show block controls again
6
84
  if (state !== null && state !== void 0 && state.isEditing) {
7
85
  stopEditing(view);
8
86
  }
87
+
88
+ // Only track hover side when right-side controls are enabled and experiment is on (performance)
89
+ if (!rightSideControlsEnabled || !expValEquals('confluence_remix_icon_right_side', 'isEnabled', true)) {
90
+ return false;
91
+ }
92
+ if (!(event instanceof MouseEvent)) {
93
+ return false;
94
+ }
95
+ pendingByView.set(view, event);
96
+ cancelScheduledProcessForView(view);
97
+ var id = requestAnimationFrame(function () {
98
+ processHoverSide(view);
99
+ });
100
+ rafIdByView.set(view, id);
9
101
  return false;
10
102
  };
11
103
  export var handleMouseLeave = function handleMouseLeave(view) {
104
+ var rightSideControlsEnabled = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
105
+ if (rightSideControlsEnabled && expValEquals('confluence_remix_icon_right_side', 'isEnabled', true)) {
106
+ clearPendingHoverSide(view);
107
+ }
12
108
  mouseLeave(view);
13
109
  return false;
14
110
  };