@atlaskit/editor-plugin-block-controls 3.7.0 → 3.8.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.
Files changed (30) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/pm-plugins/decorations-drag-handle.js +3 -2
  3. package/dist/cjs/pm-plugins/decorations-quick-insert-button.js +3 -2
  4. package/dist/cjs/pm-plugins/main.js +2 -2
  5. package/dist/cjs/pm-plugins/utils/drag-handle-positions.js +25 -1
  6. package/dist/cjs/ui/drag-handle.js +115 -21
  7. package/dist/cjs/ui/quick-insert-button.js +80 -18
  8. package/dist/es2019/pm-plugins/decorations-drag-handle.js +3 -2
  9. package/dist/es2019/pm-plugins/decorations-quick-insert-button.js +3 -2
  10. package/dist/es2019/pm-plugins/main.js +2 -2
  11. package/dist/es2019/pm-plugins/utils/drag-handle-positions.js +22 -0
  12. package/dist/es2019/ui/drag-handle.js +100 -10
  13. package/dist/es2019/ui/quick-insert-button.js +86 -27
  14. package/dist/esm/pm-plugins/decorations-drag-handle.js +3 -2
  15. package/dist/esm/pm-plugins/decorations-quick-insert-button.js +3 -2
  16. package/dist/esm/pm-plugins/main.js +2 -2
  17. package/dist/esm/pm-plugins/utils/drag-handle-positions.js +24 -0
  18. package/dist/esm/ui/drag-handle.js +116 -22
  19. package/dist/esm/ui/quick-insert-button.js +81 -19
  20. package/dist/types/pm-plugins/decorations-drag-handle.d.ts +2 -1
  21. package/dist/types/pm-plugins/decorations-quick-insert-button.d.ts +2 -1
  22. package/dist/types/pm-plugins/utils/drag-handle-positions.d.ts +9 -0
  23. package/dist/types/ui/drag-handle.d.ts +4 -2
  24. package/dist/types/ui/quick-insert-button.d.ts +3 -1
  25. package/dist/types-ts4.5/pm-plugins/decorations-drag-handle.d.ts +2 -1
  26. package/dist/types-ts4.5/pm-plugins/decorations-quick-insert-button.d.ts +2 -1
  27. package/dist/types-ts4.5/pm-plugins/utils/drag-handle-positions.d.ts +9 -0
  28. package/dist/types-ts4.5/ui/drag-handle.d.ts +4 -2
  29. package/dist/types-ts4.5/ui/quick-insert-button.d.ts +3 -1
  30. package/package.json +6 -3
@@ -26,7 +26,7 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
26
26
  import Tooltip from '@atlaskit/tooltip';
27
27
  import { key } from '../pm-plugins/main';
28
28
  import { getMultiSelectAnalyticsAttributes } from '../pm-plugins/utils/analytics';
29
- import { getLeftPosition, getTopPosition } from '../pm-plugins/utils/drag-handle-positions';
29
+ import { getControlBottomCSSValue, getControlHeightCSSValue, getLeftPosition, getNodeHeight, getTopPosition, shouldBeSticky } from '../pm-plugins/utils/drag-handle-positions';
30
30
  import { isHandleCorrelatedToSelection, selectNode } from '../pm-plugins/utils/getSelection';
31
31
  import { alignAnchorHeadInDirectionOfPos, expandSelectionHeadToNodeAtPos } from '../pm-plugins/utils/selection';
32
32
  import { BLOCK_MENU_ENABLED, DRAG_HANDLE_BORDER_RADIUS, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH, DRAG_HANDLE_WIDTH, DRAG_HANDLE_ZINDEX, dragHandleGap, nodeMargins, spacingBetweenNodesForPreview, topPositionAdjustment } from './consts';
@@ -42,6 +42,43 @@ const dragHandleColor = css({
42
42
  color: "var(--ds-icon-subtle, #626F86)"
43
43
  });
44
44
  const dragHandleButtonStyles = css({
45
+ display: 'flex',
46
+ boxSizing: 'border-box',
47
+ flexDirection: 'column',
48
+ justifyContent: 'center',
49
+ alignItems: 'center',
50
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
51
+ height: DRAG_HANDLE_HEIGHT,
52
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
53
+ width: DRAG_HANDLE_WIDTH,
54
+ border: 'none',
55
+ background: 'transparent',
56
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
57
+ borderRadius: DRAG_HANDLE_BORDER_RADIUS,
58
+ // when platform_editor_controls is enabled, the drag handle color is overridden. Update color here when experiment is cleaned up.
59
+ color: "var(--ds-icon, #44546F)",
60
+ cursor: 'grab',
61
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
62
+ zIndex: DRAG_HANDLE_ZINDEX,
63
+ outline: 'none',
64
+ '&:hover': {
65
+ backgroundColor: "var(--ds-background-neutral-subtle-hovered, #091E420F)"
66
+ },
67
+ '&:active': {
68
+ backgroundColor: "var(--ds-background-neutral-subtle-pressed, #091E4224)"
69
+ },
70
+ '&:focus': {
71
+ outline: `2px solid ${"var(--ds-border-focused, #388BFF)"}`
72
+ },
73
+ '&:disabled': {
74
+ color: "var(--ds-icon-disabled, #8993A4)",
75
+ backgroundColor: 'transparent'
76
+ },
77
+ '&:hover:disabled': {
78
+ backgroundColor: "var(--ds-background-disabled, transparent)"
79
+ }
80
+ });
81
+ const dragHandleButtonStylesOld = css({
45
82
  position: 'absolute',
46
83
  padding: `${"var(--ds-space-025, 2px)"} 0`,
47
84
  boxSizing: 'border-box',
@@ -80,6 +117,16 @@ const dragHandleButtonStyles = css({
80
117
  backgroundColor: "var(--ds-background-disabled, transparent)"
81
118
  }
82
119
  });
120
+ const dragHandleContainerStyles = xcss({
121
+ position: 'absolute',
122
+ boxSizing: 'border-box',
123
+ zIndex: 'card'
124
+ });
125
+ const controlContainerStyles = xcss({
126
+ top: '0',
127
+ position: 'sticky',
128
+ zIndex: 'card'
129
+ });
83
130
  const dragHandleMultiLineSelectionFixFirefox = css({
84
131
  '&::selection': {
85
132
  backgroundColor: 'transparent'
@@ -141,7 +188,8 @@ export const DragHandle = ({
141
188
  anchorName,
142
189
  nodeType,
143
190
  handleOptions,
144
- isTopLevelNode = true
191
+ isTopLevelNode = true,
192
+ anchorRectCache
145
193
  }) => {
146
194
  var _api$core2, _api$blockControls3, _api$analytics2, _api$core4;
147
195
  const start = getPos();
@@ -479,17 +527,22 @@ export const DragHandle = ({
479
527
  }
480
528
  }
481
529
  const isEdgeCase = (hasResizer || isExtension || isEmbedCard || isBlockCard) && innerContainer;
530
+ const isSticky = shouldBeSticky(nodeType);
482
531
  if (supportsAnchor) {
532
+ const bottom = fg('platform_editor_controls_sticky_controls') ? getControlBottomCSSValue(anchorName, isSticky, isTopLevelNode, isLayoutColumn) : {};
483
533
  return {
484
534
  left: isEdgeCase ? `calc(anchor(${anchorName} start) + ${getLeftPosition(dom, nodeType, innerContainer, isMacroInteractionUpdates, parentNodeType)})` : editorExperiment('advanced_layouts', true) && isLayoutColumn ? `calc((anchor(${anchorName} right) + anchor(${anchorName} left))/2 - ${DRAG_HANDLE_HEIGHT / 2}px)` : `calc(anchor(${anchorName} start) - ${DRAG_HANDLE_WIDTH}px - ${dragHandleGap(nodeType, parentNodeType)}px)`,
485
- top: editorExperiment('advanced_layouts', true) && isLayoutColumn ? `calc(anchor(${anchorName} top) - ${DRAG_HANDLE_WIDTH}px)` : `calc(anchor(${anchorName} start) + ${topPositionAdjustment(nodeType)}px)`
535
+ top: editorExperiment('advanced_layouts', true) && isLayoutColumn ? `calc(anchor(${anchorName} top) - ${DRAG_HANDLE_WIDTH}px)` : `calc(anchor(${anchorName} start) + ${topPositionAdjustment(nodeType)}px)`,
536
+ ...bottom
486
537
  };
487
538
  }
539
+ const height = fg('platform_editor_controls_sticky_controls') ? getControlHeightCSSValue(getNodeHeight(dom, anchorName, anchorRectCache) || 0, isSticky, isTopLevelNode, `${DRAG_HANDLE_HEIGHT}`, isLayoutColumn) : {};
488
540
  return {
489
541
  left: isEdgeCase ? `calc(${(dom === null || dom === void 0 ? void 0 : dom.offsetLeft) || 0}px + ${getLeftPosition(dom, nodeType, innerContainer, isMacroInteractionUpdates, parentNodeType)})` : getLeftPosition(dom, nodeType, innerContainer, isMacroInteractionUpdates, parentNodeType),
490
- top: getTopPosition(dom, nodeType)
542
+ top: getTopPosition(dom, nodeType),
543
+ ...height
491
544
  };
492
- }, [anchorName, nodeType, view, blockCardWidth, macroInteractionUpdates, getPos, isLayoutColumn]);
545
+ }, [anchorName, view.dom, view.state.doc, nodeType, blockCardWidth, macroInteractionUpdates, isTopLevelNode, isLayoutColumn, getPos, anchorRectCache]);
493
546
  const [positionStyles, setPositionStyles] = useState({
494
547
  display: 'none'
495
548
  });
@@ -622,14 +675,14 @@ export const DragHandle = ({
622
675
  // eslint-disable-next-line @atlaskit/design-system/no-html-button
623
676
  jsx("button", {
624
677
  type: "button",
625
- css: [dragHandleButtonStyles, editorExperiment('platform_editor_controls', 'variant1') && dragHandleColor,
678
+ css: [fg('platform_editor_controls_sticky_controls') ? dragHandleButtonStyles : dragHandleButtonStylesOld, editorExperiment('platform_editor_controls', 'variant1') && dragHandleColor,
626
679
  // ED-26266: Fixed the drag handle highlight when selecting multiple line in Firefox
627
680
  // See https://product-fabric.atlassian.net/browse/ED-26266
628
681
  browser.gecko && fg('platform_editor_dnd_handle_highlight_fix_firefox') && dragHandleMultiLineSelectionFixFirefox, editorExperiment('advanced_layouts', true) && isLayoutColumn && layoutColumnDragHandleStyles, dragHandleSelected && selectedStyles],
629
682
  ref: buttonRef
630
683
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
631
684
  ,
632
- style: positionStyles,
685
+ style: !fg('platform_editor_controls_sticky_controls') && positionStyles || {},
633
686
  onClick: handleOnClick,
634
687
  onMouseDown: handleMouseDown,
635
688
  onKeyDown: handleKeyDown
@@ -651,17 +704,54 @@ export const DragHandle = ({
651
704
  LEGACY_fallbackIcon: DragHandlerIcon,
652
705
  LEGACY_size: "medium"
653
706
  })));
654
- return !dragHandleDisabled && fg('platform_editor_element_drag_and_drop_ed_23873') ? jsx(Tooltip, {
707
+ const stickyWithTooltip = () => jsx(Box
708
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
709
+ , {
710
+ style: positionStyles,
711
+ xcss: [dragHandleContainerStyles],
712
+ as: "span",
713
+ testId: "block-ctrl-drag-handle-container"
714
+ }, jsx(Box, {
715
+ xcss: [controlContainerStyles],
716
+ as: "span"
717
+ }, jsx(Tooltip, {
655
718
  content: jsx(TooltipContentWithMultipleShortcuts, {
656
719
  helpDescriptors: helpDescriptors
657
720
  }),
658
721
  ignoreTooltipPointerEvents: true,
659
- position: editorExperiment('platform_editor_controls', 'variant1') ? 'top' : undefined,
722
+ position: 'top',
660
723
  onShow: () => {
661
724
  var _api$accessibilityUti;
662
725
  api === null || api === void 0 ? void 0 : (_api$accessibilityUti = api.accessibilityUtils) === null || _api$accessibilityUti === void 0 ? void 0 : _api$accessibilityUti.actions.ariaNotify(message, {
663
726
  priority: 'important'
664
727
  });
665
728
  }
666
- }, renderButton()) : renderButton();
729
+ }, renderButton())));
730
+ const stickyWithoutTooltip = () => jsx(Box
731
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
732
+ , {
733
+ style: positionStyles,
734
+ xcss: [dragHandleContainerStyles],
735
+ as: "span",
736
+ testId: "block-ctrl-drag-handle-container"
737
+ }, jsx(Box, {
738
+ xcss: [controlContainerStyles],
739
+ as: "span"
740
+ }, renderButton()));
741
+ const buttonWithTooltip = () => jsx(Tooltip, {
742
+ content: jsx(TooltipContentWithMultipleShortcuts, {
743
+ helpDescriptors: helpDescriptors
744
+ }),
745
+ ignoreTooltipPointerEvents: true,
746
+ onShow: () => {
747
+ var _api$accessibilityUti2;
748
+ api === null || api === void 0 ? void 0 : (_api$accessibilityUti2 = api.accessibilityUtils) === null || _api$accessibilityUti2 === void 0 ? void 0 : _api$accessibilityUti2.actions.ariaNotify(message, {
749
+ priority: 'important'
750
+ });
751
+ }
752
+ }, renderButton());
753
+ const isTooltip = !dragHandleDisabled && fg('platform_editor_element_drag_and_drop_ed_23873');
754
+ const stickyRender = isTooltip ? stickyWithTooltip() : stickyWithoutTooltip();
755
+ const render = isTooltip ? buttonWithTooltip() : renderButton();
756
+ return fg('platform_editor_controls_sticky_controls') ? stickyRender : render;
667
757
  };
@@ -9,7 +9,7 @@ import AddIcon from '@atlaskit/icon/utility/add';
9
9
  import { fg } from '@atlaskit/platform-feature-flags';
10
10
  import { Box, Pressable, xcss } from '@atlaskit/primitives';
11
11
  import Tooltip from '@atlaskit/tooltip';
12
- import { getTopPosition } from '../pm-plugins/utils/drag-handle-positions';
12
+ import { getControlBottomCSSValue, getControlHeightCSSValue, getNodeHeight, getTopPosition, shouldBeSticky } from '../pm-plugins/utils/drag-handle-positions';
13
13
  import { getLeftPositionForRootElement } from '../pm-plugins/utils/widget-positions';
14
14
  import { rootElementGap, topPositionAdjustment, QUICK_INSERT_DIMENSIONS, QUICK_INSERT_LEFT_OFFSET } from './consts';
15
15
  import { isInTextSelection, isNestedNodeSelected, isNonEditableBlock, isSelectionInNode } from './utils/document-checks';
@@ -38,10 +38,52 @@ const buttonStyles = xcss({
38
38
  outline: `2px solid ${"var(--ds-border-focused, #388BFF)"}`
39
39
  }
40
40
  });
41
+ const disabledStyles = xcss({
42
+ pointerEvents: 'none',
43
+ ':hover': {
44
+ backgroundColor: 'color.background.disabled'
45
+ },
46
+ ':active': {
47
+ backgroundColor: 'color.background.disabled'
48
+ }
49
+ });
50
+ const stickyButtonStyles = xcss({
51
+ top: '0',
52
+ position: 'sticky',
53
+ boxSizing: 'border-box',
54
+ display: 'flex',
55
+ flexDirection: 'column',
56
+ justifyContent: 'center',
57
+ alignItems: 'center',
58
+ height: "var(--ds-space-300, 24px)",
59
+ width: "var(--ds-space-300, 24px)",
60
+ border: 'none',
61
+ backgroundColor: 'color.background.neutral.subtle',
62
+ borderRadius: '50%',
63
+ zIndex: 'card',
64
+ outline: 'none',
65
+ ':hover': {
66
+ backgroundColor: 'color.background.neutral.subtle.hovered'
67
+ },
68
+ ':active': {
69
+ backgroundColor: 'color.background.neutral.subtle.pressed'
70
+ },
71
+ ':focus': {
72
+ outline: `2px solid ${"var(--ds-border-focused, #388BFF)"}`
73
+ }
74
+ });
41
75
  const containerStaticStyles = xcss({
42
76
  position: 'absolute',
43
77
  zIndex: 'card'
44
78
  });
79
+ const disabledContainerStyles = xcss({
80
+ cursor: 'not-allowed'
81
+ });
82
+ const tooltipContainerStyles = xcss({
83
+ top: '0',
84
+ position: 'sticky',
85
+ zIndex: 'card'
86
+ });
45
87
 
46
88
  // TODO: ED-26959 - Share prop types between DragHandle - generic enough to create a type for block control decoration
47
89
 
@@ -50,10 +92,14 @@ export const TypeAheadControl = ({
50
92
  api,
51
93
  formatMessage,
52
94
  getPos,
95
+ nodeType,
96
+ anchorName,
53
97
  rootAnchorName,
54
- rootNodeType
98
+ rootNodeType,
99
+ anchorRectCache
55
100
  }) => {
56
101
  const macroInteractionUpdates = useSharedPluginStateSelector(api, 'featureFlags.macroInteractionUpdates');
102
+ const isTypeAheadOpen = useSharedPluginStateSelector(api, 'typeAhead.isOpen');
57
103
  const [positionStyles, setPositionStyles] = useState({
58
104
  display: 'none'
59
105
  });
@@ -85,17 +131,27 @@ export const TypeAheadControl = ({
85
131
  }
86
132
  }
87
133
  const isEdgeCase = (hasResizer || isExtension || isEmbedCard || isBlockCard) && innerContainer;
134
+ const isSticky = shouldBeSticky(rootNodeType);
135
+ const bottom = fg('platform_editor_controls_sticky_controls') ? getControlBottomCSSValue(rootAnchorName || anchorName, isSticky, true) : {};
88
136
  if (supportsAnchor) {
89
137
  return {
90
138
  left: isEdgeCase ? `calc(anchor(${rootAnchorName} start) + ${getLeftPositionForRootElement(dom, rootNodeType, QUICK_INSERT_DIMENSIONS, innerContainer, isMacroInteractionUpdates)} + -${QUICK_INSERT_LEFT_OFFSET}px)` : `calc(anchor(${rootAnchorName} start) - ${QUICK_INSERT_DIMENSIONS.width}px - ${rootElementGap(rootNodeType)}px + -${QUICK_INSERT_LEFT_OFFSET}px)`,
91
- top: `calc(anchor(${rootAnchorName} start) + ${topPositionAdjustment(rootNodeType)}px)`
139
+ top: `calc(anchor(${rootAnchorName} start) + ${topPositionAdjustment(rootNodeType)}px)`,
140
+ ...bottom
92
141
  };
93
142
  }
143
+
144
+ // expensive, calls offsetHeight, guard behind FG
145
+ const nodeHeight =
146
+ // eslint-disable-next-line @atlaskit/platform/no-preconditioning
147
+ fg('platform_editor_controls_sticky_controls') && getNodeHeight(dom, rootAnchorName || anchorName, anchorRectCache) || 0;
148
+ const height = fg('platform_editor_controls_sticky_controls') ? getControlHeightCSSValue(nodeHeight, isSticky, true, "var(--ds-space-300, 24px)") : {};
94
149
  return {
95
150
  left: isEdgeCase ? `calc(${(dom === null || dom === void 0 ? void 0 : dom.offsetLeft) || 0}px + ${getLeftPositionForRootElement(dom, rootNodeType, QUICK_INSERT_DIMENSIONS, innerContainer, isMacroInteractionUpdates)} + -${QUICK_INSERT_LEFT_OFFSET}px)` : `calc(${getLeftPositionForRootElement(dom, rootNodeType, QUICK_INSERT_DIMENSIONS, innerContainer, isMacroInteractionUpdates)} + -${QUICK_INSERT_LEFT_OFFSET}px)`,
96
- top: getTopPosition(dom, rootNodeType)
151
+ top: getTopPosition(dom, rootNodeType),
152
+ ...height
97
153
  };
98
- }, [rootAnchorName, view.dom, rootNodeType, macroInteractionUpdates]);
154
+ }, [rootAnchorName, view.dom, rootNodeType, macroInteractionUpdates, anchorName, anchorRectCache]);
99
155
  useEffect(() => {
100
156
  let cleanUpTransitionListener;
101
157
  if (rootNodeType === 'extension' || rootNodeType === 'embedCard') {
@@ -180,26 +236,29 @@ export const TypeAheadControl = ({
180
236
  });
181
237
  }
182
238
  }, [api, view.state]);
183
- return (
184
- /*#__PURE__*/
185
- // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
186
- React.createElement(Box, {
187
- style: positionStyles,
188
- xcss: [containerStaticStyles]
189
- }, /*#__PURE__*/React.createElement(Tooltip, {
190
- position: "top",
191
- content: /*#__PURE__*/React.createElement(ToolTipContent, {
192
- description: formatMessage(messages.insert)
193
- })
194
- }, /*#__PURE__*/React.createElement(Pressable, {
195
- type: "button",
196
- "aria-label": formatMessage(messages.insert),
197
- xcss: [buttonStyles],
198
- onClick: handleQuickInsert,
199
- onMouseDown: handleMouseDown
200
- }, /*#__PURE__*/React.createElement(AddIcon, {
201
- label: "add",
202
- color: "var(--ds-icon-subtle, #626F86)"
203
- }))))
204
- );
239
+ const tooltipPressable = () => /*#__PURE__*/React.createElement(Tooltip, {
240
+ position: "top",
241
+ content: /*#__PURE__*/React.createElement(ToolTipContent, {
242
+ description: formatMessage(messages.insert)
243
+ })
244
+ }, /*#__PURE__*/React.createElement(Pressable, {
245
+ testId: "editor-quick-insert-button",
246
+ type: "button",
247
+ "aria-label": formatMessage(messages.insert),
248
+ xcss: [fg('platform_editor_controls_sticky_controls') ? buttonStyles : stickyButtonStyles, isTypeAheadOpen && fg('platform_editor_controls_patch_1') && disabledStyles],
249
+ onClick: handleQuickInsert,
250
+ onMouseDown: fg('platform_editor_controls_patch_1') ? undefined : handleMouseDown,
251
+ isDisabled: fg('platform_editor_controls_patch_1') ? isTypeAheadOpen : undefined
252
+ }, /*#__PURE__*/React.createElement(AddIcon, {
253
+ label: "add",
254
+ color: isTypeAheadOpen ? "var(--ds-icon-disabled, #091E424F)" : "var(--ds-icon-subtle, #626F86)"
255
+ })));
256
+ return /*#__PURE__*/React.createElement(Box
257
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
258
+ , {
259
+ style: positionStyles,
260
+ xcss: [containerStaticStyles, isTypeAheadOpen && fg('platform_editor_controls_patch_1') && disabledContainerStyles]
261
+ }, fg('platform_editor_controls_sticky_controls') ? /*#__PURE__*/React.createElement(Box, {
262
+ xcss: [tooltipContainerStyles]
263
+ }, tooltipPressable()) : tooltipPressable());
205
264
  };
@@ -21,7 +21,7 @@ export var findHandleDec = function findHandleDec(decorations, from, to) {
21
21
  return spec.type === TYPE_HANDLE_DEC;
22
22
  });
23
23
  };
24
- export var dragHandleDecoration = function dragHandleDecoration(api, formatMessage, pos, anchorName, nodeType, nodeViewPortalProviderAPI, handleOptions) {
24
+ export var dragHandleDecoration = function dragHandleDecoration(api, formatMessage, pos, anchorName, nodeType, nodeViewPortalProviderAPI, handleOptions, anchorRectCache) {
25
25
  unmountDecorations(nodeViewPortalProviderAPI, 'data-blocks-drag-handle-container', 'data-blocks-drag-handle-key');
26
26
  var unbind;
27
27
  var key = uuid();
@@ -93,7 +93,8 @@ export var dragHandleDecoration = function dragHandleDecoration(api, formatMessa
93
93
  anchorName: anchorName,
94
94
  nodeType: nodeType,
95
95
  handleOptions: handleOptions,
96
- isTopLevelNode: isTopLevelNode
96
+ isTopLevelNode: isTopLevelNode,
97
+ anchorRectCache: anchorRectCache
97
98
  }), element);
98
99
  //}
99
100
  return element;
@@ -8,7 +8,7 @@ export var findQuickInsertInsertButtonDecoration = function findQuickInsertInser
8
8
  return spec.type === TYPE_QUICK_INSERT;
9
9
  });
10
10
  };
11
- export var quickInsertButtonDecoration = function quickInsertButtonDecoration(api, formatMessage, rootPos, anchorName, nodeType, nodeViewPortalProviderAPI, rootAnchorName, rootNodeType) {
11
+ export var quickInsertButtonDecoration = function quickInsertButtonDecoration(api, formatMessage, rootPos, anchorName, nodeType, nodeViewPortalProviderAPI, rootAnchorName, rootNodeType, anchorRectCache) {
12
12
  var key = uuid();
13
13
  return Decoration.widget(rootPos, function (view, getPos) {
14
14
  var element = document.createElement('span');
@@ -24,7 +24,8 @@ export var quickInsertButtonDecoration = function quickInsertButtonDecoration(ap
24
24
  nodeType: nodeType,
25
25
  anchorName: anchorName,
26
26
  rootAnchorName: rootAnchorName,
27
- rootNodeType: rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType
27
+ rootNodeType: rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType,
28
+ anchorRectCache: anchorRectCache
28
29
  });
29
30
  }, element, key);
30
31
  return element;
@@ -348,14 +348,14 @@ export var newApply = function newApply(api, formatMessage, tr, currentState, ne
348
348
  var _activeNode9, _activeNode10, _latestActiveNode, _latestActiveNode2, _latestActiveNode3, _latestActiveNode4;
349
349
  var _oldHandle = findHandleDec(decorations, (_activeNode9 = activeNode) === null || _activeNode9 === void 0 ? void 0 : _activeNode9.pos, (_activeNode10 = activeNode) === null || _activeNode10 === void 0 ? void 0 : _activeNode10.pos);
350
350
  decorations = decorations.remove(_oldHandle);
351
- var handleDec = dragHandleDecoration(api, formatMessage, (_latestActiveNode = latestActiveNode) === null || _latestActiveNode === void 0 ? void 0 : _latestActiveNode.pos, (_latestActiveNode2 = latestActiveNode) === null || _latestActiveNode2 === void 0 ? void 0 : _latestActiveNode2.anchorName, (_latestActiveNode3 = latestActiveNode) === null || _latestActiveNode3 === void 0 ? void 0 : _latestActiveNode3.nodeType, nodeViewPortalProviderAPI, (_latestActiveNode4 = latestActiveNode) === null || _latestActiveNode4 === void 0 ? void 0 : _latestActiveNode4.handleOptions);
351
+ var handleDec = dragHandleDecoration(api, formatMessage, (_latestActiveNode = latestActiveNode) === null || _latestActiveNode === void 0 ? void 0 : _latestActiveNode.pos, (_latestActiveNode2 = latestActiveNode) === null || _latestActiveNode2 === void 0 ? void 0 : _latestActiveNode2.anchorName, (_latestActiveNode3 = latestActiveNode) === null || _latestActiveNode3 === void 0 ? void 0 : _latestActiveNode3.nodeType, nodeViewPortalProviderAPI, (_latestActiveNode4 = latestActiveNode) === null || _latestActiveNode4 === void 0 ? void 0 : _latestActiveNode4.handleOptions, anchorRectCache);
352
352
  decorations = decorations.add(newState.doc, [handleDec]);
353
353
  }
354
354
  if (shouldRecreateQuickInsertButton && ((_latestActiveNode5 = latestActiveNode) === null || _latestActiveNode5 === void 0 ? void 0 : _latestActiveNode5.rootPos) !== undefined && editorExperiment('platform_editor_controls', 'variant1')) {
355
355
  var _activeNode11, _activeNode12, _latestActiveNode6, _latestActiveNode7, _latestActiveNode8, _latestActiveNode9, _latestActiveNode10;
356
356
  var _oldQuickInsertButton = findQuickInsertInsertButtonDecoration(decorations, (_activeNode11 = activeNode) === null || _activeNode11 === void 0 ? void 0 : _activeNode11.rootPos, (_activeNode12 = activeNode) === null || _activeNode12 === void 0 ? void 0 : _activeNode12.rootPos);
357
357
  decorations = decorations.remove(_oldQuickInsertButton);
358
- var quickInsertButton = quickInsertButtonDecoration(api, formatMessage, (_latestActiveNode6 = latestActiveNode) === null || _latestActiveNode6 === void 0 ? void 0 : _latestActiveNode6.rootPos, (_latestActiveNode7 = latestActiveNode) === null || _latestActiveNode7 === void 0 ? void 0 : _latestActiveNode7.anchorName, (_latestActiveNode8 = latestActiveNode) === null || _latestActiveNode8 === void 0 ? void 0 : _latestActiveNode8.nodeType, nodeViewPortalProviderAPI, (_latestActiveNode9 = latestActiveNode) === null || _latestActiveNode9 === void 0 ? void 0 : _latestActiveNode9.rootAnchorName, (_latestActiveNode10 = latestActiveNode) === null || _latestActiveNode10 === void 0 ? void 0 : _latestActiveNode10.rootNodeType);
358
+ var quickInsertButton = quickInsertButtonDecoration(api, formatMessage, (_latestActiveNode6 = latestActiveNode) === null || _latestActiveNode6 === void 0 ? void 0 : _latestActiveNode6.rootPos, (_latestActiveNode7 = latestActiveNode) === null || _latestActiveNode7 === void 0 ? void 0 : _latestActiveNode7.anchorName, (_latestActiveNode8 = latestActiveNode) === null || _latestActiveNode8 === void 0 ? void 0 : _latestActiveNode8.nodeType, nodeViewPortalProviderAPI, (_latestActiveNode9 = latestActiveNode) === null || _latestActiveNode9 === void 0 ? void 0 : _latestActiveNode9.rootAnchorName, (_latestActiveNode10 = latestActiveNode) === null || _latestActiveNode10 === void 0 ? void 0 : _latestActiveNode10.rootNodeType, anchorRectCache);
359
359
  decorations = decorations.add(newState.doc, [quickInsertButton]);
360
360
  }
361
361
  }
@@ -1,4 +1,6 @@
1
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
1
2
  import { DRAG_HANDLE_DIVIDER_TOP_ADJUSTMENT, DRAG_HANDLE_H1_TOP_ADJUSTMENT, DRAG_HANDLE_H2_TOP_ADJUSTMENT, DRAG_HANDLE_H4_TOP_ADJUSTMENT, DRAG_HANDLE_H5_TOP_ADJUSTMENT, DRAG_HANDLE_H6_TOP_ADJUSTMENT, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_PARAGRAPH_TOP_ADJUSTMENT, DRAG_HANDLE_WIDTH, dragHandleGap } from '../../ui/consts';
3
+ var STICKY_NODES = ['panel', 'table', 'expand', 'layoutSection', 'bodiedExtension'];
2
4
  export var getTopPosition = function getTopPosition(dom, type) {
3
5
  if (!dom) {
4
6
  return 'auto';
@@ -42,4 +44,26 @@ export var getLeftPosition = function getLeftPosition(dom, type, innerContainer,
42
44
  var relativeSpan = macroInteractionUpdates ? dom.querySelector('span.relative') : null;
43
45
  var leftAdjustment = relativeSpan ? relativeSpan.offsetLeft : 0;
44
46
  return getComputedStyle(innerContainer).transform === 'none' ? "".concat(innerContainer.offsetLeft + leftAdjustment - dragHandleGap(type, parentType) - DRAG_HANDLE_WIDTH, "px") : "".concat(innerContainer.offsetLeft + leftAdjustment - innerContainer.offsetWidth / 2 - dragHandleGap(type, parentType) - DRAG_HANDLE_WIDTH, "px");
47
+ };
48
+
49
+ // anchorRectCache seems to have a 100% cache miss rate
50
+ export var getNodeHeight = function getNodeHeight(dom, anchor, anchorRectCache) {
51
+ return (anchorRectCache === null || anchorRectCache === void 0 ? void 0 : anchorRectCache.getHeight(anchor)) || (dom === null || dom === void 0 ? void 0 : dom.offsetHeight);
52
+ };
53
+ export var shouldBeSticky = function shouldBeSticky(nodeType) {
54
+ return editorExperiment('platform_editor_controls', 'variant1') && STICKY_NODES.includes(nodeType);
55
+ };
56
+ export var getControlBottomCSSValue = function getControlBottomCSSValue(anchor, isSticky, isTopLevelNode, isLayoutColumn) {
57
+ return editorExperiment('advanced_layouts', true) && isLayoutColumn || !isSticky || !isTopLevelNode ? {
58
+ bottom: 'unset'
59
+ } : {
60
+ bottom: "anchor(".concat(anchor, " end)")
61
+ };
62
+ };
63
+ export var getControlHeightCSSValue = function getControlHeightCSSValue(nodeHeight, isSticky, isTopLevelNode, fallbackPxHeight, isLayoutColumn) {
64
+ return editorExperiment('advanced_layouts', true) && isLayoutColumn || !isSticky || !isTopLevelNode ? {
65
+ height: 'unset'
66
+ } : {
67
+ height: "".concat(nodeHeight || fallbackPxHeight, "px")
68
+ };
45
69
  };
@@ -31,7 +31,7 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
31
31
  import Tooltip from '@atlaskit/tooltip';
32
32
  import { key } from '../pm-plugins/main';
33
33
  import { getMultiSelectAnalyticsAttributes } from '../pm-plugins/utils/analytics';
34
- import { getLeftPosition, getTopPosition } from '../pm-plugins/utils/drag-handle-positions';
34
+ import { getControlBottomCSSValue, getControlHeightCSSValue, getLeftPosition, getNodeHeight, getTopPosition, shouldBeSticky } from '../pm-plugins/utils/drag-handle-positions';
35
35
  import { isHandleCorrelatedToSelection, selectNode } from '../pm-plugins/utils/getSelection';
36
36
  import { alignAnchorHeadInDirectionOfPos, expandSelectionHeadToNodeAtPos } from '../pm-plugins/utils/selection';
37
37
  import { BLOCK_MENU_ENABLED, DRAG_HANDLE_BORDER_RADIUS, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH, DRAG_HANDLE_WIDTH, DRAG_HANDLE_ZINDEX, dragHandleGap, nodeMargins, spacingBetweenNodesForPreview, topPositionAdjustment } from './consts';
@@ -47,6 +47,43 @@ var dragHandleColor = css({
47
47
  color: "var(--ds-icon-subtle, #626F86)"
48
48
  });
49
49
  var dragHandleButtonStyles = css({
50
+ display: 'flex',
51
+ boxSizing: 'border-box',
52
+ flexDirection: 'column',
53
+ justifyContent: 'center',
54
+ alignItems: 'center',
55
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
56
+ height: DRAG_HANDLE_HEIGHT,
57
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
58
+ width: DRAG_HANDLE_WIDTH,
59
+ border: 'none',
60
+ background: 'transparent',
61
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
62
+ borderRadius: DRAG_HANDLE_BORDER_RADIUS,
63
+ // when platform_editor_controls is enabled, the drag handle color is overridden. Update color here when experiment is cleaned up.
64
+ color: "var(--ds-icon, #44546F)",
65
+ cursor: 'grab',
66
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
67
+ zIndex: DRAG_HANDLE_ZINDEX,
68
+ outline: 'none',
69
+ '&:hover': {
70
+ backgroundColor: "var(--ds-background-neutral-subtle-hovered, #091E420F)"
71
+ },
72
+ '&:active': {
73
+ backgroundColor: "var(--ds-background-neutral-subtle-pressed, #091E4224)"
74
+ },
75
+ '&:focus': {
76
+ outline: "2px solid ".concat("var(--ds-border-focused, #388BFF)")
77
+ },
78
+ '&:disabled': {
79
+ color: "var(--ds-icon-disabled, #8993A4)",
80
+ backgroundColor: 'transparent'
81
+ },
82
+ '&:hover:disabled': {
83
+ backgroundColor: "var(--ds-background-disabled, transparent)"
84
+ }
85
+ });
86
+ var dragHandleButtonStylesOld = css({
50
87
  position: 'absolute',
51
88
  padding: "var(--ds-space-025, 2px)".concat(" 0"),
52
89
  boxSizing: 'border-box',
@@ -85,6 +122,16 @@ var dragHandleButtonStyles = css({
85
122
  backgroundColor: "var(--ds-background-disabled, transparent)"
86
123
  }
87
124
  });
125
+ var dragHandleContainerStyles = xcss({
126
+ position: 'absolute',
127
+ boxSizing: 'border-box',
128
+ zIndex: 'card'
129
+ });
130
+ var controlContainerStyles = xcss({
131
+ top: '0',
132
+ position: 'sticky',
133
+ zIndex: 'card'
134
+ });
88
135
  var dragHandleMultiLineSelectionFixFirefox = css({
89
136
  '&::selection': {
90
137
  backgroundColor: 'transparent'
@@ -148,7 +195,8 @@ export var DragHandle = function DragHandle(_ref) {
148
195
  nodeType = _ref.nodeType,
149
196
  handleOptions = _ref.handleOptions,
150
197
  _ref$isTopLevelNode = _ref.isTopLevelNode,
151
- isTopLevelNode = _ref$isTopLevelNode === void 0 ? true : _ref$isTopLevelNode;
198
+ isTopLevelNode = _ref$isTopLevelNode === void 0 ? true : _ref$isTopLevelNode,
199
+ anchorRectCache = _ref.anchorRectCache;
152
200
  var start = getPos();
153
201
  var buttonRef = useRef(null);
154
202
  var _useState = useState(768),
@@ -487,17 +535,20 @@ export var DragHandle = function DragHandle(_ref) {
487
535
  }
488
536
  }
489
537
  var isEdgeCase = (hasResizer || isExtension || isEmbedCard || isBlockCard) && innerContainer;
538
+ var isSticky = shouldBeSticky(nodeType);
490
539
  if (supportsAnchor) {
491
- return {
540
+ var bottom = fg('platform_editor_controls_sticky_controls') ? getControlBottomCSSValue(anchorName, isSticky, isTopLevelNode, isLayoutColumn) : {};
541
+ return _objectSpread({
492
542
  left: isEdgeCase ? "calc(anchor(".concat(anchorName, " start) + ").concat(getLeftPosition(dom, nodeType, innerContainer, isMacroInteractionUpdates, parentNodeType), ")") : editorExperiment('advanced_layouts', true) && isLayoutColumn ? "calc((anchor(".concat(anchorName, " right) + anchor(").concat(anchorName, " left))/2 - ").concat(DRAG_HANDLE_HEIGHT / 2, "px)") : "calc(anchor(".concat(anchorName, " start) - ").concat(DRAG_HANDLE_WIDTH, "px - ").concat(dragHandleGap(nodeType, parentNodeType), "px)"),
493
543
  top: editorExperiment('advanced_layouts', true) && isLayoutColumn ? "calc(anchor(".concat(anchorName, " top) - ").concat(DRAG_HANDLE_WIDTH, "px)") : "calc(anchor(".concat(anchorName, " start) + ").concat(topPositionAdjustment(nodeType), "px)")
494
- };
544
+ }, bottom);
495
545
  }
496
- return {
546
+ var height = fg('platform_editor_controls_sticky_controls') ? getControlHeightCSSValue(getNodeHeight(dom, anchorName, anchorRectCache) || 0, isSticky, isTopLevelNode, "".concat(DRAG_HANDLE_HEIGHT), isLayoutColumn) : {};
547
+ return _objectSpread({
497
548
  left: isEdgeCase ? "calc(".concat((dom === null || dom === void 0 ? void 0 : dom.offsetLeft) || 0, "px + ").concat(getLeftPosition(dom, nodeType, innerContainer, isMacroInteractionUpdates, parentNodeType), ")") : getLeftPosition(dom, nodeType, innerContainer, isMacroInteractionUpdates, parentNodeType),
498
549
  top: getTopPosition(dom, nodeType)
499
- };
500
- }, [anchorName, nodeType, view, blockCardWidth, macroInteractionUpdates, getPos, isLayoutColumn]);
550
+ }, height);
551
+ }, [anchorName, view.dom, view.state.doc, nodeType, blockCardWidth, macroInteractionUpdates, isTopLevelNode, isLayoutColumn, getPos, anchorRectCache]);
501
552
  var _useState7 = useState({
502
553
  display: 'none'
503
554
  }),
@@ -634,14 +685,14 @@ export var DragHandle = function DragHandle(_ref) {
634
685
  // eslint-disable-next-line @atlaskit/design-system/no-html-button
635
686
  jsx("button", {
636
687
  type: "button",
637
- css: [dragHandleButtonStyles, editorExperiment('platform_editor_controls', 'variant1') && dragHandleColor,
688
+ css: [fg('platform_editor_controls_sticky_controls') ? dragHandleButtonStyles : dragHandleButtonStylesOld, editorExperiment('platform_editor_controls', 'variant1') && dragHandleColor,
638
689
  // ED-26266: Fixed the drag handle highlight when selecting multiple line in Firefox
639
690
  // See https://product-fabric.atlassian.net/browse/ED-26266
640
691
  browser.gecko && fg('platform_editor_dnd_handle_highlight_fix_firefox') && dragHandleMultiLineSelectionFixFirefox, editorExperiment('advanced_layouts', true) && isLayoutColumn && layoutColumnDragHandleStyles, dragHandleSelected && selectedStyles],
641
692
  ref: buttonRef
642
693
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
643
694
  ,
644
- style: positionStyles,
695
+ style: !fg('platform_editor_controls_sticky_controls') && positionStyles || {},
645
696
  onClick: handleOnClick,
646
697
  onMouseDown: handleMouseDown,
647
698
  onKeyDown: handleKeyDown
@@ -665,17 +716,60 @@ export var DragHandle = function DragHandle(_ref) {
665
716
  })))
666
717
  );
667
718
  };
668
- return !dragHandleDisabled && fg('platform_editor_element_drag_and_drop_ed_23873') ? jsx(Tooltip, {
669
- content: jsx(TooltipContentWithMultipleShortcuts, {
670
- helpDescriptors: helpDescriptors
671
- }),
672
- ignoreTooltipPointerEvents: true,
673
- position: editorExperiment('platform_editor_controls', 'variant1') ? 'top' : undefined,
674
- onShow: function onShow() {
675
- var _api$accessibilityUti;
676
- api === null || api === void 0 || (_api$accessibilityUti = api.accessibilityUtils) === null || _api$accessibilityUti === void 0 || _api$accessibilityUti.actions.ariaNotify(message, {
677
- priority: 'important'
678
- });
679
- }
680
- }, renderButton()) : renderButton();
719
+ var stickyWithTooltip = function stickyWithTooltip() {
720
+ return jsx(Box
721
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
722
+ , {
723
+ style: positionStyles,
724
+ xcss: [dragHandleContainerStyles],
725
+ as: "span",
726
+ testId: "block-ctrl-drag-handle-container"
727
+ }, jsx(Box, {
728
+ xcss: [controlContainerStyles],
729
+ as: "span"
730
+ }, jsx(Tooltip, {
731
+ content: jsx(TooltipContentWithMultipleShortcuts, {
732
+ helpDescriptors: helpDescriptors
733
+ }),
734
+ ignoreTooltipPointerEvents: true,
735
+ position: 'top',
736
+ onShow: function onShow() {
737
+ var _api$accessibilityUti;
738
+ api === null || api === void 0 || (_api$accessibilityUti = api.accessibilityUtils) === null || _api$accessibilityUti === void 0 || _api$accessibilityUti.actions.ariaNotify(message, {
739
+ priority: 'important'
740
+ });
741
+ }
742
+ }, renderButton())));
743
+ };
744
+ var stickyWithoutTooltip = function stickyWithoutTooltip() {
745
+ return jsx(Box
746
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
747
+ , {
748
+ style: positionStyles,
749
+ xcss: [dragHandleContainerStyles],
750
+ as: "span",
751
+ testId: "block-ctrl-drag-handle-container"
752
+ }, jsx(Box, {
753
+ xcss: [controlContainerStyles],
754
+ as: "span"
755
+ }, renderButton()));
756
+ };
757
+ var buttonWithTooltip = function buttonWithTooltip() {
758
+ return jsx(Tooltip, {
759
+ content: jsx(TooltipContentWithMultipleShortcuts, {
760
+ helpDescriptors: helpDescriptors
761
+ }),
762
+ ignoreTooltipPointerEvents: true,
763
+ onShow: function onShow() {
764
+ var _api$accessibilityUti2;
765
+ api === null || api === void 0 || (_api$accessibilityUti2 = api.accessibilityUtils) === null || _api$accessibilityUti2 === void 0 || _api$accessibilityUti2.actions.ariaNotify(message, {
766
+ priority: 'important'
767
+ });
768
+ }
769
+ }, renderButton());
770
+ };
771
+ var isTooltip = !dragHandleDisabled && fg('platform_editor_element_drag_and_drop_ed_23873');
772
+ var stickyRender = isTooltip ? stickyWithTooltip() : stickyWithoutTooltip();
773
+ var render = isTooltip ? buttonWithTooltip() : renderButton();
774
+ return fg('platform_editor_controls_sticky_controls') ? stickyRender : render;
681
775
  };