@atlaskit/editor-plugin-selection-marker 2.4.5 → 2.5.0

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,18 @@
1
1
  # @atlaskit/editor-plugin-selection-marker
2
2
 
3
+ ## 2.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#171777](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/171777)
8
+ [`befd8b6d56e78`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/befd8b6d56e78) -
9
+ [ux] Update selection marker fake-cursor to use an inline element when placed inside words, to
10
+ prevent erroneous text wrapping.
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies
15
+
3
16
  ## 2.4.5
4
17
 
5
18
  ### Patch Changes
@@ -8,6 +8,7 @@ exports.createWidgetDecoration = void 0;
8
8
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
9
  var _state = require("@atlaskit/editor-prosemirror/state");
10
10
  var _view = require("@atlaskit/editor-prosemirror/view");
11
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
11
12
  var _colors = require("@atlaskit/theme/colors");
12
13
  /**
13
14
  * @jsxRuntime classic
@@ -31,7 +32,7 @@ var selectionMarkerHighlightStyles = {
31
32
  marginRight: "var(--ds-space-negative-025, -2px)",
32
33
  pointerEvents: 'none'
33
34
  };
34
- var selectionMarkerCursorStyles = {
35
+ var selectionMarkerBlockCursorStyles = {
35
36
  content: "''",
36
37
  position: 'absolute',
37
38
  background: "var(--ds-text, ".concat(_colors.N500, ")"),
@@ -46,6 +47,16 @@ var selectionMarkerCursorStyles = {
46
47
  pointerEvents: 'none'
47
48
  };
48
49
 
50
+ // Same as above but defined as an inline element to avoid breaking long words
51
+ var selectionMarkerInlineCursorStyles = {
52
+ content: "''",
53
+ position: 'relative',
54
+ pointerEvents: 'none',
55
+ borderLeft: "1px solid ".concat("var(--ds-text, ".concat(_colors.N500, ")")),
56
+ marginLeft: '-1px',
57
+ left: '0.5px'
58
+ };
59
+
49
60
  /**
50
61
  * Converts a camelCased CSS property name to a hyphenated CSS property name.
51
62
  *
@@ -61,8 +72,10 @@ function hyphenate(property) {
61
72
  }
62
73
  var Widget = function Widget(_ref) {
63
74
  var type = _ref.type,
64
- isHighlight = _ref.isHighlight;
75
+ isHighlight = _ref.isHighlight,
76
+ isInWord = _ref.isInWord;
65
77
  var span = document.createElement('span');
78
+ var selectionMarkerCursorStyles = isInWord && (0, _platformFeatureFlags.fg)('platform_editor_inline_selection_marker_cursor') ? selectionMarkerInlineCursorStyles : selectionMarkerBlockCursorStyles;
66
79
  var styles = isHighlight ? selectionMarkerHighlightStyles : selectionMarkerCursorStyles;
67
80
  for (var _i = 0, _Object$entries = Object.entries(styles); _i < _Object$entries.length; _i++) {
68
81
  var _Object$entries$_i = (0, _slicedToArray2.default)(_Object$entries[_i], 2),
@@ -74,13 +87,14 @@ var Widget = function Widget(_ref) {
74
87
  span.dataset.testid = "selection-marker-".concat(type, "-cursor");
75
88
  return span;
76
89
  };
77
- var toDOM = function toDOM(type, isHighlight) {
90
+ var toDOM = function toDOM(type, isHighlight, isInWord) {
78
91
  var element = document.createElement('span');
79
92
  element.contentEditable = 'false';
80
93
  element.setAttribute('style', "position: relative;");
81
94
  element.appendChild(Widget({
82
95
  type: type,
83
- isHighlight: isHighlight
96
+ isHighlight: isHighlight,
97
+ isInWord: isInWord
84
98
  }));
85
99
  return element;
86
100
  };
@@ -95,7 +109,23 @@ var createWidgetDecoration = exports.createWidgetDecoration = function createWid
95
109
  if (!(selection instanceof _state.TextSelection) || containsText(resolvedPos) === false || !selection.empty) {
96
110
  return [];
97
111
  }
98
- return [_view.Decoration.widget(resolvedPos.pos, toDOM(type, isHighlight), {
112
+ var isInWord = false;
113
+ if ((0, _platformFeatureFlags.fg)('platform_editor_inline_selection_marker_cursor')) {
114
+ var _nodeBefore$textConte, _nodeAfter$textConten;
115
+ // We're inside a word if the parent, before, and after nodes are all text nodes
116
+ // and the before/after nodes are appended/prepended with non-whitespace characters
117
+ // Also if we're making a selection and not just a cursor, this isn't relevant
118
+ var nodeBefore = resolvedPos.nodeBefore,
119
+ nodeAfter = resolvedPos.nodeAfter,
120
+ parent = resolvedPos.parent;
121
+ // Check if the parent is a text node and the before/after nodes are also text nodes
122
+ var areTextNodes = parent.isTextblock && (nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.isText) && (nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.isText);
123
+ var lastCharacterOfBeforeNode = nodeBefore === null || nodeBefore === void 0 || (_nodeBefore$textConte = nodeBefore.textContent) === null || _nodeBefore$textConte === void 0 ? void 0 : _nodeBefore$textConte.slice(-1);
124
+ var firstCharacterOfAfterNode = nodeAfter === null || nodeAfter === void 0 || (_nodeAfter$textConten = nodeAfter.textContent) === null || _nodeAfter$textConten === void 0 ? void 0 : _nodeAfter$textConten.slice(0, 1);
125
+ var areAdjacentCharactersNonWhitespace = /(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/.test(lastCharacterOfBeforeNode || '') && /(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/.test(firstCharacterOfAfterNode || '');
126
+ isInWord = Boolean(areTextNodes && areAdjacentCharactersNonWhitespace);
127
+ }
128
+ return [_view.Decoration.widget(resolvedPos.pos, toDOM(type, isHighlight, isInWord), {
99
129
  side: -1,
100
130
  key: "".concat(type, "WidgetDecoration"),
101
131
  stopEvent: function stopEvent() {
@@ -5,6 +5,7 @@
5
5
 
6
6
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
7
7
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
8
+ import { fg } from '@atlaskit/platform-feature-flags';
8
9
  import { N500 } from '@atlaskit/theme/colors';
9
10
  const selectionMarkerHighlightStyles = {
10
11
  content: "''",
@@ -23,7 +24,7 @@ const selectionMarkerHighlightStyles = {
23
24
  marginRight: "var(--ds-space-negative-025, -2px)",
24
25
  pointerEvents: 'none'
25
26
  };
26
- const selectionMarkerCursorStyles = {
27
+ const selectionMarkerBlockCursorStyles = {
27
28
  content: "''",
28
29
  position: 'absolute',
29
30
  background: `var(--ds-text, ${N500})`,
@@ -38,6 +39,16 @@ const selectionMarkerCursorStyles = {
38
39
  pointerEvents: 'none'
39
40
  };
40
41
 
42
+ // Same as above but defined as an inline element to avoid breaking long words
43
+ const selectionMarkerInlineCursorStyles = {
44
+ content: "''",
45
+ position: 'relative',
46
+ pointerEvents: 'none',
47
+ borderLeft: `1px solid ${`var(--ds-text, ${N500})`}`,
48
+ marginLeft: '-1px',
49
+ left: '0.5px'
50
+ };
51
+
41
52
  /**
42
53
  * Converts a camelCased CSS property name to a hyphenated CSS property name.
43
54
  *
@@ -51,9 +62,11 @@ function hyphenate(property) {
51
62
  }
52
63
  const Widget = ({
53
64
  type,
54
- isHighlight
65
+ isHighlight,
66
+ isInWord
55
67
  }) => {
56
68
  const span = document.createElement('span');
69
+ const selectionMarkerCursorStyles = isInWord && fg('platform_editor_inline_selection_marker_cursor') ? selectionMarkerInlineCursorStyles : selectionMarkerBlockCursorStyles;
57
70
  const styles = isHighlight ? selectionMarkerHighlightStyles : selectionMarkerCursorStyles;
58
71
  for (const [rule, value] of Object.entries(styles)) {
59
72
  span.style.setProperty(hyphenate(rule), value);
@@ -62,13 +75,14 @@ const Widget = ({
62
75
  span.dataset.testid = `selection-marker-${type}-cursor`;
63
76
  return span;
64
77
  };
65
- const toDOM = (type, isHighlight) => {
78
+ const toDOM = (type, isHighlight, isInWord) => {
66
79
  const element = document.createElement('span');
67
80
  element.contentEditable = 'false';
68
81
  element.setAttribute('style', `position: relative;`);
69
82
  element.appendChild(Widget({
70
83
  type,
71
- isHighlight
84
+ isHighlight,
85
+ isInWord
72
86
  }));
73
87
  return element;
74
88
  };
@@ -85,7 +99,25 @@ export const createWidgetDecoration = (resolvedPos, type, selection, isHighlight
85
99
  if (!(selection instanceof TextSelection) || containsText(resolvedPos) === false || !selection.empty) {
86
100
  return [];
87
101
  }
88
- return [Decoration.widget(resolvedPos.pos, toDOM(type, isHighlight), {
102
+ let isInWord = false;
103
+ if (fg('platform_editor_inline_selection_marker_cursor')) {
104
+ var _nodeBefore$textConte, _nodeAfter$textConten;
105
+ // We're inside a word if the parent, before, and after nodes are all text nodes
106
+ // and the before/after nodes are appended/prepended with non-whitespace characters
107
+ // Also if we're making a selection and not just a cursor, this isn't relevant
108
+ const {
109
+ nodeBefore,
110
+ nodeAfter,
111
+ parent
112
+ } = resolvedPos;
113
+ // Check if the parent is a text node and the before/after nodes are also text nodes
114
+ const areTextNodes = parent.isTextblock && (nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.isText) && (nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.isText);
115
+ const lastCharacterOfBeforeNode = nodeBefore === null || nodeBefore === void 0 ? void 0 : (_nodeBefore$textConte = nodeBefore.textContent) === null || _nodeBefore$textConte === void 0 ? void 0 : _nodeBefore$textConte.slice(-1);
116
+ const firstCharacterOfAfterNode = nodeAfter === null || nodeAfter === void 0 ? void 0 : (_nodeAfter$textConten = nodeAfter.textContent) === null || _nodeAfter$textConten === void 0 ? void 0 : _nodeAfter$textConten.slice(0, 1);
117
+ const areAdjacentCharactersNonWhitespace = /\S/u.test(lastCharacterOfBeforeNode || '') && /\S/u.test(firstCharacterOfAfterNode || '');
118
+ isInWord = Boolean(areTextNodes && areAdjacentCharactersNonWhitespace);
119
+ }
120
+ return [Decoration.widget(resolvedPos.pos, toDOM(type, isHighlight, isInWord), {
89
121
  side: -1,
90
122
  key: `${type}WidgetDecoration`,
91
123
  stopEvent: () => true,
@@ -6,6 +6,7 @@ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
6
6
 
7
7
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
8
8
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
9
+ import { fg } from '@atlaskit/platform-feature-flags';
9
10
  import { N500 } from '@atlaskit/theme/colors';
10
11
  var selectionMarkerHighlightStyles = {
11
12
  content: "''",
@@ -24,7 +25,7 @@ var selectionMarkerHighlightStyles = {
24
25
  marginRight: "var(--ds-space-negative-025, -2px)",
25
26
  pointerEvents: 'none'
26
27
  };
27
- var selectionMarkerCursorStyles = {
28
+ var selectionMarkerBlockCursorStyles = {
28
29
  content: "''",
29
30
  position: 'absolute',
30
31
  background: "var(--ds-text, ".concat(N500, ")"),
@@ -39,6 +40,16 @@ var selectionMarkerCursorStyles = {
39
40
  pointerEvents: 'none'
40
41
  };
41
42
 
43
+ // Same as above but defined as an inline element to avoid breaking long words
44
+ var selectionMarkerInlineCursorStyles = {
45
+ content: "''",
46
+ position: 'relative',
47
+ pointerEvents: 'none',
48
+ borderLeft: "1px solid ".concat("var(--ds-text, ".concat(N500, ")")),
49
+ marginLeft: '-1px',
50
+ left: '0.5px'
51
+ };
52
+
42
53
  /**
43
54
  * Converts a camelCased CSS property name to a hyphenated CSS property name.
44
55
  *
@@ -54,8 +65,10 @@ function hyphenate(property) {
54
65
  }
55
66
  var Widget = function Widget(_ref) {
56
67
  var type = _ref.type,
57
- isHighlight = _ref.isHighlight;
68
+ isHighlight = _ref.isHighlight,
69
+ isInWord = _ref.isInWord;
58
70
  var span = document.createElement('span');
71
+ var selectionMarkerCursorStyles = isInWord && fg('platform_editor_inline_selection_marker_cursor') ? selectionMarkerInlineCursorStyles : selectionMarkerBlockCursorStyles;
59
72
  var styles = isHighlight ? selectionMarkerHighlightStyles : selectionMarkerCursorStyles;
60
73
  for (var _i = 0, _Object$entries = Object.entries(styles); _i < _Object$entries.length; _i++) {
61
74
  var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
@@ -67,13 +80,14 @@ var Widget = function Widget(_ref) {
67
80
  span.dataset.testid = "selection-marker-".concat(type, "-cursor");
68
81
  return span;
69
82
  };
70
- var toDOM = function toDOM(type, isHighlight) {
83
+ var toDOM = function toDOM(type, isHighlight, isInWord) {
71
84
  var element = document.createElement('span');
72
85
  element.contentEditable = 'false';
73
86
  element.setAttribute('style', "position: relative;");
74
87
  element.appendChild(Widget({
75
88
  type: type,
76
- isHighlight: isHighlight
89
+ isHighlight: isHighlight,
90
+ isInWord: isInWord
77
91
  }));
78
92
  return element;
79
93
  };
@@ -88,7 +102,23 @@ export var createWidgetDecoration = function createWidgetDecoration(resolvedPos,
88
102
  if (!(selection instanceof TextSelection) || containsText(resolvedPos) === false || !selection.empty) {
89
103
  return [];
90
104
  }
91
- return [Decoration.widget(resolvedPos.pos, toDOM(type, isHighlight), {
105
+ var isInWord = false;
106
+ if (fg('platform_editor_inline_selection_marker_cursor')) {
107
+ var _nodeBefore$textConte, _nodeAfter$textConten;
108
+ // We're inside a word if the parent, before, and after nodes are all text nodes
109
+ // and the before/after nodes are appended/prepended with non-whitespace characters
110
+ // Also if we're making a selection and not just a cursor, this isn't relevant
111
+ var nodeBefore = resolvedPos.nodeBefore,
112
+ nodeAfter = resolvedPos.nodeAfter,
113
+ parent = resolvedPos.parent;
114
+ // Check if the parent is a text node and the before/after nodes are also text nodes
115
+ var areTextNodes = parent.isTextblock && (nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.isText) && (nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.isText);
116
+ var lastCharacterOfBeforeNode = nodeBefore === null || nodeBefore === void 0 || (_nodeBefore$textConte = nodeBefore.textContent) === null || _nodeBefore$textConte === void 0 ? void 0 : _nodeBefore$textConte.slice(-1);
117
+ var firstCharacterOfAfterNode = nodeAfter === null || nodeAfter === void 0 || (_nodeAfter$textConten = nodeAfter.textContent) === null || _nodeAfter$textConten === void 0 ? void 0 : _nodeAfter$textConten.slice(0, 1);
118
+ var areAdjacentCharactersNonWhitespace = /(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/.test(lastCharacterOfBeforeNode || '') && /(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/.test(firstCharacterOfAfterNode || '');
119
+ isInWord = Boolean(areTextNodes && areAdjacentCharactersNonWhitespace);
120
+ }
121
+ return [Decoration.widget(resolvedPos.pos, toDOM(type, isHighlight, isInWord), {
92
122
  side: -1,
93
123
  key: "".concat(type, "WidgetDecoration"),
94
124
  stopEvent: function stopEvent() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-selection-marker",
3
- "version": "2.4.5",
3
+ "version": "2.5.0",
4
4
  "description": "Selection marker plugin for @atlaskit/editor-core.",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -31,8 +31,8 @@
31
31
  ".": "./src/index.ts"
32
32
  },
33
33
  "dependencies": {
34
- "@atlaskit/editor-common": "^106.6.0",
35
- "@atlaskit/editor-plugin-editor-disabled": "^2.0.0",
34
+ "@atlaskit/editor-common": "^106.9.0",
35
+ "@atlaskit/editor-plugin-editor-disabled": "^2.1.0",
36
36
  "@atlaskit/editor-plugin-focus": "^1.5.0",
37
37
  "@atlaskit/editor-plugin-type-ahead": "^2.7.0",
38
38
  "@atlaskit/editor-prosemirror": "7.0.0",
@@ -40,8 +40,8 @@
40
40
  "@atlaskit/platform-feature-flags": "^1.1.0",
41
41
  "@atlaskit/primitives": "^14.8.0",
42
42
  "@atlaskit/theme": "^18.0.0",
43
- "@atlaskit/tmp-editor-statsig": "^7.0.0",
44
- "@atlaskit/tokens": "^5.1.0",
43
+ "@atlaskit/tmp-editor-statsig": "^7.1.0",
44
+ "@atlaskit/tokens": "^5.2.0",
45
45
  "@babel/runtime": "^7.0.0",
46
46
  "@emotion/react": "^11.7.1",
47
47
  "lodash": "^4.17.21"
@@ -104,6 +104,9 @@
104
104
  },
105
105
  "dst-a11y__replace-anchor-with-link__editor-lego": {
106
106
  "type": "boolean"
107
+ },
108
+ "platform_editor_inline_selection_marker_cursor": {
109
+ "type": "boolean"
107
110
  }
108
111
  }
109
112
  }