@atlaskit/editor-plugin-block-controls 13.3.3 → 13.3.4

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,25 @@
1
1
  # @atlaskit/editor-plugin-block-controls
2
2
 
3
+ ## 13.3.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [`069c5c0253ba5`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/069c5c0253ba5) -
8
+ [ux] Improve Remix button hover reliability near the right edge of narrow editor layouts behind
9
+ the `cc_maui_remix_button_hover_corridor` experiment.
10
+
11
+ Consumers can check the new typed boolean experiment at the behavior callsite:
12
+
13
+ ```ts
14
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
15
+
16
+ if (expValEquals('cc_maui_remix_button_hover_corridor', 'isEnabled', true)) {
17
+ // Apply the treatment behavior.
18
+ }
19
+ ```
20
+
21
+ - Updated dependencies
22
+
3
23
  ## 13.3.3
4
24
 
5
25
  ### Patch Changes
@@ -20,10 +20,14 @@ var mouseLeave = exports.mouseLeave = function mouseLeave(view) {
20
20
  type: 'mouseLeave'
21
21
  }));
22
22
  };
23
- var mouseEnter = exports.mouseEnter = function mouseEnter(view) {
24
- view.dispatch(view.state.tr.setMeta(_pmPlugin.interactionTrackingPluginKey, {
23
+ var mouseEnter = exports.mouseEnter = function mouseEnter(view, side) {
24
+ var meta = side ? {
25
+ type: 'mouseEnter',
26
+ side: side
27
+ } : {
25
28
  type: 'mouseEnter'
26
- }));
29
+ };
30
+ view.dispatch(view.state.tr.setMeta(_pmPlugin.interactionTrackingPluginKey, meta));
27
31
  };
28
32
  var setHoverSide = exports.setHoverSide = function setHoverSide(view, side) {
29
33
  view.dispatch(view.state.tr.setMeta(_pmPlugin.interactionTrackingPluginKey, {
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.handleMouseMove = exports.handleMouseLeave = exports.handleMouseEnter = void 0;
7
+ var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
7
8
  var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
8
9
  var _handleMouseOver = require("../handle-mouse-over");
9
10
  var _commands = require("./commands");
@@ -109,6 +110,10 @@ var processHoverSide = function processHoverSide(view, api) {
109
110
  // This is more reliable than bounds when controls are in portals outside the editor DOM.
110
111
  var rightEdgeElement = target === null || target === void 0 ? void 0 : target.closest(RIGHT_EDGE_SELECTOR);
111
112
  if (rightEdgeElement) {
113
+ if (state !== null && state !== void 0 && state.isMouseOut && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('cc_maui_remix_button_hover_corridor', 'isEnabled', true)) {
114
+ (0, _commands.mouseEnter)(view, 'right');
115
+ return;
116
+ }
112
117
  if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'right') {
113
118
  (0, _commands.setHoverSide)(view, 'right');
114
119
  }
@@ -138,6 +143,10 @@ var processHoverSide = function processHoverSide(view, api) {
138
143
  }, api);
139
144
  // mouseenter doesn't fire over the click overlay, so clear isMouseOut here to re-show.
140
145
  if (state !== null && state !== void 0 && state.isMouseOut) {
146
+ if ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('cc_maui_remix_button_hover_corridor', 'isEnabled', true)) {
147
+ (0, _commands.mouseEnter)(view, 'right');
148
+ return;
149
+ }
141
150
  (0, _commands.mouseEnter)(view);
142
151
  }
143
152
  if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'right') {
@@ -147,7 +156,9 @@ var processHoverSide = function processHoverSide(view, api) {
147
156
  }
148
157
 
149
158
  // In the Rovo gap, dismiss the controls so the button doesn't linger over the Rovo button.
150
- if ((marginZone === null || marginZone === void 0 ? void 0 : marginZone.type) === 'gap' || event.clientX > getRightMarginBoundary(view)) {
159
+ // The corridor experiment keeps controls visible when the pointer is still over a real block;
160
+ // only empty margin remains reserved for Rovo in that case.
161
+ if ((marginZone === null || marginZone === void 0 ? void 0 : marginZone.type) === 'gap' || event.clientX > getRightMarginBoundary(view) && (!blockElement || !(0, _expValEqualsNoExposure.expValEqualsNoExposure)('cc_maui_remix_button_hover_corridor', 'isEnabled', true))) {
151
162
  if (!(state !== null && state !== void 0 && state.isMouseOut)) {
152
163
  (0, _commands.clearHoverSide)(view);
153
164
  (0, _commands.mouseLeave)(view);
@@ -166,6 +177,10 @@ var processHoverSide = function processHoverSide(view, api) {
166
177
  var midpoint = (left + right) / 2;
167
178
  var nextHoverSide = event.clientX > midpoint ? 'right' : 'left';
168
179
  if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== nextHoverSide) {
180
+ if (state !== null && state !== void 0 && state.isMouseOut && target !== null && target !== void 0 && target.closest(BLOCK_SELECTORS) && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('cc_maui_remix_button_hover_corridor', 'isEnabled', true)) {
181
+ (0, _commands.mouseEnter)(view, nextHoverSide);
182
+ return;
183
+ }
169
184
  (0, _commands.setHoverSide)(view, nextHoverSide);
170
185
  }
171
186
  };
@@ -79,6 +79,9 @@ var createInteractionTrackingPlugin = exports.createInteractionTrackingPlugin =
79
79
  break;
80
80
  case 'mouseEnter':
81
81
  newState.isMouseOut = false;
82
+ if (meta.side) {
83
+ newState.hoverSide = meta.side;
84
+ }
82
85
  break;
83
86
  case 'setHoverSide':
84
87
  newState.hoverSide = meta.side;
@@ -14,10 +14,14 @@ export const mouseLeave = view => {
14
14
  type: 'mouseLeave'
15
15
  }));
16
16
  };
17
- export const mouseEnter = view => {
18
- view.dispatch(view.state.tr.setMeta(interactionTrackingPluginKey, {
17
+ export const mouseEnter = (view, side) => {
18
+ const meta = side ? {
19
+ type: 'mouseEnter',
20
+ side
21
+ } : {
19
22
  type: 'mouseEnter'
20
- }));
23
+ };
24
+ view.dispatch(view.state.tr.setMeta(interactionTrackingPluginKey, meta));
21
25
  };
22
26
  export const setHoverSide = (view, side) => {
23
27
  view.dispatch(view.state.tr.setMeta(interactionTrackingPluginKey, {
@@ -1,3 +1,4 @@
1
+ import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
1
2
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
2
3
  import { handleMouseOver } from '../handle-mouse-over';
3
4
  import { clearHoverSide, mouseEnter, mouseLeave, setHoverSide, stopEditing } from './commands';
@@ -90,6 +91,10 @@ const processHoverSide = (view, api) => {
90
91
  // This is more reliable than bounds when controls are in portals outside the editor DOM.
91
92
  const rightEdgeElement = target === null || target === void 0 ? void 0 : target.closest(RIGHT_EDGE_SELECTOR);
92
93
  if (rightEdgeElement) {
94
+ if (state !== null && state !== void 0 && state.isMouseOut && expValEqualsNoExposure('cc_maui_remix_button_hover_corridor', 'isEnabled', true)) {
95
+ mouseEnter(view, 'right');
96
+ return;
97
+ }
93
98
  if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'right') {
94
99
  setHoverSide(view, 'right');
95
100
  }
@@ -119,6 +124,10 @@ const processHoverSide = (view, api) => {
119
124
  }, api);
120
125
  // mouseenter doesn't fire over the click overlay, so clear isMouseOut here to re-show.
121
126
  if (state !== null && state !== void 0 && state.isMouseOut) {
127
+ if (expValEqualsNoExposure('cc_maui_remix_button_hover_corridor', 'isEnabled', true)) {
128
+ mouseEnter(view, 'right');
129
+ return;
130
+ }
122
131
  mouseEnter(view);
123
132
  }
124
133
  if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'right') {
@@ -128,7 +137,9 @@ const processHoverSide = (view, api) => {
128
137
  }
129
138
 
130
139
  // In the Rovo gap, dismiss the controls so the button doesn't linger over the Rovo button.
131
- if ((marginZone === null || marginZone === void 0 ? void 0 : marginZone.type) === 'gap' || event.clientX > getRightMarginBoundary(view)) {
140
+ // The corridor experiment keeps controls visible when the pointer is still over a real block;
141
+ // only empty margin remains reserved for Rovo in that case.
142
+ if ((marginZone === null || marginZone === void 0 ? void 0 : marginZone.type) === 'gap' || event.clientX > getRightMarginBoundary(view) && (!blockElement || !expValEqualsNoExposure('cc_maui_remix_button_hover_corridor', 'isEnabled', true))) {
132
143
  if (!(state !== null && state !== void 0 && state.isMouseOut)) {
133
144
  clearHoverSide(view);
134
145
  mouseLeave(view);
@@ -148,6 +159,10 @@ const processHoverSide = (view, api) => {
148
159
  const midpoint = (left + right) / 2;
149
160
  const nextHoverSide = event.clientX > midpoint ? 'right' : 'left';
150
161
  if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== nextHoverSide) {
162
+ if (state !== null && state !== void 0 && state.isMouseOut && target !== null && target !== void 0 && target.closest(BLOCK_SELECTORS) && expValEqualsNoExposure('cc_maui_remix_button_hover_corridor', 'isEnabled', true)) {
163
+ mouseEnter(view, nextHoverSide);
164
+ return;
165
+ }
151
166
  setHoverSide(view, nextHoverSide);
152
167
  }
153
168
  };
@@ -66,6 +66,9 @@ export const createInteractionTrackingPlugin = (rightSideControlsEnabled = false
66
66
  break;
67
67
  case 'mouseEnter':
68
68
  newState.isMouseOut = false;
69
+ if (meta.side) {
70
+ newState.hoverSide = meta.side;
71
+ }
69
72
  break;
70
73
  case 'setHoverSide':
71
74
  newState.hoverSide = meta.side;
@@ -14,10 +14,14 @@ export var mouseLeave = function mouseLeave(view) {
14
14
  type: 'mouseLeave'
15
15
  }));
16
16
  };
17
- export var mouseEnter = function mouseEnter(view) {
18
- view.dispatch(view.state.tr.setMeta(interactionTrackingPluginKey, {
17
+ export var mouseEnter = function mouseEnter(view, side) {
18
+ var meta = side ? {
19
+ type: 'mouseEnter',
20
+ side: side
21
+ } : {
19
22
  type: 'mouseEnter'
20
- }));
23
+ };
24
+ view.dispatch(view.state.tr.setMeta(interactionTrackingPluginKey, meta));
21
25
  };
22
26
  export var setHoverSide = function setHoverSide(view, side) {
23
27
  view.dispatch(view.state.tr.setMeta(interactionTrackingPluginKey, {
@@ -1,6 +1,7 @@
1
1
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
2
2
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
3
3
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
4
+ import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
4
5
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
5
6
  import { handleMouseOver } from '../handle-mouse-over';
6
7
  import { clearHoverSide, mouseEnter, mouseLeave, setHoverSide, stopEditing } from './commands';
@@ -104,6 +105,10 @@ var processHoverSide = function processHoverSide(view, api) {
104
105
  // This is more reliable than bounds when controls are in portals outside the editor DOM.
105
106
  var rightEdgeElement = target === null || target === void 0 ? void 0 : target.closest(RIGHT_EDGE_SELECTOR);
106
107
  if (rightEdgeElement) {
108
+ if (state !== null && state !== void 0 && state.isMouseOut && expValEqualsNoExposure('cc_maui_remix_button_hover_corridor', 'isEnabled', true)) {
109
+ mouseEnter(view, 'right');
110
+ return;
111
+ }
107
112
  if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'right') {
108
113
  setHoverSide(view, 'right');
109
114
  }
@@ -133,6 +138,10 @@ var processHoverSide = function processHoverSide(view, api) {
133
138
  }, api);
134
139
  // mouseenter doesn't fire over the click overlay, so clear isMouseOut here to re-show.
135
140
  if (state !== null && state !== void 0 && state.isMouseOut) {
141
+ if (expValEqualsNoExposure('cc_maui_remix_button_hover_corridor', 'isEnabled', true)) {
142
+ mouseEnter(view, 'right');
143
+ return;
144
+ }
136
145
  mouseEnter(view);
137
146
  }
138
147
  if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'right') {
@@ -142,7 +151,9 @@ var processHoverSide = function processHoverSide(view, api) {
142
151
  }
143
152
 
144
153
  // In the Rovo gap, dismiss the controls so the button doesn't linger over the Rovo button.
145
- if ((marginZone === null || marginZone === void 0 ? void 0 : marginZone.type) === 'gap' || event.clientX > getRightMarginBoundary(view)) {
154
+ // The corridor experiment keeps controls visible when the pointer is still over a real block;
155
+ // only empty margin remains reserved for Rovo in that case.
156
+ if ((marginZone === null || marginZone === void 0 ? void 0 : marginZone.type) === 'gap' || event.clientX > getRightMarginBoundary(view) && (!blockElement || !expValEqualsNoExposure('cc_maui_remix_button_hover_corridor', 'isEnabled', true))) {
146
157
  if (!(state !== null && state !== void 0 && state.isMouseOut)) {
147
158
  clearHoverSide(view);
148
159
  mouseLeave(view);
@@ -161,6 +172,10 @@ var processHoverSide = function processHoverSide(view, api) {
161
172
  var midpoint = (left + right) / 2;
162
173
  var nextHoverSide = event.clientX > midpoint ? 'right' : 'left';
163
174
  if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== nextHoverSide) {
175
+ if (state !== null && state !== void 0 && state.isMouseOut && target !== null && target !== void 0 && target.closest(BLOCK_SELECTORS) && expValEqualsNoExposure('cc_maui_remix_button_hover_corridor', 'isEnabled', true)) {
176
+ mouseEnter(view, nextHoverSide);
177
+ return;
178
+ }
164
179
  setHoverSide(view, nextHoverSide);
165
180
  }
166
181
  };
@@ -73,6 +73,9 @@ export var createInteractionTrackingPlugin = function createInteractionTrackingP
73
73
  break;
74
74
  case 'mouseEnter':
75
75
  newState.isMouseOut = false;
76
+ if (meta.side) {
77
+ newState.hoverSide = meta.side;
78
+ }
76
79
  break;
77
80
  case 'setHoverSide':
78
81
  newState.hoverSide = meta.side;
@@ -2,6 +2,6 @@ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
2
2
  export declare const stopEditing: (view: EditorView) => void;
3
3
  export declare const startEditing: (view: EditorView) => void;
4
4
  export declare const mouseLeave: (view: EditorView) => void;
5
- export declare const mouseEnter: (view: EditorView) => void;
5
+ export declare const mouseEnter: (view: EditorView, side?: 'left' | 'right') => void;
6
6
  export declare const setHoverSide: (view: EditorView, side: 'left' | 'right') => void;
7
7
  export declare const clearHoverSide: (view: EditorView) => void;
@@ -4,7 +4,7 @@ export declare const getLeftPosition: (dom: HTMLElement | null, type: string, in
4
4
  export declare const getNodeHeight: (dom: HTMLElement | null, anchor: string, anchorRectCache?: AnchorRectCache) => number | undefined;
5
5
  export declare const shouldBeSticky: (nodeType: string) => boolean;
6
6
  export declare const getControlBottomCSSValue: (anchor: string, isSticky: boolean, isTopLevelNode: boolean, isLayoutColumn?: boolean, fallbackAnchor?: string) => {
7
- bottom: String;
7
+ bottom: string;
8
8
  };
9
9
  export declare const getControlHeightCSSValue: (nodeHeight: number, isSticky: boolean, isTopLevelNode: boolean, fallbackPxHeight: string, isLayoutColumn?: boolean) => {
10
10
  height: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-controls",
3
- "version": "13.3.3",
3
+ "version": "13.3.4",
4
4
  "description": "Block controls plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -33,7 +33,7 @@
33
33
  "@atlaskit/editor-plugin-quick-insert": "^12.0.0",
34
34
  "@atlaskit/editor-plugin-selection": "^12.0.0",
35
35
  "@atlaskit/editor-plugin-toolbar": "^9.0.0",
36
- "@atlaskit/editor-plugin-type-ahead": "^13.0.0",
36
+ "@atlaskit/editor-plugin-type-ahead": "^13.1.0",
37
37
  "@atlaskit/editor-plugin-user-intent": "^10.1.0",
38
38
  "@atlaskit/editor-plugin-width": "^13.0.0",
39
39
  "@atlaskit/editor-prosemirror": "^8.0.0",
@@ -48,7 +48,7 @@
48
48
  "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^4.1.0",
49
49
  "@atlaskit/primitives": "^22.2.0",
50
50
  "@atlaskit/theme": "^26.1.0",
51
- "@atlaskit/tmp-editor-statsig": "^135.0.0",
51
+ "@atlaskit/tmp-editor-statsig": "^135.4.0",
52
52
  "@atlaskit/tokens": "^16.3.0",
53
53
  "@atlaskit/tooltip": "^23.2.0",
54
54
  "@babel/runtime": "^7.0.0",
@@ -59,7 +59,7 @@
59
59
  "uuid": "^3.1.0"
60
60
  },
61
61
  "peerDependencies": {
62
- "@atlaskit/editor-common": "^116.41.0",
62
+ "@atlaskit/editor-common": "^116.44.0",
63
63
  "react": "^18.2.0",
64
64
  "react-dom": "^18.2.0",
65
65
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"