@atlaskit/editor-plugin-block-controls 7.18.0 → 7.18.2

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,19 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 7.18.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`275b01c2a180f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/275b01c2a180f) -
8
+ EDITOR-3911 fix key handling while preserving selection
9
+
10
+ ## 7.18.1
11
+
12
+ ### Patch Changes
13
+
14
+ - [`7b47062997f9b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/7b47062997f9b) -
15
+ EDITOR-3793 Stop preserving selection on click into editor
16
+
3
17
  ## 7.18.0
4
18
 
5
19
  ### Minor Changes
@@ -8,6 +8,7 @@ exports.createSelectionPreservationPlugin = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _monitoring = require("@atlaskit/editor-common/monitoring");
10
10
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
11
+ var _styles = require("@atlaskit/editor-common/styles");
11
12
  var _selection = require("../utils/selection");
12
13
  var _editorCommands = require("./editor-commands");
13
14
  var _pluginKey = require("./plugin-key");
@@ -41,6 +42,8 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
41
42
  * is open (editor becomes non-interactive), during drag-and-drop operations (user is mid-drag), or
42
43
  * when modal dialogs are active. In these states, any selection changes are from ProseMirror's
43
44
  * internal behavior (not user input) and should be prevented. Do not use during normal editing.
45
+ *
46
+ * https://hello.atlassian.net/wiki/spaces/egcuc/pages/6170822503/Block+Menu+Solution+for+multi-select+and+selection+preservation
44
47
  */
45
48
  var createSelectionPreservationPlugin = exports.createSelectionPreservationPlugin = function createSelectionPreservationPlugin(api) {
46
49
  return function () {
@@ -56,7 +59,7 @@ var createSelectionPreservationPlugin = exports.createSelectionPreservationPlugi
56
59
  var meta = (0, _utils.getSelectionPreservationMeta)(tr);
57
60
  var newState = _objectSpread({}, pluginState);
58
61
  if ((meta === null || meta === void 0 ? void 0 : meta.type) === 'startPreserving') {
59
- newState.preservedSelection = tr.selection;
62
+ newState.preservedSelection = (0, _selection.mapPreservedSelection)(tr.selection, tr);
60
63
  } else if ((meta === null || meta === void 0 ? void 0 : meta.type) === 'stopPreserving') {
61
64
  newState.preservedSelection = undefined;
62
65
  }
@@ -94,11 +97,34 @@ var createSelectionPreservationPlugin = exports.createSelectionPreservationPlugi
94
97
  return null;
95
98
  },
96
99
  props: {
97
- handleKeyDown: function handleKeyDown(view, event) {
98
- var _api$userIntent;
100
+ handleClick: function handleClick(view, pos, event) {
99
101
  var _ref = _pluginKey.selectionPreservationPluginKey.getState(view.state) || {},
100
102
  preservedSelection = _ref.preservedSelection;
101
103
 
104
+ // If there is no current preserved selection, do nothing
105
+ if (!preservedSelection) {
106
+ return false;
107
+ }
108
+ var clickedDragHandle = event.target instanceof HTMLElement && event.target.closest(_styles.DRAG_HANDLE_SELECTOR);
109
+
110
+ // When clicking a drag handle we continue preserving the selection
111
+ if (!clickedDragHandle) {
112
+ return false;
113
+ }
114
+
115
+ // Otherwise clicking anywhere else in the editor stops preserving the selection
116
+ var tr = view.state.tr;
117
+ (0, _editorCommands.stopPreservingSelection)({
118
+ tr: tr
119
+ });
120
+ view.dispatch(tr);
121
+ return false;
122
+ },
123
+ handleKeyDown: function handleKeyDown(view, event) {
124
+ var _api$userIntent;
125
+ var _ref2 = _pluginKey.selectionPreservationPluginKey.getState(view.state) || {},
126
+ preservedSelection = _ref2.preservedSelection;
127
+
102
128
  // If there is no current preserved selection, do nothing
103
129
  if (!preservedSelection) {
104
130
  return false;
@@ -111,15 +137,18 @@ var createSelectionPreservationPlugin = exports.createSelectionPreservationPlugi
111
137
  }
112
138
  var blockMenuOpen = (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';
113
139
 
114
- // When block menu isn't open and user presses any key, stop preserving selection
115
- if (!blockMenuOpen) {
116
- var tr = view.state.tr;
117
- (0, _editorCommands.stopPreservingSelection)({
118
- tr: tr
119
- });
120
- view.dispatch(tr);
121
- return false;
140
+ // When block menu is open, prevent all key events to avoid changing selection or editing content
141
+ if (blockMenuOpen) {
142
+ return true;
122
143
  }
144
+
145
+ // When block menu isn't open and user presses any key, stop preserving selection
146
+ var tr = view.state.tr;
147
+ (0, _editorCommands.stopPreservingSelection)({
148
+ tr: tr
149
+ });
150
+ view.dispatch(tr);
151
+ return false;
123
152
  }
124
153
  }
125
154
  });
@@ -97,19 +97,22 @@ var mapPreservedSelection = exports.mapPreservedSelection = function mapPreserve
97
97
  var to = mapping.map(selection.to);
98
98
  var isSelectionEmpty = from === to;
99
99
  var wasSelectionEmpty = selection.from === selection.to;
100
- if (isSelectionEmpty) {
101
- if (!wasSelectionEmpty) {
102
- // If selection has become empty i.e. content has been deleted, stop preserving
103
- return undefined;
104
- }
105
- // When preserving a cursor selection, just map the position without expanding
106
- return new _state.TextSelection(tr.doc.resolve(from));
100
+ if (isSelectionEmpty && !wasSelectionEmpty) {
101
+ // If selection has become empty i.e. content has been deleted, stop preserving
102
+ return undefined;
107
103
  }
108
-
109
104
  // expand the text selection range to block boundaries, so as document changes occur the
110
105
  // selection always includes whole nodes
111
106
  var expanded = (0, _selection.expandToBlockRange)(tr.doc.resolve(from), tr.doc.resolve(to));
112
107
 
108
+ // If after expanding the selection it is still empty, return a single cursor selection at 'from'
109
+ var nodeAfter = expanded.$from.nodeAfter;
110
+ var nodeBefore = expanded.$to.nodeBefore;
111
+ var expandedSelectionEmpty = nodeAfter === nodeBefore && (nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.content.size) === 0;
112
+ if (isSelectionEmpty && expandedSelectionEmpty) {
113
+ return _state.TextSelection.create(tr.doc, from);
114
+ }
115
+
113
116
  // collapse the expanded range to a valid selection range
114
117
  var _collapseToSelectionR = (0, _getSelection.collapseToSelectionRange)(expanded.$from, expanded.$to),
115
118
  $from = _collapseToSelectionR.$from,
@@ -1,5 +1,6 @@
1
1
  import { logException } from '@atlaskit/editor-common/monitoring';
2
2
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
+ import { DRAG_HANDLE_SELECTOR } from '@atlaskit/editor-common/styles';
3
4
  import { mapPreservedSelection } from '../utils/selection';
4
5
  import { stopPreservingSelection } from './editor-commands';
5
6
  import { selectionPreservationPluginKey } from './plugin-key';
@@ -32,6 +33,8 @@ import { getSelectionPreservationMeta, hasUserSelectionChange } from './utils';
32
33
  * is open (editor becomes non-interactive), during drag-and-drop operations (user is mid-drag), or
33
34
  * when modal dialogs are active. In these states, any selection changes are from ProseMirror's
34
35
  * internal behavior (not user input) and should be prevented. Do not use during normal editing.
36
+ *
37
+ * https://hello.atlassian.net/wiki/spaces/egcuc/pages/6170822503/Block+Menu+Solution+for+multi-select+and+selection+preservation
35
38
  */
36
39
  export const createSelectionPreservationPlugin = api => () => {
37
40
  return new SafePlugin({
@@ -48,7 +51,7 @@ export const createSelectionPreservationPlugin = api => () => {
48
51
  ...pluginState
49
52
  };
50
53
  if ((meta === null || meta === void 0 ? void 0 : meta.type) === 'startPreserving') {
51
- newState.preservedSelection = tr.selection;
54
+ newState.preservedSelection = mapPreservedSelection(tr.selection, tr);
52
55
  } else if ((meta === null || meta === void 0 ? void 0 : meta.type) === 'stopPreserving') {
53
56
  newState.preservedSelection = undefined;
54
57
  }
@@ -86,6 +89,30 @@ export const createSelectionPreservationPlugin = api => () => {
86
89
  return null;
87
90
  },
88
91
  props: {
92
+ handleClick: (view, pos, event) => {
93
+ const {
94
+ preservedSelection
95
+ } = selectionPreservationPluginKey.getState(view.state) || {};
96
+
97
+ // If there is no current preserved selection, do nothing
98
+ if (!preservedSelection) {
99
+ return false;
100
+ }
101
+ const clickedDragHandle = event.target instanceof HTMLElement && event.target.closest(DRAG_HANDLE_SELECTOR);
102
+
103
+ // When clicking a drag handle we continue preserving the selection
104
+ if (!clickedDragHandle) {
105
+ return false;
106
+ }
107
+
108
+ // Otherwise clicking anywhere else in the editor stops preserving the selection
109
+ const tr = view.state.tr;
110
+ stopPreservingSelection({
111
+ tr
112
+ });
113
+ view.dispatch(tr);
114
+ return false;
115
+ },
89
116
  handleKeyDown: (view, event) => {
90
117
  var _api$userIntent, _api$userIntent$share;
91
118
  const {
@@ -104,15 +131,18 @@ export const createSelectionPreservationPlugin = api => () => {
104
131
  }
105
132
  const blockMenuOpen = (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) === 'blockMenuOpen';
106
133
 
107
- // When block menu isn't open and user presses any key, stop preserving selection
108
- if (!blockMenuOpen) {
109
- const tr = view.state.tr;
110
- stopPreservingSelection({
111
- tr
112
- });
113
- view.dispatch(tr);
114
- return false;
134
+ // When block menu is open, prevent all key events to avoid changing selection or editing content
135
+ if (blockMenuOpen) {
136
+ return true;
115
137
  }
138
+
139
+ // When block menu isn't open and user presses any key, stop preserving selection
140
+ const tr = view.state.tr;
141
+ stopPreservingSelection({
142
+ tr
143
+ });
144
+ view.dispatch(tr);
145
+ return false;
116
146
  }
117
147
  }
118
148
  });
@@ -93,19 +93,22 @@ export const mapPreservedSelection = (selection, tr) => {
93
93
  const to = mapping.map(selection.to);
94
94
  const isSelectionEmpty = from === to;
95
95
  const wasSelectionEmpty = selection.from === selection.to;
96
- if (isSelectionEmpty) {
97
- if (!wasSelectionEmpty) {
98
- // If selection has become empty i.e. content has been deleted, stop preserving
99
- return undefined;
100
- }
101
- // When preserving a cursor selection, just map the position without expanding
102
- return new TextSelection(tr.doc.resolve(from));
96
+ if (isSelectionEmpty && !wasSelectionEmpty) {
97
+ // If selection has become empty i.e. content has been deleted, stop preserving
98
+ return undefined;
103
99
  }
104
-
105
100
  // expand the text selection range to block boundaries, so as document changes occur the
106
101
  // selection always includes whole nodes
107
102
  const expanded = expandToBlockRange(tr.doc.resolve(from), tr.doc.resolve(to));
108
103
 
104
+ // If after expanding the selection it is still empty, return a single cursor selection at 'from'
105
+ const nodeAfter = expanded.$from.nodeAfter;
106
+ const nodeBefore = expanded.$to.nodeBefore;
107
+ const expandedSelectionEmpty = nodeAfter === nodeBefore && (nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.content.size) === 0;
108
+ if (isSelectionEmpty && expandedSelectionEmpty) {
109
+ return TextSelection.create(tr.doc, from);
110
+ }
111
+
109
112
  // collapse the expanded range to a valid selection range
110
113
  const {
111
114
  $from,
@@ -3,6 +3,7 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
3
3
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
4
  import { logException } from '@atlaskit/editor-common/monitoring';
5
5
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
6
+ import { DRAG_HANDLE_SELECTOR } from '@atlaskit/editor-common/styles';
6
7
  import { mapPreservedSelection } from '../utils/selection';
7
8
  import { stopPreservingSelection } from './editor-commands';
8
9
  import { selectionPreservationPluginKey } from './plugin-key';
@@ -35,6 +36,8 @@ import { getSelectionPreservationMeta, hasUserSelectionChange } from './utils';
35
36
  * is open (editor becomes non-interactive), during drag-and-drop operations (user is mid-drag), or
36
37
  * when modal dialogs are active. In these states, any selection changes are from ProseMirror's
37
38
  * internal behavior (not user input) and should be prevented. Do not use during normal editing.
39
+ *
40
+ * https://hello.atlassian.net/wiki/spaces/egcuc/pages/6170822503/Block+Menu+Solution+for+multi-select+and+selection+preservation
38
41
  */
39
42
  export var createSelectionPreservationPlugin = function createSelectionPreservationPlugin(api) {
40
43
  return function () {
@@ -50,7 +53,7 @@ export var createSelectionPreservationPlugin = function createSelectionPreservat
50
53
  var meta = getSelectionPreservationMeta(tr);
51
54
  var newState = _objectSpread({}, pluginState);
52
55
  if ((meta === null || meta === void 0 ? void 0 : meta.type) === 'startPreserving') {
53
- newState.preservedSelection = tr.selection;
56
+ newState.preservedSelection = mapPreservedSelection(tr.selection, tr);
54
57
  } else if ((meta === null || meta === void 0 ? void 0 : meta.type) === 'stopPreserving') {
55
58
  newState.preservedSelection = undefined;
56
59
  }
@@ -88,11 +91,34 @@ export var createSelectionPreservationPlugin = function createSelectionPreservat
88
91
  return null;
89
92
  },
90
93
  props: {
91
- handleKeyDown: function handleKeyDown(view, event) {
92
- var _api$userIntent;
94
+ handleClick: function handleClick(view, pos, event) {
93
95
  var _ref = selectionPreservationPluginKey.getState(view.state) || {},
94
96
  preservedSelection = _ref.preservedSelection;
95
97
 
98
+ // If there is no current preserved selection, do nothing
99
+ if (!preservedSelection) {
100
+ return false;
101
+ }
102
+ var clickedDragHandle = event.target instanceof HTMLElement && event.target.closest(DRAG_HANDLE_SELECTOR);
103
+
104
+ // When clicking a drag handle we continue preserving the selection
105
+ if (!clickedDragHandle) {
106
+ return false;
107
+ }
108
+
109
+ // Otherwise clicking anywhere else in the editor stops preserving the selection
110
+ var tr = view.state.tr;
111
+ stopPreservingSelection({
112
+ tr: tr
113
+ });
114
+ view.dispatch(tr);
115
+ return false;
116
+ },
117
+ handleKeyDown: function handleKeyDown(view, event) {
118
+ var _api$userIntent;
119
+ var _ref2 = selectionPreservationPluginKey.getState(view.state) || {},
120
+ preservedSelection = _ref2.preservedSelection;
121
+
96
122
  // If there is no current preserved selection, do nothing
97
123
  if (!preservedSelection) {
98
124
  return false;
@@ -105,15 +131,18 @@ export var createSelectionPreservationPlugin = function createSelectionPreservat
105
131
  }
106
132
  var blockMenuOpen = (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';
107
133
 
108
- // When block menu isn't open and user presses any key, stop preserving selection
109
- if (!blockMenuOpen) {
110
- var tr = view.state.tr;
111
- stopPreservingSelection({
112
- tr: tr
113
- });
114
- view.dispatch(tr);
115
- return false;
134
+ // When block menu is open, prevent all key events to avoid changing selection or editing content
135
+ if (blockMenuOpen) {
136
+ return true;
116
137
  }
138
+
139
+ // When block menu isn't open and user presses any key, stop preserving selection
140
+ var tr = view.state.tr;
141
+ stopPreservingSelection({
142
+ tr: tr
143
+ });
144
+ view.dispatch(tr);
145
+ return false;
117
146
  }
118
147
  }
119
148
  });
@@ -91,19 +91,22 @@ export var mapPreservedSelection = function mapPreservedSelection(selection, tr)
91
91
  var to = mapping.map(selection.to);
92
92
  var isSelectionEmpty = from === to;
93
93
  var wasSelectionEmpty = selection.from === selection.to;
94
- if (isSelectionEmpty) {
95
- if (!wasSelectionEmpty) {
96
- // If selection has become empty i.e. content has been deleted, stop preserving
97
- return undefined;
98
- }
99
- // When preserving a cursor selection, just map the position without expanding
100
- return new TextSelection(tr.doc.resolve(from));
94
+ if (isSelectionEmpty && !wasSelectionEmpty) {
95
+ // If selection has become empty i.e. content has been deleted, stop preserving
96
+ return undefined;
101
97
  }
102
-
103
98
  // expand the text selection range to block boundaries, so as document changes occur the
104
99
  // selection always includes whole nodes
105
100
  var expanded = expandToBlockRange(tr.doc.resolve(from), tr.doc.resolve(to));
106
101
 
102
+ // If after expanding the selection it is still empty, return a single cursor selection at 'from'
103
+ var nodeAfter = expanded.$from.nodeAfter;
104
+ var nodeBefore = expanded.$to.nodeBefore;
105
+ var expandedSelectionEmpty = nodeAfter === nodeBefore && (nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.content.size) === 0;
106
+ if (isSelectionEmpty && expandedSelectionEmpty) {
107
+ return TextSelection.create(tr.doc, from);
108
+ }
109
+
107
110
  // collapse the expanded range to a valid selection range
108
111
  var _collapseToSelectionR = collapseToSelectionRange(expanded.$from, expanded.$to),
109
112
  $from = _collapseToSelectionR.$from,
@@ -29,5 +29,7 @@ import type { SelectionPreservationPluginState } from './types';
29
29
  * is open (editor becomes non-interactive), during drag-and-drop operations (user is mid-drag), or
30
30
  * when modal dialogs are active. In these states, any selection changes are from ProseMirror's
31
31
  * internal behavior (not user input) and should be prevented. Do not use during normal editing.
32
+ *
33
+ * https://hello.atlassian.net/wiki/spaces/egcuc/pages/6170822503/Block+Menu+Solution+for+multi-select+and+selection+preservation
32
34
  */
33
35
  export declare const createSelectionPreservationPlugin: (api: ExtractInjectionAPI<BlockControlsPlugin> | undefined) => () => SafePlugin<SelectionPreservationPluginState>;
@@ -29,5 +29,7 @@ import type { SelectionPreservationPluginState } from './types';
29
29
  * is open (editor becomes non-interactive), during drag-and-drop operations (user is mid-drag), or
30
30
  * when modal dialogs are active. In these states, any selection changes are from ProseMirror's
31
31
  * internal behavior (not user input) and should be prevented. Do not use during normal editing.
32
+ *
33
+ * https://hello.atlassian.net/wiki/spaces/egcuc/pages/6170822503/Block+Menu+Solution+for+multi-select+and+selection+preservation
32
34
  */
33
35
  export declare const createSelectionPreservationPlugin: (api: ExtractInjectionAPI<BlockControlsPlugin> | undefined) => () => SafePlugin<SelectionPreservationPluginState>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-controls",
3
- "version": "7.18.0",
3
+ "version": "7.18.2",
4
4
  "description": "Block controls plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",