@atlaskit/editor-plugin-block-controls 8.0.14 → 8.0.15

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,13 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 8.0.15
4
+
5
+ ### Patch Changes
6
+
7
+ - [`131735fb6ad06`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/131735fb6ad06) -
8
+ [ux] EDITOR-4281 Expand preserved selection edge case
9
+ - Updated dependencies
10
+
3
11
  ## 8.0.14
4
12
 
5
13
  ### Patch Changes
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.mapPreservedSelection = exports.getSelectedSlicePosition = exports.getMultiSelectionIfPosInside = exports.expandSelectionHeadToNodeAtPos = exports.createPreservedSelection = exports.alignAnchorHeadInDirectionOfPos = void 0;
6
+ exports.mapPreservedSelection = exports.getSelectedSlicePosition = exports.getMultiSelectionIfPosInside = exports.expandSelectionHeadToNodeAtPos = exports.createPreservedSelection = exports.alignAnchorHeadInDirectionOfPos = exports.adjustSelectionBoundsForEdgePositions = void 0;
7
7
  var _selection = require("@atlaskit/editor-common/selection");
8
8
  var _state = require("@atlaskit/editor-prosemirror/state");
9
9
  var _utils = require("@atlaskit/editor-tables/utils");
@@ -103,7 +103,58 @@ var mapPreservedSelection = exports.mapPreservedSelection = function mapPreserve
103
103
  }
104
104
  return createPreservedSelection(tr.doc.resolve(from), tr.doc.resolve(to));
105
105
  };
106
+ var isInsideEmptyTextblock = function isInsideEmptyTextblock($pos) {
107
+ return $pos.parent.isTextblock && $pos.parent.content.size === 0;
108
+ };
109
+ var isAtEndOfParent = function isAtEndOfParent($pos) {
110
+ return $pos.parentOffset === $pos.parent.content.size;
111
+ };
112
+ var isAtStartOfParent = function isAtStartOfParent($pos) {
113
+ return $pos.parentOffset === 0;
114
+ };
106
115
 
116
+ /**
117
+ * Adjust selection bounds to exclude nodes where the selection only touches
118
+ * the edge position without selecting any content.
119
+ *
120
+ * Exception: Don't adjust if the selection is inside an empty textblock,
121
+ * as we want to include empty paragraphs in block operations.
122
+ *
123
+ * @param $from The resolved position of the start of the selection
124
+ * @param $to The resolved position of the end of the selection
125
+ * @returns Adjusted $from and $to positions
126
+ */
127
+ var adjustSelectionBoundsForEdgePositions = exports.adjustSelectionBoundsForEdgePositions = function adjustSelectionBoundsForEdgePositions($from, $to) {
128
+ var doc = $from.doc;
129
+
130
+ // Walk $from forward while at end of ancestors
131
+ var adjustedFrom = $from;
132
+ if (!isInsideEmptyTextblock($from)) {
133
+ while (adjustedFrom.depth > 0 && isAtEndOfParent(adjustedFrom)) {
134
+ var nextPos = adjustedFrom.after();
135
+ if (nextPos > doc.content.size || nextPos === adjustedFrom.pos) {
136
+ break;
137
+ }
138
+ adjustedFrom = doc.resolve(nextPos);
139
+ }
140
+ }
141
+
142
+ // Walk $to backward while at start of ancestors
143
+ var adjustedTo = $to;
144
+ if (!isInsideEmptyTextblock($to)) {
145
+ while (adjustedTo.depth > 0 && isAtStartOfParent(adjustedTo)) {
146
+ var prevPos = adjustedTo.before();
147
+ if (prevPos < 0 || prevPos === adjustedTo.pos) {
148
+ break;
149
+ }
150
+ adjustedTo = doc.resolve(prevPos);
151
+ }
152
+ }
153
+ return {
154
+ $from: adjustedFrom,
155
+ $to: adjustedTo
156
+ };
157
+ };
107
158
  /**
108
159
  * Creates a preserved selection which is expanded to block boundaries.
109
160
  *
@@ -119,9 +170,17 @@ var mapPreservedSelection = exports.mapPreservedSelection = function mapPreserve
119
170
  var createPreservedSelection = exports.createPreservedSelection = function createPreservedSelection($from, $to) {
120
171
  var _doc$nodeAt;
121
172
  var doc = $from.doc;
173
+ var isCollapsed = $from.pos === $to.pos;
174
+ var adjusted = isCollapsed ? {
175
+ $from: $from,
176
+ $to: $to
177
+ } : adjustSelectionBoundsForEdgePositions($from, $to);
178
+ if (!isCollapsed && adjusted.$from.pos >= adjusted.$to.pos) {
179
+ return undefined;
180
+ }
122
181
 
123
182
  // expand the selection range to block boundaries, so selection always includes whole nodes
124
- var expanded = (0, _selection.expandToBlockRange)($from, $to);
183
+ var expanded = (0, _selection.expandToBlockRange)(adjusted.$from, adjusted.$to);
125
184
 
126
185
  // stop preserving if selection becomes invalid
127
186
  if (expanded.$from.pos < 0 || expanded.$to.pos > doc.content.size || expanded.$from.pos >= expanded.$to.pos) {
@@ -358,7 +358,11 @@ var getExpandedSelectionRange = function getExpandedSelectionRange(_ref) {
358
358
  var selectUp = resolvedStartPos.pos < selection.from;
359
359
  var $from = isShiftPressed && selectUp ? resolvedStartPos : selection.$from;
360
360
  var $to = isShiftPressed && !selectUp ? doc.resolve(resolvedStartPos.pos + 1) : selection.$to;
361
- return (0, _selection.expandToBlockRange)($from, $to);
361
+ var adjusted = isShiftPressed ? {
362
+ $from: $from,
363
+ $to: $to
364
+ } : (0, _selection2.adjustSelectionBoundsForEdgePositions)($from, $to);
365
+ return (0, _selection.expandToBlockRange)(adjusted.$from, adjusted.$to);
362
366
  };
363
367
  /**
364
368
  * Updates the transaction with preserved selection logic.
@@ -99,7 +99,54 @@ export const mapPreservedSelection = (selection, tr) => {
99
99
  }
100
100
  return createPreservedSelection(tr.doc.resolve(from), tr.doc.resolve(to));
101
101
  };
102
+ const isInsideEmptyTextblock = $pos => $pos.parent.isTextblock && $pos.parent.content.size === 0;
103
+ const isAtEndOfParent = $pos => $pos.parentOffset === $pos.parent.content.size;
104
+ const isAtStartOfParent = $pos => $pos.parentOffset === 0;
102
105
 
106
+ /**
107
+ * Adjust selection bounds to exclude nodes where the selection only touches
108
+ * the edge position without selecting any content.
109
+ *
110
+ * Exception: Don't adjust if the selection is inside an empty textblock,
111
+ * as we want to include empty paragraphs in block operations.
112
+ *
113
+ * @param $from The resolved position of the start of the selection
114
+ * @param $to The resolved position of the end of the selection
115
+ * @returns Adjusted $from and $to positions
116
+ */
117
+ export const adjustSelectionBoundsForEdgePositions = ($from, $to) => {
118
+ const {
119
+ doc
120
+ } = $from;
121
+
122
+ // Walk $from forward while at end of ancestors
123
+ let adjustedFrom = $from;
124
+ if (!isInsideEmptyTextblock($from)) {
125
+ while (adjustedFrom.depth > 0 && isAtEndOfParent(adjustedFrom)) {
126
+ const nextPos = adjustedFrom.after();
127
+ if (nextPos > doc.content.size || nextPos === adjustedFrom.pos) {
128
+ break;
129
+ }
130
+ adjustedFrom = doc.resolve(nextPos);
131
+ }
132
+ }
133
+
134
+ // Walk $to backward while at start of ancestors
135
+ let adjustedTo = $to;
136
+ if (!isInsideEmptyTextblock($to)) {
137
+ while (adjustedTo.depth > 0 && isAtStartOfParent(adjustedTo)) {
138
+ const prevPos = adjustedTo.before();
139
+ if (prevPos < 0 || prevPos === adjustedTo.pos) {
140
+ break;
141
+ }
142
+ adjustedTo = doc.resolve(prevPos);
143
+ }
144
+ }
145
+ return {
146
+ $from: adjustedFrom,
147
+ $to: adjustedTo
148
+ };
149
+ };
103
150
  /**
104
151
  * Creates a preserved selection which is expanded to block boundaries.
105
152
  *
@@ -117,9 +164,17 @@ export const createPreservedSelection = ($from, $to) => {
117
164
  const {
118
165
  doc
119
166
  } = $from;
167
+ const isCollapsed = $from.pos === $to.pos;
168
+ const adjusted = isCollapsed ? {
169
+ $from,
170
+ $to
171
+ } : adjustSelectionBoundsForEdgePositions($from, $to);
172
+ if (!isCollapsed && adjusted.$from.pos >= adjusted.$to.pos) {
173
+ return undefined;
174
+ }
120
175
 
121
176
  // expand the selection range to block boundaries, so selection always includes whole nodes
122
- const expanded = expandToBlockRange($from, $to);
177
+ const expanded = expandToBlockRange(adjusted.$from, adjusted.$to);
123
178
 
124
179
  // stop preserving if selection becomes invalid
125
180
  if (expanded.$from.pos < 0 || expanded.$to.pos > doc.content.size || expanded.$from.pos >= expanded.$to.pos) {
@@ -37,7 +37,7 @@ import { selectionPreservationPluginKey } from '../pm-plugins/selection-preserva
37
37
  import { getMultiSelectAnalyticsAttributes } from '../pm-plugins/utils/analytics';
38
38
  import { getControlBottomCSSValue, getControlHeightCSSValue, getLeftPosition, getNodeHeight, getTopPosition, shouldBeSticky, shouldMaskNodeControls } from '../pm-plugins/utils/drag-handle-positions';
39
39
  import { isHandleCorrelatedToSelection, selectNode } from '../pm-plugins/utils/getSelection';
40
- import { alignAnchorHeadInDirectionOfPos, expandSelectionHeadToNodeAtPos } from '../pm-plugins/utils/selection';
40
+ import { adjustSelectionBoundsForEdgePositions, alignAnchorHeadInDirectionOfPos, expandSelectionHeadToNodeAtPos } from '../pm-plugins/utils/selection';
41
41
  import { DRAG_HANDLE_BORDER_RADIUS, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH, DRAG_HANDLE_ZINDEX, dragHandleGap, nodeMargins, spacingBetweenNodesForPreview, STICKY_CONTROLS_TOP_MARGIN, STICKY_CONTROLS_TOP_MARGIN_FOR_STICKY_HEADER, topPositionAdjustment } from './consts';
42
42
  import { dragPreview } from './drag-preview';
43
43
  import { refreshAnchorName } from './utils/anchor-name';
@@ -354,7 +354,11 @@ const getExpandedSelectionRange = ({
354
354
  const selectUp = resolvedStartPos.pos < selection.from;
355
355
  const $from = isShiftPressed && selectUp ? resolvedStartPos : selection.$from;
356
356
  const $to = isShiftPressed && !selectUp ? doc.resolve(resolvedStartPos.pos + 1) : selection.$to;
357
- return expandToBlockRange($from, $to);
357
+ const adjusted = isShiftPressed ? {
358
+ $from,
359
+ $to
360
+ } : adjustSelectionBoundsForEdgePositions($from, $to);
361
+ return expandToBlockRange(adjusted.$from, adjusted.$to);
358
362
  };
359
363
  /**
360
364
  * Updates the transaction with preserved selection logic.
@@ -97,7 +97,58 @@ export var mapPreservedSelection = function mapPreservedSelection(selection, tr)
97
97
  }
98
98
  return createPreservedSelection(tr.doc.resolve(from), tr.doc.resolve(to));
99
99
  };
100
+ var isInsideEmptyTextblock = function isInsideEmptyTextblock($pos) {
101
+ return $pos.parent.isTextblock && $pos.parent.content.size === 0;
102
+ };
103
+ var isAtEndOfParent = function isAtEndOfParent($pos) {
104
+ return $pos.parentOffset === $pos.parent.content.size;
105
+ };
106
+ var isAtStartOfParent = function isAtStartOfParent($pos) {
107
+ return $pos.parentOffset === 0;
108
+ };
100
109
 
110
+ /**
111
+ * Adjust selection bounds to exclude nodes where the selection only touches
112
+ * the edge position without selecting any content.
113
+ *
114
+ * Exception: Don't adjust if the selection is inside an empty textblock,
115
+ * as we want to include empty paragraphs in block operations.
116
+ *
117
+ * @param $from The resolved position of the start of the selection
118
+ * @param $to The resolved position of the end of the selection
119
+ * @returns Adjusted $from and $to positions
120
+ */
121
+ export var adjustSelectionBoundsForEdgePositions = function adjustSelectionBoundsForEdgePositions($from, $to) {
122
+ var doc = $from.doc;
123
+
124
+ // Walk $from forward while at end of ancestors
125
+ var adjustedFrom = $from;
126
+ if (!isInsideEmptyTextblock($from)) {
127
+ while (adjustedFrom.depth > 0 && isAtEndOfParent(adjustedFrom)) {
128
+ var nextPos = adjustedFrom.after();
129
+ if (nextPos > doc.content.size || nextPos === adjustedFrom.pos) {
130
+ break;
131
+ }
132
+ adjustedFrom = doc.resolve(nextPos);
133
+ }
134
+ }
135
+
136
+ // Walk $to backward while at start of ancestors
137
+ var adjustedTo = $to;
138
+ if (!isInsideEmptyTextblock($to)) {
139
+ while (adjustedTo.depth > 0 && isAtStartOfParent(adjustedTo)) {
140
+ var prevPos = adjustedTo.before();
141
+ if (prevPos < 0 || prevPos === adjustedTo.pos) {
142
+ break;
143
+ }
144
+ adjustedTo = doc.resolve(prevPos);
145
+ }
146
+ }
147
+ return {
148
+ $from: adjustedFrom,
149
+ $to: adjustedTo
150
+ };
151
+ };
101
152
  /**
102
153
  * Creates a preserved selection which is expanded to block boundaries.
103
154
  *
@@ -113,9 +164,17 @@ export var mapPreservedSelection = function mapPreservedSelection(selection, tr)
113
164
  export var createPreservedSelection = function createPreservedSelection($from, $to) {
114
165
  var _doc$nodeAt;
115
166
  var doc = $from.doc;
167
+ var isCollapsed = $from.pos === $to.pos;
168
+ var adjusted = isCollapsed ? {
169
+ $from: $from,
170
+ $to: $to
171
+ } : adjustSelectionBoundsForEdgePositions($from, $to);
172
+ if (!isCollapsed && adjusted.$from.pos >= adjusted.$to.pos) {
173
+ return undefined;
174
+ }
116
175
 
117
176
  // expand the selection range to block boundaries, so selection always includes whole nodes
118
- var expanded = expandToBlockRange($from, $to);
177
+ var expanded = expandToBlockRange(adjusted.$from, adjusted.$to);
119
178
 
120
179
  // stop preserving if selection becomes invalid
121
180
  if (expanded.$from.pos < 0 || expanded.$to.pos > doc.content.size || expanded.$from.pos >= expanded.$to.pos) {
@@ -42,7 +42,7 @@ import { selectionPreservationPluginKey } from '../pm-plugins/selection-preserva
42
42
  import { getMultiSelectAnalyticsAttributes } from '../pm-plugins/utils/analytics';
43
43
  import { getControlBottomCSSValue, getControlHeightCSSValue, getLeftPosition, getNodeHeight, getTopPosition, shouldBeSticky, shouldMaskNodeControls } from '../pm-plugins/utils/drag-handle-positions';
44
44
  import { isHandleCorrelatedToSelection, selectNode } from '../pm-plugins/utils/getSelection';
45
- import { alignAnchorHeadInDirectionOfPos, expandSelectionHeadToNodeAtPos } from '../pm-plugins/utils/selection';
45
+ import { adjustSelectionBoundsForEdgePositions, alignAnchorHeadInDirectionOfPos, expandSelectionHeadToNodeAtPos } from '../pm-plugins/utils/selection';
46
46
  import { DRAG_HANDLE_BORDER_RADIUS, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH, DRAG_HANDLE_ZINDEX, dragHandleGap, nodeMargins, spacingBetweenNodesForPreview, STICKY_CONTROLS_TOP_MARGIN, STICKY_CONTROLS_TOP_MARGIN_FOR_STICKY_HEADER, topPositionAdjustment } from './consts';
47
47
  import { dragPreview } from './drag-preview';
48
48
  import { refreshAnchorName } from './utils/anchor-name';
@@ -355,7 +355,11 @@ var getExpandedSelectionRange = function getExpandedSelectionRange(_ref) {
355
355
  var selectUp = resolvedStartPos.pos < selection.from;
356
356
  var $from = isShiftPressed && selectUp ? resolvedStartPos : selection.$from;
357
357
  var $to = isShiftPressed && !selectUp ? doc.resolve(resolvedStartPos.pos + 1) : selection.$to;
358
- return expandToBlockRange($from, $to);
358
+ var adjusted = isShiftPressed ? {
359
+ $from: $from,
360
+ $to: $to
361
+ } : adjustSelectionBoundsForEdgePositions($from, $to);
362
+ return expandToBlockRange(adjusted.$from, adjusted.$to);
359
363
  };
360
364
  /**
361
365
  * Updates the transaction with preserved selection logic.
@@ -39,6 +39,21 @@ export declare const alignAnchorHeadInDirectionOfPos: (selection: Selection, pos
39
39
  * @returns The mapped selection or undefined if mapping is not possible
40
40
  */
41
41
  export declare const mapPreservedSelection: (selection: Selection, tr: ReadonlyTransaction | Transaction) => Selection | undefined;
42
+ /**
43
+ * Adjust selection bounds to exclude nodes where the selection only touches
44
+ * the edge position without selecting any content.
45
+ *
46
+ * Exception: Don't adjust if the selection is inside an empty textblock,
47
+ * as we want to include empty paragraphs in block operations.
48
+ *
49
+ * @param $from The resolved position of the start of the selection
50
+ * @param $to The resolved position of the end of the selection
51
+ * @returns Adjusted $from and $to positions
52
+ */
53
+ export declare const adjustSelectionBoundsForEdgePositions: ($from: ResolvedPos, $to: ResolvedPos) => {
54
+ $from: ResolvedPos;
55
+ $to: ResolvedPos;
56
+ };
42
57
  /**
43
58
  * Creates a preserved selection which is expanded to block boundaries.
44
59
  *
@@ -39,6 +39,21 @@ export declare const alignAnchorHeadInDirectionOfPos: (selection: Selection, pos
39
39
  * @returns The mapped selection or undefined if mapping is not possible
40
40
  */
41
41
  export declare const mapPreservedSelection: (selection: Selection, tr: ReadonlyTransaction | Transaction) => Selection | undefined;
42
+ /**
43
+ * Adjust selection bounds to exclude nodes where the selection only touches
44
+ * the edge position without selecting any content.
45
+ *
46
+ * Exception: Don't adjust if the selection is inside an empty textblock,
47
+ * as we want to include empty paragraphs in block operations.
48
+ *
49
+ * @param $from The resolved position of the start of the selection
50
+ * @param $to The resolved position of the end of the selection
51
+ * @returns Adjusted $from and $to positions
52
+ */
53
+ export declare const adjustSelectionBoundsForEdgePositions: ($from: ResolvedPos, $to: ResolvedPos) => {
54
+ $from: ResolvedPos;
55
+ $to: ResolvedPos;
56
+ };
42
57
  /**
43
58
  * Creates a preserved selection which is expanded to block boundaries.
44
59
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-controls",
3
- "version": "8.0.14",
3
+ "version": "8.0.15",
4
4
  "description": "Block controls plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -42,7 +42,7 @@
42
42
  "@atlaskit/editor-plugin-toolbar": "^4.1.0",
43
43
  "@atlaskit/editor-plugin-type-ahead": "^7.0.0",
44
44
  "@atlaskit/editor-plugin-user-intent": "^5.0.0",
45
- "@atlaskit/editor-plugin-width": "^8.0.0",
45
+ "@atlaskit/editor-plugin-width": "^8.1.0",
46
46
  "@atlaskit/editor-prosemirror": "^7.2.0",
47
47
  "@atlaskit/editor-shared-styles": "^3.10.0",
48
48
  "@atlaskit/editor-tables": "^2.9.0",
@@ -54,7 +54,7 @@
54
54
  "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^3.2.0",
55
55
  "@atlaskit/primitives": "^17.1.0",
56
56
  "@atlaskit/theme": "^21.0.0",
57
- "@atlaskit/tmp-editor-statsig": "^16.30.0",
57
+ "@atlaskit/tmp-editor-statsig": "^16.35.0",
58
58
  "@atlaskit/tokens": "^10.1.0",
59
59
  "@atlaskit/tooltip": "^20.14.0",
60
60
  "@babel/runtime": "^7.0.0",
@@ -66,7 +66,7 @@
66
66
  "uuid": "^3.1.0"
67
67
  },
68
68
  "peerDependencies": {
69
- "@atlaskit/editor-common": "^111.8.0",
69
+ "@atlaskit/editor-common": "^111.9.0",
70
70
  "react": "^18.2.0",
71
71
  "react-dom": "^18.2.0",
72
72
  "react-intl-next": "npm:react-intl@^5.18.1"