@atlaskit/editor-plugin-block-controls 7.7.1 → 7.7.3
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 +16 -0
- package/dist/cjs/blockControlsPlugin.js +14 -0
- package/dist/cjs/pm-plugins/main.js +10 -4
- package/dist/cjs/pm-plugins/selection-preservation/editor-commands.js +32 -0
- package/dist/cjs/pm-plugins/selection-preservation/plugin-key.js +8 -0
- package/dist/cjs/pm-plugins/selection-preservation/pm-plugin.js +99 -0
- package/dist/cjs/pm-plugins/selection-preservation/types.js +5 -0
- package/dist/cjs/pm-plugins/selection-preservation/utils.js +24 -0
- package/dist/cjs/ui/drag-handle.js +196 -61
- package/dist/es2019/blockControlsPlugin.js +11 -1
- package/dist/es2019/pm-plugins/main.js +10 -4
- package/dist/es2019/pm-plugins/selection-preservation/editor-commands.js +28 -0
- package/dist/es2019/pm-plugins/selection-preservation/plugin-key.js +2 -0
- package/dist/es2019/pm-plugins/selection-preservation/pm-plugin.js +92 -0
- package/dist/es2019/pm-plugins/selection-preservation/types.js +1 -0
- package/dist/es2019/pm-plugins/selection-preservation/utils.js +16 -0
- package/dist/es2019/ui/drag-handle.js +170 -31
- package/dist/esm/blockControlsPlugin.js +14 -0
- package/dist/esm/pm-plugins/main.js +10 -4
- package/dist/esm/pm-plugins/selection-preservation/editor-commands.js +26 -0
- package/dist/esm/pm-plugins/selection-preservation/plugin-key.js +2 -0
- package/dist/esm/pm-plugins/selection-preservation/pm-plugin.js +93 -0
- package/dist/esm/pm-plugins/selection-preservation/types.js +1 -0
- package/dist/esm/pm-plugins/selection-preservation/utils.js +18 -0
- package/dist/esm/ui/drag-handle.js +195 -60
- package/dist/types/blockControlsPluginType.d.ts +12 -1
- package/dist/types/pm-plugins/selection-preservation/editor-commands.d.ts +13 -0
- package/dist/types/pm-plugins/selection-preservation/plugin-key.d.ts +3 -0
- package/dist/types/pm-plugins/selection-preservation/pm-plugin.d.ts +26 -0
- package/dist/types/pm-plugins/selection-preservation/types.d.ts +7 -0
- package/dist/types/pm-plugins/selection-preservation/utils.d.ts +10 -0
- package/dist/types-ts4.5/blockControlsPluginType.d.ts +12 -1
- package/dist/types-ts4.5/pm-plugins/selection-preservation/editor-commands.d.ts +13 -0
- package/dist/types-ts4.5/pm-plugins/selection-preservation/plugin-key.d.ts +3 -0
- package/dist/types-ts4.5/pm-plugins/selection-preservation/pm-plugin.d.ts +26 -0
- package/dist/types-ts4.5/pm-plugins/selection-preservation/types.d.ts +7 -0
- package/dist/types-ts4.5/pm-plugins/selection-preservation/utils.d.ts +10 -0
- package/package.json +7 -6
|
@@ -11,11 +11,13 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
|
|
|
11
11
|
var _react = require("react");
|
|
12
12
|
var _react2 = require("@emotion/react");
|
|
13
13
|
var _bindEventListener = require("bind-event-listener");
|
|
14
|
+
var _browserApis = require("@atlaskit/browser-apis");
|
|
14
15
|
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
15
16
|
var _browser = require("@atlaskit/editor-common/browser");
|
|
16
17
|
var _hooks = require("@atlaskit/editor-common/hooks");
|
|
17
18
|
var _keymaps = require("@atlaskit/editor-common/keymaps");
|
|
18
19
|
var _messages = require("@atlaskit/editor-common/messages");
|
|
20
|
+
var _selection2 = require("@atlaskit/editor-common/selection");
|
|
19
21
|
var _styles = require("@atlaskit/editor-common/styles");
|
|
20
22
|
var _useSharedPluginStateSelector = require("@atlaskit/editor-common/use-shared-plugin-state-selector");
|
|
21
23
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
@@ -33,10 +35,11 @@ var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
|
|
|
33
35
|
var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
|
|
34
36
|
var _decorationsCommon = require("../pm-plugins/decorations-common");
|
|
35
37
|
var _main = require("../pm-plugins/main");
|
|
38
|
+
var _pluginKey = require("../pm-plugins/selection-preservation/plugin-key");
|
|
36
39
|
var _analytics2 = require("../pm-plugins/utils/analytics");
|
|
37
40
|
var _dragHandlePositions = require("../pm-plugins/utils/drag-handle-positions");
|
|
38
41
|
var _getSelection = require("../pm-plugins/utils/getSelection");
|
|
39
|
-
var
|
|
42
|
+
var _selection3 = require("../pm-plugins/utils/selection");
|
|
40
43
|
var _consts2 = require("./consts");
|
|
41
44
|
var _dragPreview = require("./drag-preview");
|
|
42
45
|
var _anchorName = require("./utils/anchor-name");
|
|
@@ -295,18 +298,81 @@ var getNodeMargins = function getNodeMargins(node) {
|
|
|
295
298
|
}
|
|
296
299
|
return _consts2.nodeMargins[nodeTypeName] || _consts2.nodeMargins['default'];
|
|
297
300
|
};
|
|
298
|
-
var
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
301
|
+
var isRangeSpanningMultipleNodes = function isRangeSpanningMultipleNodes(range) {
|
|
302
|
+
if (range.endIndex - range.startIndex <= 1) {
|
|
303
|
+
return false; // At most one child
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Count block nodes in the range, return true if more than one
|
|
307
|
+
var blockCount = 0;
|
|
308
|
+
for (var i = range.startIndex; i < range.endIndex; i++) {
|
|
309
|
+
if (range.parent.child(i).isBlock) {
|
|
310
|
+
blockCount++;
|
|
311
|
+
}
|
|
312
|
+
if (blockCount > 1) {
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return false;
|
|
317
|
+
};
|
|
318
|
+
var shouldExpandSelection = function shouldExpandSelection(range, startPos) {
|
|
319
|
+
return !!range && isRangeSpanningMultipleNodes(range) && range.start <= startPos && range.end >= startPos + 1;
|
|
320
|
+
};
|
|
321
|
+
var calculateBlockRange = function calculateBlockRange(_ref) {
|
|
322
|
+
var selection = _ref.selection,
|
|
323
|
+
doc = _ref.doc,
|
|
324
|
+
resolvedStartPos = _ref.resolvedStartPos,
|
|
325
|
+
isShiftPressed = _ref.isShiftPressed;
|
|
326
|
+
if (!isShiftPressed) {
|
|
327
|
+
// When not pressing shift, create range including all block nodes within the selection
|
|
328
|
+
return selection.$from.blockRange(selection.$to);
|
|
329
|
+
}
|
|
330
|
+
if (resolvedStartPos.pos < selection.from) {
|
|
331
|
+
// If shift+click selecting upwards, get range from start of node to end of selection
|
|
332
|
+
return resolvedStartPos.blockRange(selection.$to);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Shift+click selecting downwards, get range from start of selection to pos within or after node
|
|
336
|
+
var resolvedPosWithinOrAfterNode = doc.resolve(resolvedStartPos.pos + 1);
|
|
337
|
+
return selection.$from.blockRange(resolvedPosWithinOrAfterNode);
|
|
338
|
+
};
|
|
339
|
+
var createExpandedSelection = function createExpandedSelection(doc, selection, range) {
|
|
340
|
+
return _state.TextSelection.create(doc, Math.min(selection.from, range.start), Math.max(selection.to, range.end));
|
|
341
|
+
};
|
|
342
|
+
var createSelectionFromRange = function createSelectionFromRange(_ref2) {
|
|
343
|
+
var tr = _ref2.tr,
|
|
344
|
+
selection = _ref2.selection,
|
|
345
|
+
startPos = _ref2.startPos,
|
|
346
|
+
nodeType = _ref2.nodeType,
|
|
347
|
+
range = _ref2.range,
|
|
348
|
+
api = _ref2.api;
|
|
349
|
+
if (range && shouldExpandSelection(range, startPos)) {
|
|
350
|
+
var expandedSelection = createExpandedSelection(tr.doc, selection, range);
|
|
351
|
+
if (!expandedSelection.eq(tr.selection)) {
|
|
352
|
+
tr.setSelection(expandedSelection);
|
|
353
|
+
}
|
|
354
|
+
return tr;
|
|
355
|
+
}
|
|
356
|
+
var node = tr.doc.nodeAt(startPos);
|
|
357
|
+
var isEmptyNode = (node === null || node === void 0 ? void 0 : node.content.size) === 0;
|
|
358
|
+
if (isEmptyNode && node.type.name !== 'paragraph') {
|
|
359
|
+
tr.setSelection(new _state.NodeSelection(tr.doc.resolve(startPos)));
|
|
360
|
+
return tr;
|
|
361
|
+
}
|
|
362
|
+
return (0, _getSelection.selectNode)(tr, startPos, nodeType, api);
|
|
363
|
+
};
|
|
364
|
+
var DragHandle = exports.DragHandle = function DragHandle(_ref3) {
|
|
365
|
+
var _api$core4;
|
|
366
|
+
var view = _ref3.view,
|
|
367
|
+
api = _ref3.api,
|
|
368
|
+
formatMessage = _ref3.formatMessage,
|
|
369
|
+
getPos = _ref3.getPos,
|
|
370
|
+
anchorName = _ref3.anchorName,
|
|
371
|
+
nodeType = _ref3.nodeType,
|
|
372
|
+
handleOptions = _ref3.handleOptions,
|
|
373
|
+
_ref3$isTopLevelNode = _ref3.isTopLevelNode,
|
|
374
|
+
isTopLevelNode = _ref3$isTopLevelNode === void 0 ? true : _ref3$isTopLevelNode,
|
|
375
|
+
anchorRectCache = _ref3.anchorRectCache;
|
|
310
376
|
var buttonRef = (0, _react.useRef)(null);
|
|
311
377
|
var _useState = (0, _react.useState)(false),
|
|
312
378
|
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
@@ -367,14 +433,69 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
367
433
|
}
|
|
368
434
|
}
|
|
369
435
|
}, [anchorName, nodeType, view.dom]);
|
|
370
|
-
var
|
|
436
|
+
var handleOnClickNew = (0, _react.useCallback)(function (e) {
|
|
371
437
|
var _api$core;
|
|
438
|
+
api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref4) {
|
|
439
|
+
var _api$analytics, _resolvedStartPos$nod, _selectionPreservatio, _api$blockControls, _api$blockControls2;
|
|
440
|
+
var tr = _ref4.tr;
|
|
441
|
+
var startPos = getPos();
|
|
442
|
+
if (startPos === undefined) {
|
|
443
|
+
return tr;
|
|
444
|
+
}
|
|
445
|
+
var resolvedStartPos = tr.doc.resolve(startPos);
|
|
446
|
+
api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
|
|
447
|
+
eventType: _analytics.EVENT_TYPE.UI,
|
|
448
|
+
action: _analytics.ACTION.CLICKED,
|
|
449
|
+
actionSubject: _analytics.ACTION_SUBJECT.BUTTON,
|
|
450
|
+
actionSubjectId: _analytics.ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE,
|
|
451
|
+
attributes: {
|
|
452
|
+
nodeDepth: resolvedStartPos.depth,
|
|
453
|
+
nodeType: ((_resolvedStartPos$nod = resolvedStartPos.nodeAfter) === null || _resolvedStartPos$nod === void 0 ? void 0 : _resolvedStartPos$nod.type.name) || ''
|
|
454
|
+
}
|
|
455
|
+
})(tr);
|
|
456
|
+
var preservedSelection = (_selectionPreservatio = _pluginKey.selectionPreservationPluginKey.getState(view.state)) === null || _selectionPreservatio === void 0 ? void 0 : _selectionPreservatio.preservedSelection;
|
|
457
|
+
var selection = preservedSelection || tr.selection;
|
|
458
|
+
var range = calculateBlockRange({
|
|
459
|
+
doc: tr.doc,
|
|
460
|
+
selection: selection,
|
|
461
|
+
resolvedStartPos: resolvedStartPos,
|
|
462
|
+
isShiftPressed: e.shiftKey
|
|
463
|
+
});
|
|
464
|
+
tr = createSelectionFromRange({
|
|
465
|
+
tr: tr,
|
|
466
|
+
selection: selection,
|
|
467
|
+
startPos: startPos,
|
|
468
|
+
nodeType: nodeType,
|
|
469
|
+
range: range,
|
|
470
|
+
api: api
|
|
471
|
+
});
|
|
472
|
+
api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.startPreservingSelection()({
|
|
473
|
+
tr: tr
|
|
474
|
+
});
|
|
475
|
+
api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.toggleBlockMenu({
|
|
476
|
+
anchorName: anchorName,
|
|
477
|
+
openedViaKeyboard: false,
|
|
478
|
+
triggerByNode: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_synced_block', 'isEnabled', true) ? {
|
|
479
|
+
nodeType: nodeType,
|
|
480
|
+
pos: startPos,
|
|
481
|
+
rootPos: tr.doc.resolve(startPos).before(1)
|
|
482
|
+
} : undefined
|
|
483
|
+
})({
|
|
484
|
+
tr: tr
|
|
485
|
+
});
|
|
486
|
+
tr.setMeta('scrollIntoView', false);
|
|
487
|
+
return tr;
|
|
488
|
+
});
|
|
489
|
+
view.focus();
|
|
490
|
+
}, [api, view, getPos, nodeType, anchorName]);
|
|
491
|
+
var handleOnClick = (0, _react.useCallback)(function (e) {
|
|
492
|
+
var _api$core2;
|
|
372
493
|
if (!isMultiSelect) {
|
|
373
494
|
setDragHandleSelected(!dragHandleSelected);
|
|
374
495
|
}
|
|
375
|
-
api === null || api === void 0 || (_api$
|
|
376
|
-
var _api$blockControls$sh, _api$
|
|
377
|
-
var tr =
|
|
496
|
+
api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(function (_ref5) {
|
|
497
|
+
var _api$blockControls$sh, _api$analytics2;
|
|
498
|
+
var tr = _ref5.tr;
|
|
378
499
|
var startPos = getPos();
|
|
379
500
|
if (startPos === undefined) {
|
|
380
501
|
return tr;
|
|
@@ -403,8 +524,8 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
403
524
|
rootPos: rootPos
|
|
404
525
|
} : undefined;
|
|
405
526
|
if (_consts2.BLOCK_MENU_ENABLED && (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) {
|
|
406
|
-
var _api$
|
|
407
|
-
api === null || api === void 0 || (_api$
|
|
527
|
+
var _api$blockControls3;
|
|
528
|
+
api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || _api$blockControls3.commands.toggleBlockMenu({
|
|
408
529
|
anchorName: anchorName,
|
|
409
530
|
triggerByNode: triggerByNode,
|
|
410
531
|
openedViaKeyboard: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? false : undefined
|
|
@@ -413,8 +534,8 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
413
534
|
});
|
|
414
535
|
e.stopPropagation();
|
|
415
536
|
} else if ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true)) {
|
|
416
|
-
var _api$
|
|
417
|
-
api === null || api === void 0 || (_api$
|
|
537
|
+
var _api$blockControls4;
|
|
538
|
+
api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 || _api$blockControls4.commands.toggleBlockMenu({
|
|
418
539
|
anchorName: anchorName,
|
|
419
540
|
triggerByNode: triggerByNode,
|
|
420
541
|
openedViaKeyboard: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? false : undefined
|
|
@@ -424,18 +545,18 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
424
545
|
e.stopPropagation();
|
|
425
546
|
}
|
|
426
547
|
} else if (isTopLevelNode && $anchor.depth <= _consts2.DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH && e.shiftKey && (0, _platformFeatureFlags.fg)('platform_editor_elements_dnd_shift_click_select')) {
|
|
427
|
-
var _api$
|
|
428
|
-
var alignAnchorHeadToSel = (0,
|
|
429
|
-
var selectionWithExpandedHead = (0,
|
|
548
|
+
var _api$blockControls5;
|
|
549
|
+
var alignAnchorHeadToSel = (0, _selection3.alignAnchorHeadInDirectionOfPos)(tr.selection, startPos);
|
|
550
|
+
var selectionWithExpandedHead = (0, _selection3.expandSelectionHeadToNodeAtPos)(alignAnchorHeadToSel, startPos);
|
|
430
551
|
tr.setSelection(selectionWithExpandedHead);
|
|
431
|
-
api === null || api === void 0 || (_api$
|
|
552
|
+
api === null || api === void 0 || (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 || _api$blockControls5.commands.setMultiSelectPositions()({
|
|
432
553
|
tr: tr
|
|
433
554
|
});
|
|
434
555
|
}
|
|
435
556
|
var resolvedMovingNode = tr.doc.resolve(startPos);
|
|
436
557
|
var maybeNode = resolvedMovingNode.nodeAfter;
|
|
437
558
|
tr.setMeta('scrollIntoView', false);
|
|
438
|
-
api === null || api === void 0 || (_api$
|
|
559
|
+
api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.attachAnalyticsEvent({
|
|
439
560
|
eventType: _analytics.EVENT_TYPE.UI,
|
|
440
561
|
action: _analytics.ACTION.CLICKED,
|
|
441
562
|
actionSubject: _analytics.ACTION_SUBJECT.BUTTON,
|
|
@@ -452,10 +573,10 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
452
573
|
var handleKeyDown = (0, _react.useCallback)(function (e) {
|
|
453
574
|
// allow user to use spacebar to select the node
|
|
454
575
|
if (!e.repeat && e.key === ' ') {
|
|
455
|
-
var _api$
|
|
576
|
+
var _api$core3;
|
|
456
577
|
var startPos = getPos();
|
|
457
|
-
api === null || api === void 0 || (_api$
|
|
458
|
-
var tr =
|
|
578
|
+
api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref6) {
|
|
579
|
+
var tr = _ref6.tr;
|
|
459
580
|
if (startPos === undefined) {
|
|
460
581
|
return tr;
|
|
461
582
|
}
|
|
@@ -478,20 +599,20 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
478
599
|
// return focus to editor to resume editing from caret position
|
|
479
600
|
view.focus();
|
|
480
601
|
}
|
|
481
|
-
}, [getPos, api === null || api === void 0 || (_api$
|
|
602
|
+
}, [getPos, api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, isMultiSelect, view]);
|
|
482
603
|
var handleKeyDownNew = (0, _react.useCallback)(function (e) {
|
|
483
604
|
// allow user to use spacebar to select the node
|
|
484
605
|
if (e.key === 'Enter' || !e.repeat && e.key === ' ') {
|
|
485
|
-
var _api$
|
|
486
|
-
if (
|
|
606
|
+
var _getDocument, _api$core5;
|
|
607
|
+
if (((_getDocument = (0, _browserApis.getDocument)()) === null || _getDocument === void 0 ? void 0 : _getDocument.activeElement) !== buttonRef.current) {
|
|
487
608
|
return;
|
|
488
609
|
}
|
|
489
610
|
e.preventDefault();
|
|
490
611
|
e.stopPropagation();
|
|
491
612
|
var startPos = getPos();
|
|
492
|
-
api === null || api === void 0 || (_api$
|
|
493
|
-
var _api$
|
|
494
|
-
var tr =
|
|
613
|
+
api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref7) {
|
|
614
|
+
var _api$blockControls6, _api$userIntent;
|
|
615
|
+
var tr = _ref7.tr;
|
|
495
616
|
if (startPos === undefined) {
|
|
496
617
|
return tr;
|
|
497
618
|
}
|
|
@@ -505,7 +626,7 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
505
626
|
pos: startPos,
|
|
506
627
|
rootPos: rootPos
|
|
507
628
|
} : undefined;
|
|
508
|
-
api === null || api === void 0 || (_api$
|
|
629
|
+
api === null || api === void 0 || (_api$blockControls6 = api.blockControls) === null || _api$blockControls6 === void 0 || _api$blockControls6.commands.toggleBlockMenu({
|
|
509
630
|
anchorName: anchorName,
|
|
510
631
|
triggerByNode: triggerByNode,
|
|
511
632
|
openedViaKeyboard: true
|
|
@@ -517,6 +638,20 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
517
638
|
});
|
|
518
639
|
return tr;
|
|
519
640
|
});
|
|
641
|
+
} else if (e.key === 'Backspace' || e.key === 'Delete') {
|
|
642
|
+
e.preventDefault();
|
|
643
|
+
e.stopPropagation();
|
|
644
|
+
api === null || api === void 0 || api.core.actions.execute(function (_ref8) {
|
|
645
|
+
var _api$blockControls7;
|
|
646
|
+
var tr = _ref8.tr;
|
|
647
|
+
(0, _selection2.deleteSelectedRange)(tr);
|
|
648
|
+
api === null || api === void 0 || (_api$blockControls7 = api.blockControls) === null || _api$blockControls7 === void 0 || _api$blockControls7.commands.toggleBlockMenu({
|
|
649
|
+
closeMenu: true
|
|
650
|
+
})({
|
|
651
|
+
tr: tr
|
|
652
|
+
});
|
|
653
|
+
return tr;
|
|
654
|
+
});
|
|
520
655
|
} else if (![e.altKey, e.ctrlKey, e.shiftKey].some(function (pressed) {
|
|
521
656
|
return pressed;
|
|
522
657
|
})) {
|
|
@@ -538,21 +673,21 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
538
673
|
start: start
|
|
539
674
|
};
|
|
540
675
|
},
|
|
541
|
-
onGenerateDragPreview: function onGenerateDragPreview(
|
|
676
|
+
onGenerateDragPreview: function onGenerateDragPreview(_ref9) {
|
|
542
677
|
var _api$blockControls$sh2;
|
|
543
|
-
var nativeSetDragImage =
|
|
678
|
+
var nativeSetDragImage = _ref9.nativeSetDragImage;
|
|
544
679
|
if (isMultiSelect) {
|
|
545
|
-
var _api$
|
|
546
|
-
api === null || api === void 0 || (_api$
|
|
547
|
-
var tr =
|
|
680
|
+
var _api$core6;
|
|
681
|
+
api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 || _api$core6.actions.execute(function (_ref0) {
|
|
682
|
+
var tr = _ref0.tr;
|
|
548
683
|
var handlePos = getPos();
|
|
549
684
|
if (typeof handlePos !== 'number') {
|
|
550
685
|
return tr;
|
|
551
686
|
}
|
|
552
687
|
var newHandlePosCheck = (0, _getSelection.isHandleCorrelatedToSelection)(view.state, tr.selection, handlePos);
|
|
553
688
|
if (!tr.selection.empty && newHandlePosCheck) {
|
|
554
|
-
var _api$
|
|
555
|
-
api === null || api === void 0 || (_api$
|
|
689
|
+
var _api$blockControls8;
|
|
690
|
+
api === null || api === void 0 || (_api$blockControls8 = api.blockControls) === null || _api$blockControls8 === void 0 || _api$blockControls8.commands.setMultiSelectPositions()({
|
|
556
691
|
tr: tr
|
|
557
692
|
});
|
|
558
693
|
} else if ((0, _platformFeatureFlags.fg)('platform_editor_elements_dnd_select_node_on_drag')) {
|
|
@@ -622,8 +757,8 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
622
757
|
};
|
|
623
758
|
}
|
|
624
759
|
},
|
|
625
|
-
render: function render(
|
|
626
|
-
var container =
|
|
760
|
+
render: function render(_ref1) {
|
|
761
|
+
var container = _ref1.container;
|
|
627
762
|
var dom = view.dom.querySelector("[".concat((0, _domAttrName.getAnchorAttrName)(), "=\"").concat(anchorName, "\"]"));
|
|
628
763
|
if (!dom) {
|
|
629
764
|
return;
|
|
@@ -655,13 +790,13 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
655
790
|
});
|
|
656
791
|
},
|
|
657
792
|
onDragStart: function onDragStart() {
|
|
658
|
-
var _api$
|
|
793
|
+
var _api$core7;
|
|
659
794
|
if (start === undefined) {
|
|
660
795
|
return;
|
|
661
796
|
}
|
|
662
|
-
api === null || api === void 0 || (_api$
|
|
663
|
-
var _api$blockControls$sh3, _api$
|
|
664
|
-
var tr =
|
|
797
|
+
api === null || api === void 0 || (_api$core7 = api.core) === null || _api$core7 === void 0 || _api$core7.actions.execute(function (_ref10) {
|
|
798
|
+
var _api$blockControls$sh3, _api$blockControls9, _api$analytics3;
|
|
799
|
+
var tr = _ref10.tr;
|
|
665
800
|
var nodeTypes, hasSelectedMultipleNodes;
|
|
666
801
|
var resolvedMovingNode = tr.doc.resolve(start);
|
|
667
802
|
var maybeNode = resolvedMovingNode.nodeAfter;
|
|
@@ -674,11 +809,11 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
674
809
|
nodeTypes = maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name;
|
|
675
810
|
hasSelectedMultipleNodes = false;
|
|
676
811
|
}
|
|
677
|
-
api === null || api === void 0 || (_api$
|
|
812
|
+
api === null || api === void 0 || (_api$blockControls9 = api.blockControls) === null || _api$blockControls9 === void 0 || _api$blockControls9.commands.setNodeDragged(getPos, anchorName, nodeType)({
|
|
678
813
|
tr: tr
|
|
679
814
|
});
|
|
680
815
|
tr.setMeta('scrollIntoView', false);
|
|
681
|
-
api === null || api === void 0 || (_api$
|
|
816
|
+
api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.attachAnalyticsEvent({
|
|
682
817
|
eventType: _analytics.EVENT_TYPE.UI,
|
|
683
818
|
action: _analytics.ACTION.DRAGGED,
|
|
684
819
|
actionSubject: _analytics.ACTION_SUBJECT.ELEMENT,
|
|
@@ -972,7 +1107,7 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
972
1107
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
|
|
973
1108
|
,
|
|
974
1109
|
style: !(0, _experiments.editorExperiment)('platform_editor_controls', 'variant1') ? (0, _experiments.editorExperiment)('platform_editor_block_control_optimise_render', true) ? positionStyles : positionStylesOld : {},
|
|
975
|
-
onClick: handleOnClick,
|
|
1110
|
+
onClick: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true) ? handleOnClickNew : handleOnClick,
|
|
976
1111
|
onKeyDown: (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu', 'isEnabled', true) && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? handleKeyDownNew : handleKeyDown
|
|
977
1112
|
// eslint-disable-next-line @atlaskit/design-system/no-direct-use-of-web-platform-drag-and-drop
|
|
978
1113
|
,
|
|
@@ -1057,15 +1192,15 @@ var DragHandle = exports.DragHandle = function DragHandle(_ref) {
|
|
|
1057
1192
|
var render = isTooltip ? buttonWithTooltip() : renderButton();
|
|
1058
1193
|
return (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1') ? stickyRender : render;
|
|
1059
1194
|
};
|
|
1060
|
-
var DragHandleWithVisibility = exports.DragHandleWithVisibility = function DragHandleWithVisibility(
|
|
1061
|
-
var view =
|
|
1062
|
-
api =
|
|
1063
|
-
formatMessage =
|
|
1064
|
-
getPos =
|
|
1065
|
-
anchorName =
|
|
1066
|
-
nodeType =
|
|
1067
|
-
handleOptions =
|
|
1068
|
-
anchorRectCache =
|
|
1195
|
+
var DragHandleWithVisibility = exports.DragHandleWithVisibility = function DragHandleWithVisibility(_ref11) {
|
|
1196
|
+
var view = _ref11.view,
|
|
1197
|
+
api = _ref11.api,
|
|
1198
|
+
formatMessage = _ref11.formatMessage,
|
|
1199
|
+
getPos = _ref11.getPos,
|
|
1200
|
+
anchorName = _ref11.anchorName,
|
|
1201
|
+
nodeType = _ref11.nodeType,
|
|
1202
|
+
handleOptions = _ref11.handleOptions,
|
|
1203
|
+
anchorRectCache = _ref11.anchorRectCache;
|
|
1069
1204
|
return (0, _react2.jsx)(_visibilityContainer.VisibilityContainer, {
|
|
1070
1205
|
api: api
|
|
1071
1206
|
}, (0, _react2.jsx)(DragHandle, {
|
|
@@ -12,6 +12,8 @@ import { canMoveNodeUpOrDown } from './editor-commands/utils/move-node-utils';
|
|
|
12
12
|
import { firstNodeDecPlugin } from './pm-plugins/first-node-dec-plugin';
|
|
13
13
|
import { createInteractionTrackingPlugin, interactionTrackingPluginKey } from './pm-plugins/interaction-tracking/pm-plugin';
|
|
14
14
|
import { createPlugin, key } from './pm-plugins/main';
|
|
15
|
+
import { startPreservingSelection, stopPreservingSelection } from './pm-plugins/selection-preservation/editor-commands';
|
|
16
|
+
import { createSelectionPreservationPlugin } from './pm-plugins/selection-preservation/pm-plugin';
|
|
15
17
|
import { selectNode } from './pm-plugins/utils/getSelection';
|
|
16
18
|
import BlockMenu from './ui/block-menu';
|
|
17
19
|
import { DragHandleMenu } from './ui/drag-handle-menu';
|
|
@@ -34,6 +36,12 @@ export const blockControlsPlugin = ({
|
|
|
34
36
|
plugin: createInteractionTrackingPlugin
|
|
35
37
|
});
|
|
36
38
|
}
|
|
39
|
+
if (expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true)) {
|
|
40
|
+
pmPlugins.push({
|
|
41
|
+
name: 'blockControlsSelectionPreservationPlugin',
|
|
42
|
+
plugin: createSelectionPreservationPlugin
|
|
43
|
+
});
|
|
44
|
+
}
|
|
37
45
|
|
|
38
46
|
// platform_editor_controls note: quick insert rendering fixes
|
|
39
47
|
if (areToolbarFlagsEnabled(Boolean(api === null || api === void 0 ? void 0 : api.toolbar))) {
|
|
@@ -233,7 +241,9 @@ export const blockControlsPlugin = ({
|
|
|
233
241
|
},
|
|
234
242
|
moveNodeWithBlockMenu: direction => {
|
|
235
243
|
return moveNodeWithBlockMenu(api, direction);
|
|
236
|
-
}
|
|
244
|
+
},
|
|
245
|
+
startPreservingSelection: () => startPreservingSelection,
|
|
246
|
+
stopPreservingSelection: () => stopPreservingSelection
|
|
237
247
|
},
|
|
238
248
|
getSharedState(editorState) {
|
|
239
249
|
var _key$getState$isMenuO, _key$getState, _key$getState$menuTri, _key$getState2, _key$getState$menuTri2, _key$getState3, _key$getState$blockMe, _key$getState4, _key$getState$activeN, _key$getState5, _key$getState$activeD, _key$getState6, _key$getState$isDragg, _key$getState7, _key$getState$isPMDra, _key$getState8, _key$getState$multiSe, _key$getState9, _key$getState$isShift, _key$getState0, _key$getState$lastDra, _key$getState1, _interactionTrackingP, _key$getState$isSelec, _key$getState10;
|
|
@@ -775,8 +775,11 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI) => {
|
|
|
775
775
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.setSelectedViaDragHandle(isDragHandle));
|
|
776
776
|
}
|
|
777
777
|
if ((event.key === 'ArrowLeft' || event.key === 'ArrowRight' || event.key === 'ArrowDown' || event.key === 'ArrowUp') && editorExperiment('platform_editor_controls', 'variant1')) {
|
|
778
|
-
var _api$blockControls$sh2;
|
|
779
|
-
|
|
778
|
+
var _api$blockControls$sh2, _api$blockControls$sh3;
|
|
779
|
+
const isBlockMenuOpen = (api === null || api === void 0 ? void 0 : (_api$blockControls$sh2 = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh2 === void 0 ? void 0 : _api$blockControls$sh2.isMenuOpen) && expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true) && expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true);
|
|
780
|
+
// when block menu is just open, and we press arrow keys, we want to use the arrow keys to navigate the block menu
|
|
781
|
+
// in this scenario, isSelectedViaDragHandle should not be set to false
|
|
782
|
+
if (api !== null && api !== void 0 && (_api$blockControls$sh3 = api.blockControls.sharedState.currentState()) !== null && _api$blockControls$sh3 !== void 0 && _api$blockControls$sh3.isSelectedViaDragHandle && !isBlockMenuOpen) {
|
|
780
783
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.setSelectedViaDragHandle(false));
|
|
781
784
|
}
|
|
782
785
|
}
|
|
@@ -800,8 +803,11 @@ export const createPlugin = (api, getIntl, nodeViewPortalProviderAPI) => {
|
|
|
800
803
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.setSelectedViaDragHandle(isDragHandle));
|
|
801
804
|
}
|
|
802
805
|
if ((event.key === 'ArrowLeft' || event.key === 'ArrowRight' || event.key === 'ArrowDown' || event.key === 'ArrowUp') && editorExperiment('platform_editor_controls', 'variant1')) {
|
|
803
|
-
var _api$blockControls$
|
|
804
|
-
|
|
806
|
+
var _api$blockControls$sh4, _api$blockControls$sh5;
|
|
807
|
+
const isBlockMenuOpen = (api === null || api === void 0 ? void 0 : (_api$blockControls$sh4 = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh4 === void 0 ? void 0 : _api$blockControls$sh4.isMenuOpen) && expValEqualsNoExposure('platform_editor_block_menu', 'isEnabled', true) && expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true);
|
|
808
|
+
// when block menu is just open, and we press arrow keys, we want to use the arrow keys to navigate the block menu
|
|
809
|
+
// in this scenario, isSelectedViaDragHandle should not be set to false
|
|
810
|
+
if (api !== null && api !== void 0 && (_api$blockControls$sh5 = api.blockControls.sharedState.currentState()) !== null && _api$blockControls$sh5 !== void 0 && _api$blockControls$sh5.isSelectedViaDragHandle && !isBlockMenuOpen) {
|
|
805
811
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : api.blockControls.commands.setSelectedViaDragHandle(false));
|
|
806
812
|
}
|
|
807
813
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { selectionPreservationPluginKey } from './plugin-key';
|
|
2
|
+
/**
|
|
3
|
+
* Start preserving the selection when a UI interaction requires it
|
|
4
|
+
*
|
|
5
|
+
* e.g., block menu open, drag-and-drop in progress
|
|
6
|
+
*/
|
|
7
|
+
export const startPreservingSelection = ({
|
|
8
|
+
tr
|
|
9
|
+
}) => {
|
|
10
|
+
const meta = {
|
|
11
|
+
type: 'startPreserving'
|
|
12
|
+
};
|
|
13
|
+
return tr.setMeta(selectionPreservationPluginKey, meta);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Stop preserving the selection when a UI interaction completes
|
|
18
|
+
*
|
|
19
|
+
* e.g., block menu closed, drag-and-drop ended
|
|
20
|
+
*/
|
|
21
|
+
export const stopPreservingSelection = ({
|
|
22
|
+
tr
|
|
23
|
+
}) => {
|
|
24
|
+
const meta = {
|
|
25
|
+
type: 'stopPreserving'
|
|
26
|
+
};
|
|
27
|
+
return tr.setMeta(selectionPreservationPluginKey, meta);
|
|
28
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
2
|
+
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
3
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
4
|
+
import { stopPreservingSelection } from './editor-commands';
|
|
5
|
+
import { selectionPreservationPluginKey } from './plugin-key';
|
|
6
|
+
import { getSelectionPreservationMeta, hasUserSelectionChange } from './utils';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Selection Preservation Plugin for ProseMirror Editor
|
|
10
|
+
*
|
|
11
|
+
* Solves a ProseMirror limitation where TextSelection cannot include positions at node boundaries
|
|
12
|
+
* (like media/images). When a selection spans text + media nodes, subsequent transactions cause
|
|
13
|
+
* ProseMirror to collapse the selection to the nearest inline position, excluding the media node.
|
|
14
|
+
* This is problematic for features like block menus and drag-and-drop that need stable multi-node
|
|
15
|
+
* selections while performing operations.
|
|
16
|
+
*
|
|
17
|
+
* The plugin works in three phases:
|
|
18
|
+
* (1) Explicitly save a selection via startPreservingSelection() when opening block menus or starting drag operations.
|
|
19
|
+
* (2) Map the saved selection through document changes to keep positions valid.
|
|
20
|
+
* (3) Detect when transactions collapse the selection and restore it via appendTransaction().
|
|
21
|
+
*
|
|
22
|
+
* Stops preserving via stopPreservingSelection() when the menu closes or operation completes.
|
|
23
|
+
*
|
|
24
|
+
* Commands: startPreservingSelection() to begin preservation, stopPreservingSelection() to end it.
|
|
25
|
+
*
|
|
26
|
+
* NOTE: Only use when the UI blocks user selection changes. For example: when a block menu overlay
|
|
27
|
+
* is open (editor becomes non-interactive), during drag-and-drop operations (user is mid-drag), or
|
|
28
|
+
* when modal dialogs are active. In these states, any selection changes are from ProseMirror's
|
|
29
|
+
* internal behavior (not user input) and should be prevented. Do not use during normal editing.
|
|
30
|
+
*/
|
|
31
|
+
export const createSelectionPreservationPlugin = () => {
|
|
32
|
+
return new SafePlugin({
|
|
33
|
+
key: selectionPreservationPluginKey,
|
|
34
|
+
state: {
|
|
35
|
+
init() {
|
|
36
|
+
return {
|
|
37
|
+
preservedSelection: undefined
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
apply(tr, pluginState) {
|
|
41
|
+
const meta = getSelectionPreservationMeta(tr);
|
|
42
|
+
const newState = {
|
|
43
|
+
...pluginState
|
|
44
|
+
};
|
|
45
|
+
if ((meta === null || meta === void 0 ? void 0 : meta.type) === 'startPreserving') {
|
|
46
|
+
newState.preservedSelection = new TextSelection(tr.selection.$from, tr.selection.$to);
|
|
47
|
+
} else if ((meta === null || meta === void 0 ? void 0 : meta.type) === 'stopPreserving') {
|
|
48
|
+
newState.preservedSelection = undefined;
|
|
49
|
+
}
|
|
50
|
+
if (newState.preservedSelection && tr.docChanged) {
|
|
51
|
+
const mapped = new TextSelection(newState.preservedSelection.$from, newState.preservedSelection.$to);
|
|
52
|
+
mapped.map(tr.doc, tr.mapping);
|
|
53
|
+
if (mapped.from >= 0 && mapped.to <= tr.doc.content.size && mapped.from !== mapped.to) {
|
|
54
|
+
newState.preservedSelection = mapped;
|
|
55
|
+
} else if (mapped.from === mapped.to) {
|
|
56
|
+
// If selection has collapsed to a cursor, e.g. after deleting the selection, stop preserving
|
|
57
|
+
newState.preservedSelection = undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return newState;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
appendTransaction(transactions, _oldState, newState) {
|
|
64
|
+
const pluginState = selectionPreservationPluginKey.getState(newState);
|
|
65
|
+
const savedSel = pluginState === null || pluginState === void 0 ? void 0 : pluginState.preservedSelection;
|
|
66
|
+
if (!savedSel) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
if (hasUserSelectionChange(transactions)) {
|
|
70
|
+
// Auto-stop if user explicitly changes selection
|
|
71
|
+
return stopPreservingSelection({
|
|
72
|
+
tr: newState.tr
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const currSel = newState.selection;
|
|
76
|
+
const wasEmptySelection = savedSel.from === savedSel.to;
|
|
77
|
+
const selectionUnchanged = currSel.from === savedSel.from && currSel.to === savedSel.to;
|
|
78
|
+
const selectionInvalid = savedSel.from < 0 || savedSel.to > newState.doc.content.size;
|
|
79
|
+
if (wasEmptySelection || selectionUnchanged || selectionInvalid) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
return newState.tr.setSelection(TextSelection.create(newState.doc, savedSel.from, savedSel.to));
|
|
84
|
+
} catch (error) {
|
|
85
|
+
logException(error, {
|
|
86
|
+
location: 'editor-plugin-block-controls/SelectionPreservationPlugin'
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { selectionPreservationPluginKey } from './plugin-key';
|
|
2
|
+
/**
|
|
3
|
+
* Detects if any of the transactions include user-driven selection changes.
|
|
4
|
+
*
|
|
5
|
+
* @param transactions The list of transactions to check.
|
|
6
|
+
* @returns True if any transaction includes a user-driven selection change, otherwise false.
|
|
7
|
+
*/
|
|
8
|
+
export const hasUserSelectionChange = transactions => {
|
|
9
|
+
return transactions.some(tr => tr.getMeta('pointer') || tr.getMeta('uiEvent') || tr.getMeta('paste') || tr.getMeta('cut') || tr.getMeta('composition') ||
|
|
10
|
+
// IME input
|
|
11
|
+
// Keyboard events that change selection
|
|
12
|
+
tr.getMeta('addToHistory') && tr.selectionSet);
|
|
13
|
+
};
|
|
14
|
+
export const getSelectionPreservationMeta = tr => {
|
|
15
|
+
return tr.getMeta(selectionPreservationPluginKey);
|
|
16
|
+
};
|