@atlaskit/editor-plugin-toolbar 12.0.11 → 12.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @atlaskit/editor-plugin-toolbar
2
2
 
3
+ ## 12.0.12
4
+
5
+ ### Patch Changes
6
+
7
+ - [`7d227f4a065e5`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/7d227f4a065e5) -
8
+ Prevent selection toolbar false failures when user intent suppresses the toolbar, and exclude
9
+ structural Shift+Arrow and unchanged-selection mouse interactions behind
10
+ platform_editor_toolbar_intent_fix
11
+ - Updated dependencies
12
+
3
13
  ## 12.0.11
4
14
 
5
15
  ### Patch Changes
@@ -10,6 +10,8 @@ var _analytics = require("@atlaskit/editor-common/analytics");
10
10
  var _experiences = require("@atlaskit/editor-common/experiences");
11
11
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
12
12
  var _state = require("@atlaskit/editor-prosemirror/state");
13
+ var _fg = require("@atlaskit/platform-feature-flags/fg");
14
+ var _visibility = require("../../ui/SelectionToolbar/visibility");
13
15
  var pluginKey = new _state.PluginKey('selectionToolbarOpenExperience');
14
16
  var START_METHOD = {
15
17
  MOUSE_UP: 'mouseUp',
@@ -18,7 +20,8 @@ var START_METHOD = {
18
20
  var ABORT_REASON = {
19
21
  SELECTION_CLEARED: 'selectionCleared',
20
22
  BLOCK_MENU_OPENED: 'blockMenuOpened',
21
- EDITOR_DESTROYED: 'editorDestroyed'
23
+ EDITOR_DESTROYED: 'editorDestroyed',
24
+ USER_INTENT_SUPPRESSED: 'userIntentSuppressed'
22
25
  };
23
26
  /**
24
27
  * This experience tracks when the selection toolbar is opened.
@@ -32,11 +35,14 @@ var ABORT_REASON = {
32
35
  */
33
36
  var getSelectionToolbarOpenExperiencePlugin = exports.getSelectionToolbarOpenExperiencePlugin = function getSelectionToolbarOpenExperiencePlugin(_ref) {
34
37
  var refs = _ref.refs,
35
- dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent;
38
+ dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent,
39
+ getCurrentUserIntent = _ref.getCurrentUserIntent;
40
+ var isIntentFixEnabled = (0, _fg.fg)('platform_editor_toolbar_intent_fix');
36
41
  var editorView;
37
42
  var targetEl;
38
43
  var shiftArrowKeyPressed = false;
39
44
  var mouseDownPos;
45
+ var mouseDownSelection;
40
46
  var getTarget = function getTarget() {
41
47
  if (!targetEl) {
42
48
  var _editorView;
@@ -44,19 +50,31 @@ var getSelectionToolbarOpenExperiencePlugin = exports.getSelectionToolbarOpenExp
44
50
  }
45
51
  return targetEl;
46
52
  };
53
+ var isCurrentUserIntentSuppressingToolbar = function isCurrentUserIntentSuppressingToolbar(selection) {
54
+ if (!selection) {
55
+ return false;
56
+ }
57
+ var isCellSelection = !selection.empty && '$anchorCell' in selection;
58
+ return (0, _visibility.isSelectionToolbarSuppressedByUserIntent)(getCurrentUserIntent === null || getCurrentUserIntent === void 0 ? void 0 : getCurrentUserIntent(), isCellSelection);
59
+ };
47
60
  var experience = new _experiences.Experience(_experiences.EXPERIENCE_ID.TOOLBAR_OPEN, {
48
61
  actionSubjectId: _analytics.ACTION_SUBJECT_ID.SELECTION_TOOLBAR,
49
62
  dispatchAnalyticsEvent: dispatchAnalyticsEvent,
50
63
  checks: [new _experiences.ExperienceCheckTimeout({
51
64
  durationMs: 1000,
52
65
  onTimeout: function onTimeout() {
53
- var _editorView2;
54
- if (isBlockMenuWithinNode(getTarget())) {
66
+ var _editorView2, _editorView3;
67
+ if (isIntentFixEnabled && isCurrentUserIntentSuppressingToolbar((_editorView2 = editorView) === null || _editorView2 === void 0 ? void 0 : _editorView2.state.selection)) {
68
+ return {
69
+ status: 'abort',
70
+ reason: ABORT_REASON.USER_INTENT_SUPPRESSED
71
+ };
72
+ } else if (isBlockMenuWithinNode(getTarget())) {
55
73
  return {
56
74
  status: 'abort',
57
75
  reason: ABORT_REASON.BLOCK_MENU_OPENED
58
76
  };
59
- } else if (isSelectionWithoutTextContent((_editorView2 = editorView) === null || _editorView2 === void 0 ? void 0 : _editorView2.state.selection)) {
77
+ } else if (isSelectionWithoutTextContent((_editorView3 = editorView) === null || _editorView3 === void 0 ? void 0 : _editorView3.state.selection)) {
60
78
  return {
61
79
  status: 'abort',
62
80
  reason: ABORT_REASON.SELECTION_CLEARED
@@ -83,7 +101,7 @@ var getSelectionToolbarOpenExperiencePlugin = exports.getSelectionToolbarOpenExp
83
101
  })]
84
102
  });
85
103
  var shouldSkipExperienceStart = function shouldSkipExperienceStart(selection) {
86
- if (isSelectionWithoutTextContent(selection) || isSelectionWithinCodeBlock(selection)) {
104
+ if (isSelectionWithoutTextContent(selection) || isSelectionWithinCodeBlock(selection) || isIntentFixEnabled && isCurrentUserIntentSuppressingToolbar(selection)) {
87
105
  return true;
88
106
  }
89
107
  var target = getTarget();
@@ -117,17 +135,27 @@ var getSelectionToolbarOpenExperiencePlugin = exports.getSelectionToolbarOpenExp
117
135
  },
118
136
  props: {
119
137
  handleDOMEvents: {
120
- mousedown: function mousedown(_view, e) {
138
+ mousedown: function mousedown(view, e) {
121
139
  mouseDownPos = {
122
140
  x: e.clientX,
123
141
  y: e.clientY
124
142
  };
143
+ if (isIntentFixEnabled) {
144
+ mouseDownSelection = view.state.selection;
145
+ }
125
146
  },
126
147
  mouseup: function mouseup(view, e) {
127
- if (!mouseDownPos || shouldSkipExperienceStart(view.state.selection)) {
148
+ var initialMouseDownPos = mouseDownPos;
149
+ var selectionChanged = (0, _visibility.hasSelectionChanged)(mouseDownSelection, view.state.selection);
150
+ if (isIntentFixEnabled) {
151
+ mouseDownPos = undefined;
152
+ mouseDownSelection = undefined;
153
+ }
154
+ if (!initialMouseDownPos || shouldSkipExperienceStart(view.state.selection)) {
128
155
  return;
129
156
  }
130
- if (e.clientX !== mouseDownPos.x || e.clientY !== mouseDownPos.y) {
157
+ var mouseCoordinatesChanged = e.clientX !== initialMouseDownPos.x || e.clientY !== initialMouseDownPos.y;
158
+ if (mouseCoordinatesChanged && (!isIntentFixEnabled || selectionChanged)) {
131
159
  experience.start({
132
160
  method: START_METHOD.MOUSE_UP
133
161
  });
@@ -141,10 +169,8 @@ var getSelectionToolbarOpenExperiencePlugin = exports.getSelectionToolbarOpenExp
141
169
  method: START_METHOD.MOUSE_UP
142
170
  });
143
171
  },
144
- keydown: function keydown(_view, _ref3) {
145
- var shiftKey = _ref3.shiftKey,
146
- key = _ref3.key;
147
- shiftArrowKeyPressed = shiftKey && key.includes('Arrow') && !isSelectionToolbarWithinNode(getTarget());
172
+ keydown: function keydown(_view, event) {
173
+ shiftArrowKeyPressed = (isIntentFixEnabled ? (0, _visibility.isPlainShiftArrowKey)(event) : event.shiftKey && event.key.includes('Arrow')) && !isSelectionToolbarWithinNode(getTarget());
148
174
  },
149
175
  keyup: function keyup() {
150
176
  shiftArrowKeyPressed = false;
@@ -163,9 +189,9 @@ var getSelectionToolbarOpenExperiencePlugin = exports.getSelectionToolbarOpenExp
163
189
  }
164
190
  });
165
191
  };
166
- var isSelectionToolbarAddedInMutation = function isSelectionToolbarAddedInMutation(_ref4) {
167
- var type = _ref4.type,
168
- addedNodes = _ref4.addedNodes;
192
+ var isSelectionToolbarAddedInMutation = function isSelectionToolbarAddedInMutation(_ref3) {
193
+ var type = _ref3.type,
194
+ addedNodes = _ref3.addedNodes;
169
195
  return type === 'childList' && (0, _toConsumableArray2.default)(addedNodes).some(isSelectionToolbarWithinNode);
170
196
  };
171
197
  var isSelectionToolbarWithinNode = function isSelectionToolbarWithinNode(node) {
@@ -269,6 +269,10 @@ var toolbarPlugin = exports.toolbarPlugin = function toolbarPlugin(_ref) {
269
269
  dispatchAnalyticsEvent: function dispatchAnalyticsEvent(payload) {
270
270
  var _api$analytics;
271
271
  return api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 ? void 0 : _api$analytics.fireAnalyticsEvent(payload);
272
+ },
273
+ getCurrentUserIntent: function getCurrentUserIntent() {
274
+ var _api$userIntent;
275
+ return 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;
272
276
  }
273
277
  });
274
278
  }
@@ -26,6 +26,7 @@ var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
26
26
  var _consts = require("../consts");
27
27
  var _keyboardConfig = require("./keyboard-config");
28
28
  var _utils2 = require("./utils");
29
+ var _visibility = require("./visibility");
29
30
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
30
31
  var isToolbarComponent = function isToolbarComponent(component) {
31
32
  return component.type === 'toolbar' && component.key === 'inline-text-toolbar';
@@ -100,7 +101,7 @@ var SelectionToolbar = exports.SelectionToolbar = function SelectionToolbar(_ref
100
101
  }
101
102
  if (!(isTextSelection || isCellSelection || isAllSelection) || currentUserIntent === 'dragging' || !shouldShowToolbar || currentUserIntent === 'blockMenuOpen' && (0, _experiments.editorExperiment)('platform_editor_block_menu', true) ||
102
103
  // hide toolbar when user intent is not default, except when it's dragHandleSelected without cell selection
103
- currentUserIntent && currentUserIntent !== 'default' && !(currentUserIntent === 'dragHandleSelected' && !isCellSelection) || (0, _coreUtils.isSSR)()) {
104
+ (0, _visibility.isSelectionToolbarSuppressedByUserIntent)(currentUserIntent, isCellSelection) || (0, _coreUtils.isSSR)()) {
104
105
  return null;
105
106
  }
106
107
  var toolbarContent = /*#__PURE__*/_react.default.createElement(_toolbar.EditorToolbarProvider, {
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isSelectionToolbarSuppressedByUserIntent = exports.isPlainShiftArrowKey = exports.hasSelectionChanged = void 0;
7
+ var isSelectionToolbarSuppressedByUserIntent = exports.isSelectionToolbarSuppressedByUserIntent = function isSelectionToolbarSuppressedByUserIntent(currentUserIntent, isCellSelection) {
8
+ return Boolean(currentUserIntent && currentUserIntent !== 'default' && !(currentUserIntent === 'dragHandleSelected' && !isCellSelection));
9
+ };
10
+ var isPlainShiftArrowKey = exports.isPlainShiftArrowKey = function isPlainShiftArrowKey(_ref) {
11
+ var shiftKey = _ref.shiftKey,
12
+ key = _ref.key,
13
+ metaKey = _ref.metaKey,
14
+ ctrlKey = _ref.ctrlKey,
15
+ altKey = _ref.altKey;
16
+ return shiftKey && !metaKey && !ctrlKey && !altKey && key.includes('Arrow');
17
+ };
18
+ var hasSelectionChanged = exports.hasSelectionChanged = function hasSelectionChanged(mouseDownSelection, currentSelection) {
19
+ return Boolean(mouseDownSelection && !mouseDownSelection.eq(currentSelection));
20
+ };
@@ -2,6 +2,8 @@ import { ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
2
2
  import { containsPopupWithNestedElement, Experience, EXPERIENCE_ID, ExperienceCheckDomMutation, ExperienceCheckTimeout, getPopupContainerFromEditorView } from '@atlaskit/editor-common/experiences';
3
3
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
4
4
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
5
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
6
+ import { hasSelectionChanged, isPlainShiftArrowKey, isSelectionToolbarSuppressedByUserIntent } from '../../ui/SelectionToolbar/visibility';
5
7
  const pluginKey = new PluginKey('selectionToolbarOpenExperience');
6
8
  const START_METHOD = {
7
9
  MOUSE_UP: 'mouseUp',
@@ -10,7 +12,8 @@ const START_METHOD = {
10
12
  const ABORT_REASON = {
11
13
  SELECTION_CLEARED: 'selectionCleared',
12
14
  BLOCK_MENU_OPENED: 'blockMenuOpened',
13
- EDITOR_DESTROYED: 'editorDestroyed'
15
+ EDITOR_DESTROYED: 'editorDestroyed',
16
+ USER_INTENT_SUPPRESSED: 'userIntentSuppressed'
14
17
  };
15
18
  /**
16
19
  * This experience tracks when the selection toolbar is opened.
@@ -24,13 +27,16 @@ const ABORT_REASON = {
24
27
  */
25
28
  export const getSelectionToolbarOpenExperiencePlugin = ({
26
29
  refs,
27
- dispatchAnalyticsEvent
30
+ dispatchAnalyticsEvent,
31
+ getCurrentUserIntent
28
32
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
29
33
  }) => {
34
+ const isIntentFixEnabled = fg('platform_editor_toolbar_intent_fix');
30
35
  let editorView;
31
36
  let targetEl;
32
37
  let shiftArrowKeyPressed = false;
33
38
  let mouseDownPos;
39
+ let mouseDownSelection;
34
40
  const getTarget = () => {
35
41
  if (!targetEl) {
36
42
  var _editorView;
@@ -38,19 +44,31 @@ export const getSelectionToolbarOpenExperiencePlugin = ({
38
44
  }
39
45
  return targetEl;
40
46
  };
47
+ const isCurrentUserIntentSuppressingToolbar = selection => {
48
+ if (!selection) {
49
+ return false;
50
+ }
51
+ const isCellSelection = !selection.empty && '$anchorCell' in selection;
52
+ return isSelectionToolbarSuppressedByUserIntent(getCurrentUserIntent === null || getCurrentUserIntent === void 0 ? void 0 : getCurrentUserIntent(), isCellSelection);
53
+ };
41
54
  const experience = new Experience(EXPERIENCE_ID.TOOLBAR_OPEN, {
42
55
  actionSubjectId: ACTION_SUBJECT_ID.SELECTION_TOOLBAR,
43
56
  dispatchAnalyticsEvent,
44
57
  checks: [new ExperienceCheckTimeout({
45
58
  durationMs: 1000,
46
59
  onTimeout: () => {
47
- var _editorView2;
48
- if (isBlockMenuWithinNode(getTarget())) {
60
+ var _editorView2, _editorView3;
61
+ if (isIntentFixEnabled && isCurrentUserIntentSuppressingToolbar((_editorView2 = editorView) === null || _editorView2 === void 0 ? void 0 : _editorView2.state.selection)) {
62
+ return {
63
+ status: 'abort',
64
+ reason: ABORT_REASON.USER_INTENT_SUPPRESSED
65
+ };
66
+ } else if (isBlockMenuWithinNode(getTarget())) {
49
67
  return {
50
68
  status: 'abort',
51
69
  reason: ABORT_REASON.BLOCK_MENU_OPENED
52
70
  };
53
- } else if (isSelectionWithoutTextContent((_editorView2 = editorView) === null || _editorView2 === void 0 ? void 0 : _editorView2.state.selection)) {
71
+ } else if (isSelectionWithoutTextContent((_editorView3 = editorView) === null || _editorView3 === void 0 ? void 0 : _editorView3.state.selection)) {
54
72
  return {
55
73
  status: 'abort',
56
74
  reason: ABORT_REASON.SELECTION_CLEARED
@@ -76,7 +94,7 @@ export const getSelectionToolbarOpenExperiencePlugin = ({
76
94
  })]
77
95
  });
78
96
  const shouldSkipExperienceStart = selection => {
79
- if (isSelectionWithoutTextContent(selection) || isSelectionWithinCodeBlock(selection)) {
97
+ if (isSelectionWithoutTextContent(selection) || isSelectionWithinCodeBlock(selection) || isIntentFixEnabled && isCurrentUserIntentSuppressingToolbar(selection)) {
80
98
  return true;
81
99
  }
82
100
  const target = getTarget();
@@ -108,17 +126,27 @@ export const getSelectionToolbarOpenExperiencePlugin = ({
108
126
  },
109
127
  props: {
110
128
  handleDOMEvents: {
111
- mousedown: (_view, e) => {
129
+ mousedown: (view, e) => {
112
130
  mouseDownPos = {
113
131
  x: e.clientX,
114
132
  y: e.clientY
115
133
  };
134
+ if (isIntentFixEnabled) {
135
+ mouseDownSelection = view.state.selection;
136
+ }
116
137
  },
117
138
  mouseup: (view, e) => {
118
- if (!mouseDownPos || shouldSkipExperienceStart(view.state.selection)) {
139
+ const initialMouseDownPos = mouseDownPos;
140
+ const selectionChanged = hasSelectionChanged(mouseDownSelection, view.state.selection);
141
+ if (isIntentFixEnabled) {
142
+ mouseDownPos = undefined;
143
+ mouseDownSelection = undefined;
144
+ }
145
+ if (!initialMouseDownPos || shouldSkipExperienceStart(view.state.selection)) {
119
146
  return;
120
147
  }
121
- if (e.clientX !== mouseDownPos.x || e.clientY !== mouseDownPos.y) {
148
+ const mouseCoordinatesChanged = e.clientX !== initialMouseDownPos.x || e.clientY !== initialMouseDownPos.y;
149
+ if (mouseCoordinatesChanged && (!isIntentFixEnabled || selectionChanged)) {
122
150
  experience.start({
123
151
  method: START_METHOD.MOUSE_UP
124
152
  });
@@ -132,11 +160,8 @@ export const getSelectionToolbarOpenExperiencePlugin = ({
132
160
  method: START_METHOD.MOUSE_UP
133
161
  });
134
162
  },
135
- keydown: (_view, {
136
- shiftKey,
137
- key
138
- }) => {
139
- shiftArrowKeyPressed = shiftKey && key.includes('Arrow') && !isSelectionToolbarWithinNode(getTarget());
163
+ keydown: (_view, event) => {
164
+ shiftArrowKeyPressed = (isIntentFixEnabled ? isPlainShiftArrowKey(event) : event.shiftKey && event.key.includes('Arrow')) && !isSelectionToolbarWithinNode(getTarget());
140
165
  },
141
166
  keyup: () => {
142
167
  shiftArrowKeyPressed = false;
@@ -260,6 +260,10 @@ export const toolbarPlugin = ({
260
260
  dispatchAnalyticsEvent: payload => {
261
261
  var _api$analytics, _api$analytics$action;
262
262
  return api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : (_api$analytics$action = _api$analytics.actions) === null || _api$analytics$action === void 0 ? void 0 : _api$analytics$action.fireAnalyticsEvent(payload);
263
+ },
264
+ getCurrentUserIntent: () => {
265
+ var _api$userIntent, _api$userIntent$share;
266
+ return api === null || api === void 0 ? void 0 : (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : (_api$userIntent$share = _api$userIntent.sharedState.currentState()) === null || _api$userIntent$share === void 0 ? void 0 : _api$userIntent$share.currentUserIntent;
263
267
  }
264
268
  })
265
269
  }] : [])];
@@ -19,6 +19,7 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
19
19
  import { SELECTION_TOOLBAR_LABEL } from '../consts';
20
20
  import { getKeyboardNavigationConfig } from './keyboard-config';
21
21
  import { getDomRefFromSelection } from './utils';
22
+ import { isSelectionToolbarSuppressedByUserIntent } from './visibility';
22
23
  const isToolbarComponent = component => {
23
24
  return component.type === 'toolbar' && component.key === 'inline-text-toolbar';
24
25
  };
@@ -93,7 +94,7 @@ export const SelectionToolbar = ({
93
94
  }
94
95
  if (!(isTextSelection || isCellSelection || isAllSelection) || currentUserIntent === 'dragging' || !shouldShowToolbar || currentUserIntent === 'blockMenuOpen' && editorExperiment('platform_editor_block_menu', true) ||
95
96
  // hide toolbar when user intent is not default, except when it's dragHandleSelected without cell selection
96
- currentUserIntent && currentUserIntent !== 'default' && !(currentUserIntent === 'dragHandleSelected' && !isCellSelection) || isSSR()) {
97
+ isSelectionToolbarSuppressedByUserIntent(currentUserIntent, isCellSelection) || isSSR()) {
97
98
  return null;
98
99
  }
99
100
  const toolbarContent = /*#__PURE__*/React.createElement(EditorToolbarProvider, {
@@ -0,0 +1,9 @@
1
+ export const isSelectionToolbarSuppressedByUserIntent = (currentUserIntent, isCellSelection) => Boolean(currentUserIntent && currentUserIntent !== 'default' && !(currentUserIntent === 'dragHandleSelected' && !isCellSelection));
2
+ export const isPlainShiftArrowKey = ({
3
+ shiftKey,
4
+ key,
5
+ metaKey,
6
+ ctrlKey,
7
+ altKey
8
+ }) => shiftKey && !metaKey && !ctrlKey && !altKey && key.includes('Arrow');
9
+ export const hasSelectionChanged = (mouseDownSelection, currentSelection) => Boolean(mouseDownSelection && !mouseDownSelection.eq(currentSelection));
@@ -3,6 +3,8 @@ import { ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
3
3
  import { containsPopupWithNestedElement, Experience, EXPERIENCE_ID, ExperienceCheckDomMutation, ExperienceCheckTimeout, getPopupContainerFromEditorView } from '@atlaskit/editor-common/experiences';
4
4
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
5
5
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
6
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
7
+ import { hasSelectionChanged, isPlainShiftArrowKey, isSelectionToolbarSuppressedByUserIntent } from '../../ui/SelectionToolbar/visibility';
6
8
  var pluginKey = new PluginKey('selectionToolbarOpenExperience');
7
9
  var START_METHOD = {
8
10
  MOUSE_UP: 'mouseUp',
@@ -11,7 +13,8 @@ var START_METHOD = {
11
13
  var ABORT_REASON = {
12
14
  SELECTION_CLEARED: 'selectionCleared',
13
15
  BLOCK_MENU_OPENED: 'blockMenuOpened',
14
- EDITOR_DESTROYED: 'editorDestroyed'
16
+ EDITOR_DESTROYED: 'editorDestroyed',
17
+ USER_INTENT_SUPPRESSED: 'userIntentSuppressed'
15
18
  };
16
19
  /**
17
20
  * This experience tracks when the selection toolbar is opened.
@@ -25,11 +28,14 @@ var ABORT_REASON = {
25
28
  */
26
29
  export var getSelectionToolbarOpenExperiencePlugin = function getSelectionToolbarOpenExperiencePlugin(_ref) {
27
30
  var refs = _ref.refs,
28
- dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent;
31
+ dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent,
32
+ getCurrentUserIntent = _ref.getCurrentUserIntent;
33
+ var isIntentFixEnabled = fg('platform_editor_toolbar_intent_fix');
29
34
  var editorView;
30
35
  var targetEl;
31
36
  var shiftArrowKeyPressed = false;
32
37
  var mouseDownPos;
38
+ var mouseDownSelection;
33
39
  var getTarget = function getTarget() {
34
40
  if (!targetEl) {
35
41
  var _editorView;
@@ -37,19 +43,31 @@ export var getSelectionToolbarOpenExperiencePlugin = function getSelectionToolba
37
43
  }
38
44
  return targetEl;
39
45
  };
46
+ var isCurrentUserIntentSuppressingToolbar = function isCurrentUserIntentSuppressingToolbar(selection) {
47
+ if (!selection) {
48
+ return false;
49
+ }
50
+ var isCellSelection = !selection.empty && '$anchorCell' in selection;
51
+ return isSelectionToolbarSuppressedByUserIntent(getCurrentUserIntent === null || getCurrentUserIntent === void 0 ? void 0 : getCurrentUserIntent(), isCellSelection);
52
+ };
40
53
  var experience = new Experience(EXPERIENCE_ID.TOOLBAR_OPEN, {
41
54
  actionSubjectId: ACTION_SUBJECT_ID.SELECTION_TOOLBAR,
42
55
  dispatchAnalyticsEvent: dispatchAnalyticsEvent,
43
56
  checks: [new ExperienceCheckTimeout({
44
57
  durationMs: 1000,
45
58
  onTimeout: function onTimeout() {
46
- var _editorView2;
47
- if (isBlockMenuWithinNode(getTarget())) {
59
+ var _editorView2, _editorView3;
60
+ if (isIntentFixEnabled && isCurrentUserIntentSuppressingToolbar((_editorView2 = editorView) === null || _editorView2 === void 0 ? void 0 : _editorView2.state.selection)) {
61
+ return {
62
+ status: 'abort',
63
+ reason: ABORT_REASON.USER_INTENT_SUPPRESSED
64
+ };
65
+ } else if (isBlockMenuWithinNode(getTarget())) {
48
66
  return {
49
67
  status: 'abort',
50
68
  reason: ABORT_REASON.BLOCK_MENU_OPENED
51
69
  };
52
- } else if (isSelectionWithoutTextContent((_editorView2 = editorView) === null || _editorView2 === void 0 ? void 0 : _editorView2.state.selection)) {
70
+ } else if (isSelectionWithoutTextContent((_editorView3 = editorView) === null || _editorView3 === void 0 ? void 0 : _editorView3.state.selection)) {
53
71
  return {
54
72
  status: 'abort',
55
73
  reason: ABORT_REASON.SELECTION_CLEARED
@@ -76,7 +94,7 @@ export var getSelectionToolbarOpenExperiencePlugin = function getSelectionToolba
76
94
  })]
77
95
  });
78
96
  var shouldSkipExperienceStart = function shouldSkipExperienceStart(selection) {
79
- if (isSelectionWithoutTextContent(selection) || isSelectionWithinCodeBlock(selection)) {
97
+ if (isSelectionWithoutTextContent(selection) || isSelectionWithinCodeBlock(selection) || isIntentFixEnabled && isCurrentUserIntentSuppressingToolbar(selection)) {
80
98
  return true;
81
99
  }
82
100
  var target = getTarget();
@@ -110,17 +128,27 @@ export var getSelectionToolbarOpenExperiencePlugin = function getSelectionToolba
110
128
  },
111
129
  props: {
112
130
  handleDOMEvents: {
113
- mousedown: function mousedown(_view, e) {
131
+ mousedown: function mousedown(view, e) {
114
132
  mouseDownPos = {
115
133
  x: e.clientX,
116
134
  y: e.clientY
117
135
  };
136
+ if (isIntentFixEnabled) {
137
+ mouseDownSelection = view.state.selection;
138
+ }
118
139
  },
119
140
  mouseup: function mouseup(view, e) {
120
- if (!mouseDownPos || shouldSkipExperienceStart(view.state.selection)) {
141
+ var initialMouseDownPos = mouseDownPos;
142
+ var selectionChanged = hasSelectionChanged(mouseDownSelection, view.state.selection);
143
+ if (isIntentFixEnabled) {
144
+ mouseDownPos = undefined;
145
+ mouseDownSelection = undefined;
146
+ }
147
+ if (!initialMouseDownPos || shouldSkipExperienceStart(view.state.selection)) {
121
148
  return;
122
149
  }
123
- if (e.clientX !== mouseDownPos.x || e.clientY !== mouseDownPos.y) {
150
+ var mouseCoordinatesChanged = e.clientX !== initialMouseDownPos.x || e.clientY !== initialMouseDownPos.y;
151
+ if (mouseCoordinatesChanged && (!isIntentFixEnabled || selectionChanged)) {
124
152
  experience.start({
125
153
  method: START_METHOD.MOUSE_UP
126
154
  });
@@ -134,10 +162,8 @@ export var getSelectionToolbarOpenExperiencePlugin = function getSelectionToolba
134
162
  method: START_METHOD.MOUSE_UP
135
163
  });
136
164
  },
137
- keydown: function keydown(_view, _ref3) {
138
- var shiftKey = _ref3.shiftKey,
139
- key = _ref3.key;
140
- shiftArrowKeyPressed = shiftKey && key.includes('Arrow') && !isSelectionToolbarWithinNode(getTarget());
165
+ keydown: function keydown(_view, event) {
166
+ shiftArrowKeyPressed = (isIntentFixEnabled ? isPlainShiftArrowKey(event) : event.shiftKey && event.key.includes('Arrow')) && !isSelectionToolbarWithinNode(getTarget());
141
167
  },
142
168
  keyup: function keyup() {
143
169
  shiftArrowKeyPressed = false;
@@ -156,9 +182,9 @@ export var getSelectionToolbarOpenExperiencePlugin = function getSelectionToolba
156
182
  }
157
183
  });
158
184
  };
159
- var isSelectionToolbarAddedInMutation = function isSelectionToolbarAddedInMutation(_ref4) {
160
- var type = _ref4.type,
161
- addedNodes = _ref4.addedNodes;
185
+ var isSelectionToolbarAddedInMutation = function isSelectionToolbarAddedInMutation(_ref3) {
186
+ var type = _ref3.type,
187
+ addedNodes = _ref3.addedNodes;
162
188
  return type === 'childList' && _toConsumableArray(addedNodes).some(isSelectionToolbarWithinNode);
163
189
  };
164
190
  var isSelectionToolbarWithinNode = function isSelectionToolbarWithinNode(node) {
@@ -262,6 +262,10 @@ export var toolbarPlugin = function toolbarPlugin(_ref) {
262
262
  dispatchAnalyticsEvent: function dispatchAnalyticsEvent(payload) {
263
263
  var _api$analytics;
264
264
  return api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 ? void 0 : _api$analytics.fireAnalyticsEvent(payload);
265
+ },
266
+ getCurrentUserIntent: function getCurrentUserIntent() {
267
+ var _api$userIntent;
268
+ return 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;
265
269
  }
266
270
  });
267
271
  }
@@ -19,6 +19,7 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
19
19
  import { SELECTION_TOOLBAR_LABEL } from '../consts';
20
20
  import { getKeyboardNavigationConfig } from './keyboard-config';
21
21
  import { getDomRefFromSelection } from './utils';
22
+ import { isSelectionToolbarSuppressedByUserIntent } from './visibility';
22
23
  var isToolbarComponent = function isToolbarComponent(component) {
23
24
  return component.type === 'toolbar' && component.key === 'inline-text-toolbar';
24
25
  };
@@ -92,7 +93,7 @@ export var SelectionToolbar = function SelectionToolbar(_ref) {
92
93
  }
93
94
  if (!(isTextSelection || isCellSelection || isAllSelection) || currentUserIntent === 'dragging' || !shouldShowToolbar || currentUserIntent === 'blockMenuOpen' && editorExperiment('platform_editor_block_menu', true) ||
94
95
  // hide toolbar when user intent is not default, except when it's dragHandleSelected without cell selection
95
- currentUserIntent && currentUserIntent !== 'default' && !(currentUserIntent === 'dragHandleSelected' && !isCellSelection) || isSSR()) {
96
+ isSelectionToolbarSuppressedByUserIntent(currentUserIntent, isCellSelection) || isSSR()) {
96
97
  return null;
97
98
  }
98
99
  var toolbarContent = /*#__PURE__*/React.createElement(EditorToolbarProvider, {
@@ -0,0 +1,14 @@
1
+ export var isSelectionToolbarSuppressedByUserIntent = function isSelectionToolbarSuppressedByUserIntent(currentUserIntent, isCellSelection) {
2
+ return Boolean(currentUserIntent && currentUserIntent !== 'default' && !(currentUserIntent === 'dragHandleSelected' && !isCellSelection));
3
+ };
4
+ export var isPlainShiftArrowKey = function isPlainShiftArrowKey(_ref) {
5
+ var shiftKey = _ref.shiftKey,
6
+ key = _ref.key,
7
+ metaKey = _ref.metaKey,
8
+ ctrlKey = _ref.ctrlKey,
9
+ altKey = _ref.altKey;
10
+ return shiftKey && !metaKey && !ctrlKey && !altKey && key.includes('Arrow');
11
+ };
12
+ export var hasSelectionChanged = function hasSelectionChanged(mouseDownSelection, currentSelection) {
13
+ return Boolean(mouseDownSelection && !mouseDownSelection.eq(currentSelection));
14
+ };
@@ -1,7 +1,9 @@
1
1
  import type { DispatchAnalyticsEvent } from '@atlaskit/editor-common/analytics';
2
2
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
+ import type { UserIntent } from '@atlaskit/editor-plugin-user-intent/types';
3
4
  type SelectionToolbarOpenExperienceOptions = {
4
5
  dispatchAnalyticsEvent: DispatchAnalyticsEvent;
6
+ getCurrentUserIntent?: () => UserIntent | undefined;
5
7
  refs: {
6
8
  popupsMountPoint?: HTMLElement;
7
9
  };
@@ -16,5 +18,5 @@ type SelectionToolbarOpenExperienceOptions = {
16
18
  *
17
19
  * @see https://hello.atlassian.net/wiki/spaces/EDITOR/pages/6262117789/Experience+tracking+Selection+toolbar+open
18
20
  */
19
- export declare const getSelectionToolbarOpenExperiencePlugin: ({ refs, dispatchAnalyticsEvent, }: SelectionToolbarOpenExperienceOptions) => SafePlugin<{}>;
21
+ export declare const getSelectionToolbarOpenExperiencePlugin: ({ refs, dispatchAnalyticsEvent, getCurrentUserIntent, }: SelectionToolbarOpenExperienceOptions) => SafePlugin<{}>;
20
22
  export {};
@@ -0,0 +1,5 @@
1
+ import type { UserIntent } from '@atlaskit/editor-plugin-user-intent/types';
2
+ import type { Selection } from '@atlaskit/editor-prosemirror/state';
3
+ export declare const isSelectionToolbarSuppressedByUserIntent: (currentUserIntent: UserIntent | undefined, isCellSelection: boolean) => boolean;
4
+ export declare const isPlainShiftArrowKey: ({ shiftKey, key, metaKey, ctrlKey, altKey, }: Pick<KeyboardEvent, 'shiftKey' | 'key' | 'metaKey' | 'ctrlKey' | 'altKey'>) => boolean;
5
+ export declare const hasSelectionChanged: (mouseDownSelection: Selection | undefined, currentSelection: Selection) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-toolbar",
3
- "version": "12.0.11",
3
+ "version": "12.0.12",
4
4
  "description": "Toolbar plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -33,16 +33,19 @@
33
33
  "@atlaskit/editor-toolbar-model": "^1.2.0",
34
34
  "@atlaskit/platform-feature-experiments": "^0.3.0",
35
35
  "@atlaskit/platform-feature-flags": "^2.1.0",
36
- "@atlaskit/tmp-editor-statsig": "^157.0.0",
36
+ "@atlaskit/tmp-editor-statsig": "^158.0.0",
37
37
  "@babel/runtime": "^7.0.0",
38
38
  "bind-event-listener": "^3.0.0"
39
39
  },
40
40
  "peerDependencies": {
41
- "@atlaskit/editor-common": "^119.13.0",
41
+ "@atlaskit/editor-common": "^119.16.0",
42
42
  "react": "^18.2.0 || ^19.2.0",
43
43
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
44
44
  },
45
45
  "platform-feature-flags": {
46
+ "platform_editor_toolbar_intent_fix": {
47
+ "type": "boolean"
48
+ },
46
49
  "platform_editor_blocks_patch_7": {
47
50
  "type": "boolean",
48
51
  "referenceOnly": true