UNPKG

@atlaskit/editor-plugin-block-controls

Version:

Block controls plugin for @atlaskit/editor-core

896 lines (887 loc) 68.8 kB
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /** * @jsxRuntime classic * @jsx jsx */ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports import { css, jsx } from '@emotion/react'; import { bind } from 'bind-event-listener'; import { getDocument } from '@atlaskit/browser-apis'; import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics'; import { getBrowserInfo } from '@atlaskit/editor-common/browser'; import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'; import { dragToMoveDown, dragToMoveLeft, dragToMoveRight, dragToMoveUp, getAriaKeyshortcuts, TooltipContentWithMultipleShortcuts } from '@atlaskit/editor-common/keymaps'; import { blockControlsMessages } from '@atlaskit/editor-common/messages'; import { DRAG_HANDLE_WIDTH, tableControlsSpacing } from '@atlaskit/editor-common/styles'; import { TextSelection } from '@atlaskit/editor-prosemirror/state'; import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils'; import { akEditorFullPageNarrowBreakout, akEditorTableToolbarSize, relativeSizeToBaseFontSize } from '@atlaskit/editor-shared-styles/consts'; import DragHandleVerticalIcon from '@atlaskit/icon/core/drag-handle-vertical'; import { fg } from '@atlaskit/platform-feature-flags'; import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview'; // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss import { Box, xcss } from '@atlaskit/primitives'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure'; import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments'; import Tooltip from '@atlaskit/tooltip'; import { getNodeTypeWithLevel } from '../pm-plugins/decorations-common'; import { key } from '../pm-plugins/main'; import { selectionPreservationPluginKey } from '../pm-plugins/selection-preservation/plugin-key'; import { getMultiSelectAnalyticsAttributes } from '../pm-plugins/utils/analytics'; import { getControlBottomCSSValue, getControlHeightCSSValue, getLeftPosition, getNodeHeight, getTopPosition, shouldBeSticky, shouldMaskNodeControls } from '../pm-plugins/utils/drag-handle-positions'; import { expandAndUpdateSelection } from '../pm-plugins/utils/expand-and-update-selection'; import { isHandleCorrelatedToSelection, selectNode } from '../pm-plugins/utils/getSelection'; import { alignAnchorHeadInDirectionOfPos, expandSelectionHeadToNodeAtPos } from '../pm-plugins/utils/selection'; import { DRAG_HANDLE_BORDER_RADIUS, DRAG_HANDLE_HEIGHT, DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH, DRAG_HANDLE_ZINDEX, dragHandleGap, nodeMargins, spacingBetweenNodesForPreview, STICKY_CONTROLS_TOP_MARGIN, STICKY_CONTROLS_TOP_MARGIN_FOR_STICKY_HEADER, topPositionAdjustment } from './consts'; import { DragHandleNestedIcon } from './drag-handle-nested-icon'; import { dragPreview } from './drag-preview'; import { refreshAnchorName } from './utils/anchor-name'; import { getAnchorAttrName } from './utils/dom-attr-name'; import { VisibilityContainer } from './visibility-container'; var iconWrapperStyles = xcss({ display: 'flex', justifyContent: 'center', alignItems: 'center' }); var buttonWrapperStyles = css({ display: 'flex', justifyContent: 'center', alignItems: 'center', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-blocks-drag-handle-container]:has(+ [data-prosemirror-node-name="table"] .pm-table-with-controls tr.sticky) &': { background: "linear-gradient(to bottom, ".concat("var(--ds-surface, #FFFFFF)", " 90%, transparent)"), marginBottom: "var(--ds-space-negative-200, -16px)", paddingBottom: "var(--ds-space-200, 16px)", marginTop: "var(--ds-space-negative-400, -32px)", paddingTop: "calc(".concat("var(--ds-space-400, 32px)", " - 1px)"), marginRight: "var(--ds-space-negative-150, -12px)", paddingRight: "var(--ds-space-150, 12px)", boxSizing: 'border-box' }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-prosemirror-mark-name="breakout"]:has([data-blocks-drag-handle-container]):has(+ [data-prosemirror-node-name="table"] .pm-table-with-controls tr.sticky) &': { background: "linear-gradient(to bottom, ".concat("var(--ds-surface, #FFFFFF)", " 90%, transparent)"), marginBottom: "var(--ds-space-negative-200, -16px)", paddingBottom: "var(--ds-space-200, 16px)", marginTop: "var(--ds-space-negative-400, -32px)", paddingTop: "calc(".concat("var(--ds-space-400, 32px)", " - 1px)"), marginRight: "var(--ds-space-negative-150, -12px)", paddingRight: "var(--ds-space-150, 12px)", boxSizing: 'border-box' } }); var buttonWrapperStylesPatch = css({ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-blocks-drag-handle-container]:has(+ [data-prosemirror-node-name="table"] .pm-table-with-controls [data-number-column="true"] tr.sticky) &': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values marginRight: -akEditorTableToolbarSize, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values paddingRight: akEditorTableToolbarSize }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-prosemirror-mark-name="breakout"]:has([data-blocks-drag-handle-container]):has(+ [data-prosemirror-node-name="table"] .pm-table-with-controls [data-number-column="true"] tr.sticky) &': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values marginRight: -akEditorTableToolbarSize, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values paddingRight: akEditorTableToolbarSize } }); // update color to match quick insert button for new editor controls var dragHandleColor = css({ color: "var(--ds-icon-subtle, #505258)" }); var dragHandleButtonStyles = css({ display: 'flex', boxSizing: 'border-box', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 height: DRAG_HANDLE_HEIGHT, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 width: DRAG_HANDLE_WIDTH, border: 'none', background: 'transparent', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 borderRadius: DRAG_HANDLE_BORDER_RADIUS, // when platform_editor_controls is enabled, the drag handle color is overridden. Update color here when experiment is cleaned up. color: "var(--ds-icon, #292A2E)", cursor: 'grab', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 zIndex: DRAG_HANDLE_ZINDEX, outline: 'none', '&:hover': { backgroundColor: "var(--ds-background-neutral-subtle-hovered, #0515240F)" }, '&:active': { backgroundColor: "var(--ds-background-neutral-subtle-pressed, #0B120E24)" }, '&:disabled': { color: "var(--ds-icon-disabled, #080F214A)", backgroundColor: 'transparent' }, '&:hover:disabled': { backgroundColor: "var(--ds-background-disabled, #17171708)" } }); // Calculate scaled dimensions based on the base font size using CSS calc() // Default font size is 16px, scale proportionally // Standard: 16px -> 24h x 12w, Dense: 13px -> 18h x 9w, Jira: 14px -> 21h x 12w var dragHandleButtonScaledStyles = css({ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values height: relativeSizeToBaseFontSize(DRAG_HANDLE_HEIGHT), // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values width: relativeSizeToBaseFontSize(DRAG_HANDLE_WIDTH) }); var dragHandleButtonSmallScreenStyles = css(_defineProperty({}, "@container editor-area (max-width: ".concat(akEditorFullPageNarrowBreakout, "px)"), { opacity: 0, visibility: 'hidden' })); var dragHandleButtonStylesOld = css({ position: 'absolute', paddingTop: "var(--ds-space-025, 2px)", paddingBottom: "var(--ds-space-025, 2px)", paddingLeft: '0', paddingRight: '0', boxSizing: 'border-box', display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 height: DRAG_HANDLE_HEIGHT, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 width: DRAG_HANDLE_WIDTH, border: 'none', background: 'transparent', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 borderRadius: DRAG_HANDLE_BORDER_RADIUS, // when platform_editor_controls is enabled, the drag handle color is overridden. Update color here when experiment is cleaned up. color: "var(--ds-icon, #292A2E)", cursor: 'grab', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 zIndex: DRAG_HANDLE_ZINDEX, outline: 'none', '&:hover': { backgroundColor: "var(--ds-background-neutral-subtle-hovered, #0515240F)" }, '&:active': { backgroundColor: "var(--ds-background-neutral-subtle-pressed, #0B120E24)" }, '&:focus': { outline: "var(--ds-border-width-focused, 2px)".concat(" solid ", "var(--ds-border-focused, #4688EC)") }, '&:disabled': { color: "var(--ds-icon-disabled, #080F214A)", backgroundColor: 'transparent' }, '&:hover:disabled': { backgroundColor: "var(--ds-background-disabled, #17171708)" } }); var focusedStylesOld = css({ '&:focus': { outline: "var(--ds-border-width-focused, 2px)".concat(" solid ", "var(--ds-border-focused, #4688EC)") } }); var focusedStyles = css({ '&:focus-visible': { outline: "var(--ds-border-width-focused, 2px)".concat(" solid ", "var(--ds-border-focused, #4688EC)") } }); var keyboardFocusedDragHandleStyles = css({ outline: "var(--ds-border-width-focused, 2px)".concat(" solid ", "var(--ds-border-focused, #4688EC)") }); var dragHandleContainerStyles = xcss({ position: 'absolute', boxSizing: 'border-box' }); var tooltipContainerStyles = css({ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values bottom: "-".concat(STICKY_CONTROLS_TOP_MARGIN, "px"), position: 'sticky', display: 'block', zIndex: 100 // card = 100 }); var tooltipContainerStylesStickyHeaderWithMask = css({ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: "".concat(STICKY_CONTROLS_TOP_MARGIN, "px"), // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-blocks-drag-handle-container]:has(+ [data-prosemirror-node-name="table"] .pm-table-with-controls tr.sticky) &': { top: '0' }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-prosemirror-mark-name="breakout"]:has([data-blocks-drag-handle-container]):has(+ [data-prosemirror-node-name="table"] .pm-table-with-controls tr.sticky) &': { top: '0' } }); var tooltipContainerStylesImprovedStickyHeaderWithMask = css({ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: "".concat(STICKY_CONTROLS_TOP_MARGIN, "px"), // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-blocks-drag-handle-container]:has(+ [data-prosemirror-node-name="table"] .pm-table-with-controls tr.sticky) &': { top: '0' }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-prosemirror-mark-name="breakout"]:has([data-blocks-drag-handle-container]):has(+ [data-prosemirror-node-name="table"] .pm-table-with-controls tr.sticky) &': { top: '0' }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-blocks-drag-handle-container]:has(+ [data-prosemirror-mark-name="fragment"] >[data-prosemirror-node-name="table"] .pm-table-with-controls tr.sticky) &': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: tableControlsSpacing }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-prosemirror-mark-name="breakout"]:has([data-blocks-drag-handle-container]):has(+ [data-prosemirror-mark-name="fragment"] >[data-prosemirror-node-name="table"] .pm-table-with-controls tr.sticky) &': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: tableControlsSpacing }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-blocks-drag-handle-container]:has(+ [data-prosemirror-node-name="table"] tr.pm-table-row-native-sticky.pm-table-row-native-sticky-active) &': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: "".concat(STICKY_CONTROLS_TOP_MARGIN_FOR_STICKY_HEADER, "px") }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-prosemirror-mark-name="breakout"]:has([data-blocks-drag-handle-container]):has(+ [data-prosemirror-node-name="table"] tr.pm-table-row-native-sticky.pm-table-row-native-sticky-active) &': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: "".concat(STICKY_CONTROLS_TOP_MARGIN_FOR_STICKY_HEADER, "px") }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-blocks-drag-handle-container]:has(+ [data-prosemirror-mark-name="fragment"] >[data-prosemirror-node-name="table"] tr.pm-table-row-native-sticky.pm-table-row-native-sticky-active) &': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: "".concat(STICKY_CONTROLS_TOP_MARGIN_FOR_STICKY_HEADER, "px") }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-prosemirror-mark-name="breakout"]:has([data-blocks-drag-handle-container]):has(+ [data-prosemirror-mark-name="fragment"] > [data-prosemirror-node-name="table"] tr.pm-table-row-native-sticky.pm-table-row-native-sticky-active) &': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: "".concat(STICKY_CONTROLS_TOP_MARGIN_FOR_STICKY_HEADER, "px") } }); var tooltipContainerStylesStickyHeaderWithoutMask = css({ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: "".concat(STICKY_CONTROLS_TOP_MARGIN, "px"), // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-blocks-drag-handle-container]:has(+ [data-prosemirror-node-name="table"] .pm-table-with-controls tr.sticky) &': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: tableControlsSpacing }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors '[data-prosemirror-mark-name="breakout"]:has([data-blocks-drag-handle-container]):has(+ [data-prosemirror-node-name="table"] .pm-table-with-controls tr.sticky) &': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values top: tableControlsSpacing } }); var dragHandleMultiLineSelectionFixFirefox = css({ '&::selection': { backgroundColor: 'transparent' } }); var layoutColumnDragHandleStyles = css({ transform: 'rotate(90deg)' }); var selectedStyles = css({ backgroundColor: "var(--ds-background-selected, #E9F2FE)", color: "var(--ds-icon-selected, #1868DB)" }); // [Chrome only] When selection contains multiple nodes and then drag a drag handle that is within the selection range, // icon span receives dragStart event, instead of button, and since it is not registered as a draggable element // with pragmatic DnD and pragmatic DnD is not triggered var handleIconDragStart = function handleIconDragStart(e) { var browser = getBrowserInfo(); if (!browser.chrome) { return; } // prevent dragStart handler triggered by icon e.stopPropagation(); var dragEvent = new DragEvent('dragstart', { bubbles: true, cancelable: true, dataTransfer: e.dataTransfer }); if (e.target instanceof HTMLElement) { var _e$target$closest; // re-dispatch drag event on button so that pragmatic DnD can be triggered properly (_e$target$closest = e.target.closest('button')) === null || _e$target$closest === void 0 || _e$target$closest.dispatchEvent(dragEvent); } }; var getNodeSpacingForPreview = function getNodeSpacingForPreview(node) { if (!node) { return spacingBetweenNodesForPreview['default']; } var nodeTypeName = node.type.name; if (nodeTypeName === 'heading') { return spacingBetweenNodesForPreview["heading".concat(node.attrs.level)] || spacingBetweenNodesForPreview['default']; } return spacingBetweenNodesForPreview[nodeTypeName] || spacingBetweenNodesForPreview['default']; }; var getNodeMargins = function getNodeMargins(node) { if (!node) { return nodeMargins['default']; } var nodeTypeName = node.type.name; if (nodeTypeName === 'heading') { return nodeMargins["heading".concat(node.attrs.level)] || nodeMargins['default']; } return nodeMargins[nodeTypeName] || nodeMargins['default']; }; export var DragHandle = function DragHandle(_ref) { var _api$core4; var view = _ref.view, api = _ref.api, formatMessage = _ref.formatMessage, getPos = _ref.getPos, anchorName = _ref.anchorName, nodeType = _ref.nodeType, handleOptions = _ref.handleOptions, _ref$isTopLevelNode = _ref.isTopLevelNode, isTopLevelNode = _ref$isTopLevelNode === void 0 ? true : _ref$isTopLevelNode, anchorRectCache = _ref.anchorRectCache; var buttonRef = useRef(null); var mouseDownRef = useRef(false); var _useState = useState(false), _useState2 = _slicedToArray(_useState, 2), dragHandleSelected = _useState2[0], setDragHandleSelected = _useState2[1]; var _useState3 = useState(false), _useState4 = _slicedToArray(_useState3, 2), dragHandleDisabled = _useState4[0], setDragHandleDisabled = _useState4[1]; var _useState5 = useState(768), _useState6 = _slicedToArray(_useState5, 2), blockCardWidth = _useState6[0], setBlockCardWidth = _useState6[1]; var _useState7 = useState(false), _useState8 = _slicedToArray(_useState7, 2), recalculatePosition = _useState8[0], setRecalculatePosition = _useState8[1]; var _useState9 = useState({ display: 'none' }), _useState0 = _slicedToArray(_useState9, 2), positionStylesOld = _useState0[0], setPositionStylesOld = _useState0[1]; var _useState1 = useState(Boolean(handleOptions === null || handleOptions === void 0 ? void 0 : handleOptions.isFocused)), _useState10 = _slicedToArray(_useState1, 2), isFocused = _useState10[0], setIsFocused = _useState10[1]; var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['featureFlags', 'selection', 'blockControls', 'interaction'], function (states) { var _states$featureFlagsS, _states$selectionStat, _states$blockControls, _states$interactionSt; return { macroInteractionUpdates: (_states$featureFlagsS = states.featureFlagsState) === null || _states$featureFlagsS === void 0 ? void 0 : _states$featureFlagsS.macroInteractionUpdates, selection: (_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection, isShiftDown: (_states$blockControls = states.blockControlsState) === null || _states$blockControls === void 0 ? void 0 : _states$blockControls.isShiftDown, interactionState: (_states$interactionSt = states.interactionState) === null || _states$interactionSt === void 0 ? void 0 : _states$interactionSt.interactionState }; }), macroInteractionUpdates = _useSharedPluginState.macroInteractionUpdates, selection = _useSharedPluginState.selection, isShiftDown = _useSharedPluginState.isShiftDown, interactionState = _useSharedPluginState.interactionState; var start = getPos(); var isLayoutColumn = nodeType === 'layoutColumn'; var isMultiSelect = editorExperiment('platform_editor_element_drag_and_drop_multiselect', true); // Dynamically calculate if node is top-level based on current position (gated by experiment) var isTopLevelNodeDynamic = useMemo(function () { if (!expValEquals('platform_editor_nested_drag_handle_icon', 'isEnabled', true)) { return isTopLevelNode; } var pos = getPos(); if (typeof pos === 'number') { var $pos = view.state.doc.resolve(pos); return ($pos === null || $pos === void 0 ? void 0 : $pos.parent.type.name) === 'doc'; } return true; }, [getPos, view.state.doc, isTopLevelNode]); // Use the dynamic value when experiment is on, otherwise use the prop // When cleaning up the experiment, you can safely remove the isTopLevelNode as an prop and // just rely on the dynamic value (rename it to isTopLevelNode for simplicitiy) var isTopLevelNodeValue = expValEquals('platform_editor_nested_drag_handle_icon', 'isEnabled', true) ? isTopLevelNodeDynamic : isTopLevelNode; useEffect(function () { if (editorExperiment('platform_editor_block_control_optimise_render', true)) { return; } // blockCard/datasource width is rendered correctly after this decoraton does. We need to observe for changes. if (nodeType === 'blockCard') { var dom = view.dom.querySelector("[".concat(getAnchorAttrName(), "=\"").concat(anchorName, "\"]")); var container = dom === null || dom === void 0 ? void 0 : dom.querySelector('.datasourceView-content-inner-wrap'); if (container) { var resizeObserver = new ResizeObserver(function (entries) { var width = entries[0].contentBoxSize[0].inlineSize; setBlockCardWidth(width); }); resizeObserver.observe(container); return function () { return resizeObserver.unobserve(container); }; } } }, [anchorName, nodeType, view.dom]); useEffect(function () { if (!expValEqualsNoExposure('platform_editor_selection_toolbar_block_handle', 'isEnabled', true)) { return; } var unbind = bind(window, { type: 'mouseUp', listener: function listener() { return mouseDownRef.current = false; } }); return function () { return unbind(); }; }, []); var handleMouseDown = useCallback(function () { mouseDownRef.current = true; }, []); var handleMouseUp = useCallback(function (e) { // Stop propagation so that for drag handles in nested scenarios the click is captured // and doesn't propagate to the edge of the element and trigger a node selection // on the parent element if (!expValEqualsNoExposure('platform_editor_selection_toolbar_block_handle', 'isEnabled', true)) { e.stopPropagation(); } // Fixes bug where selection toolbar is blocked when mouse is released on drag handle if (mouseDownRef.current) { e.stopPropagation(); } }, []); var handleOnClickNew = useCallback(function (e) { var _api$core; api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref2) { var _selectionPreservatio, _api$analytics, _resolvedStartPos$nod, _api$blockControls, _api$blockControls2; var tr = _ref2.tr; var startPos = getPos(); if (startPos === undefined) { return tr; } var resolvedStartPos = tr.doc.resolve(startPos); var selection = ((_selectionPreservatio = selectionPreservationPluginKey.getState(view.state)) === null || _selectionPreservatio === void 0 ? void 0 : _selectionPreservatio.preservedSelection) || tr.selection; api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({ eventType: EVENT_TYPE.UI, action: ACTION.CLICKED, actionSubject: ACTION_SUBJECT.BUTTON, actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE, attributes: { nodeDepth: resolvedStartPos.depth, nodeType: ((_resolvedStartPos$nod = resolvedStartPos.nodeAfter) === null || _resolvedStartPos$nod === void 0 ? void 0 : _resolvedStartPos$nod.type.name) || '' } })(tr); expandAndUpdateSelection({ tr: tr, selection: selection, startPos: startPos, isShiftPressed: e.shiftKey, nodeType: nodeType, api: api }); api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.startPreservingSelection()({ tr: tr }); api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || _api$blockControls2.commands.toggleBlockMenu({ anchorName: anchorName, openedViaKeyboard: false, triggerByNode: editorExperiment('platform_synced_block', true) ? { nodeType: nodeType, pos: startPos, rootPos: tr.doc.resolve(startPos).before(1) } : undefined })({ tr: tr }); tr.setMeta('scrollIntoView', false); return tr; }); view.focus(); }, [api, view, getPos, nodeType, anchorName]); var handleOnClick = useCallback(function (e) { var _api$core2; if (!isMultiSelect) { setDragHandleSelected(!dragHandleSelected); } api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(function (_ref3) { var _api$blockControls$sh, _api$analytics2; var tr = _ref3.tr; var startPos = getPos(); if (startPos === undefined) { return tr; } var mSelect = api === null || api === void 0 || (_api$blockControls$sh = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh === void 0 ? void 0 : _api$blockControls$sh.multiSelectDnD; var $anchor = (mSelect === null || mSelect === void 0 ? void 0 : mSelect.anchor) !== undefined ? tr.doc.resolve(mSelect === null || mSelect === void 0 ? void 0 : mSelect.anchor) : tr.selection.$anchor; if (!isMultiSelect || tr.selection.empty || !e.shiftKey) { tr = selectNode(tr, startPos, nodeType, api); } else if (isTopLevelNodeValue && $anchor.depth <= DRAG_HANDLE_MAX_SHIFT_CLICK_DEPTH && e.shiftKey && fg('platform_editor_elements_dnd_shift_click_select')) { var _api$blockControls3; var alignAnchorHeadToSel = alignAnchorHeadInDirectionOfPos(tr.selection, startPos); var selectionWithExpandedHead = expandSelectionHeadToNodeAtPos(alignAnchorHeadToSel, startPos); tr.setSelection(selectionWithExpandedHead); api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 || _api$blockControls3.commands.setMultiSelectPositions()({ tr: tr }); } var resolvedMovingNode = tr.doc.resolve(startPos); var maybeNode = resolvedMovingNode.nodeAfter; tr.setMeta('scrollIntoView', false); api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.attachAnalyticsEvent({ eventType: EVENT_TYPE.UI, action: ACTION.CLICKED, actionSubject: ACTION_SUBJECT.BUTTON, actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE, attributes: { nodeDepth: resolvedMovingNode.depth, nodeType: (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name) || '' } })(tr); return tr; }); view.focus(); }, [isMultiSelect, api, view, dragHandleSelected, getPos, isTopLevelNodeValue, nodeType]); var handleKeyDown = useCallback(function (e) { // allow user to use spacebar to select the node if (!e.repeat && e.key === ' ') { var _api$core3; var startPos = getPos(); api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref4) { var tr = _ref4.tr; if (startPos === undefined) { return tr; } var node = tr.doc.nodeAt(startPos); if (!node) { return tr; } var $startPos = tr.doc.resolve(startPos + node.nodeSize); var selection = new TextSelection($startPos); tr.setSelection(selection); !isMultiSelect && tr.setMeta(key, { pos: startPos }); return tr; }); } else if (![e.altKey, e.ctrlKey, e.shiftKey].some(function (pressed) { return pressed; })) { // If not trying to press shortcut keys, // return focus to editor to resume editing from caret position view.focus(); } }, [getPos, api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions, isMultiSelect, view]); var handleKeyDownNew = useCallback(function (e) { // allow user to use spacebar to select the node if (e.key === 'Enter' || !e.repeat && e.key === ' ') { var _getDocument, _api$core5; if (((_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.activeElement) !== buttonRef.current) { return; } e.preventDefault(); e.stopPropagation(); var startPos = getPos(); api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref5) { var _selectionPreservatio2, _api$blockControls4, _api$blockControls5, _api$userIntent; var tr = _ref5.tr; if (startPos === undefined) { return tr; } var selection = ((_selectionPreservatio2 = selectionPreservationPluginKey.getState(view.state)) === null || _selectionPreservatio2 === void 0 ? void 0 : _selectionPreservatio2.preservedSelection) || tr.selection; expandAndUpdateSelection({ tr: tr, selection: selection, startPos: startPos, isShiftPressed: e.shiftKey, nodeType: nodeType, api: api }); api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 || _api$blockControls4.commands.startPreservingSelection()({ tr: tr }); var rootPos = editorExperiment('platform_synced_block', true) ? tr.doc.resolve(startPos).before(1) : undefined; var triggerByNode = editorExperiment('platform_synced_block', true) ? { nodeType: nodeType, pos: startPos, rootPos: rootPos } : undefined; api === null || api === void 0 || (_api$blockControls5 = api.blockControls) === null || _api$blockControls5 === void 0 || _api$blockControls5.commands.toggleBlockMenu({ anchorName: anchorName, triggerByNode: triggerByNode, openedViaKeyboard: true })({ tr: tr }); api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 || _api$userIntent.commands.setCurrentUserIntent('blockMenuOpen')({ tr: tr }); return tr; }); view.focus(); } else if (![e.altKey, e.ctrlKey, e.shiftKey].some(function (pressed) { return pressed; })) { // If not trying to press shortcut keys, // return focus to editor to resume editing from caret position view.focus(); } }, [getPos, api, nodeType, anchorName, view]); useEffect(function () { var element = buttonRef.current; if (!element) { return; } return draggable({ element: element, getInitialData: function getInitialData() { return { type: 'element', start: start }; }, onGenerateDragPreview: function onGenerateDragPreview(_ref6) { var _api$blockControls$sh2; var nativeSetDragImage = _ref6.nativeSetDragImage; if (isMultiSelect) { var _api$core6; api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 || _api$core6.actions.execute(function (_ref7) { var tr = _ref7.tr; var handlePos = getPos(); if (typeof handlePos !== 'number') { return tr; } var newHandlePosCheck = isHandleCorrelatedToSelection(view.state, tr.selection, handlePos); if (!tr.selection.empty && newHandlePosCheck) { var _api$blockControls6; api === null || api === void 0 || (_api$blockControls6 = api.blockControls) === null || _api$blockControls6 === void 0 || _api$blockControls6.commands.setMultiSelectPositions()({ tr: tr }); } else { tr = selectNode(tr, handlePos, nodeType, api); } return tr; }); } var startPos = getPos(); var state = view.state; var doc = state.doc, selection = state.selection; var sliceFrom = selection.from; var sliceTo = selection.to; var mSelect = api === null || api === void 0 || (_api$blockControls$sh2 = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh2 === void 0 ? void 0 : _api$blockControls$sh2.multiSelectDnD; if (mSelect) { var anchor = mSelect.anchor, head = mSelect.head; sliceFrom = Math.min(anchor, head); sliceTo = Math.max(anchor, head); } var expandedSlice = doc.slice(sliceFrom, sliceTo); var isDraggingMultiLine = isMultiSelect && startPos !== undefined && startPos >= sliceFrom && startPos < sliceTo && expandedSlice.content.childCount > 1; setCustomNativeDragPreview({ getOffset: function getOffset() { if (!isDraggingMultiLine) { return { x: 0, y: 0 }; } else { // Calculate the offset of the preview container, // So when drag multiple nodes, the preview align with the position of the selected nodes var domAtPos = view.domAtPos.bind(view); var domElementsHeightBeforeHandle = 0; var nodesStartPos = []; var nodesEndPos = []; var activeNodeMarginTop = 0; for (var i = 0; i < expandedSlice.content.childCount; i++) { if (i === 0) { var _expandedSlice$conten; nodesStartPos[i] = sliceFrom; nodesEndPos[i] = sliceFrom + (((_expandedSlice$conten = expandedSlice.content.maybeChild(i)) === null || _expandedSlice$conten === void 0 ? void 0 : _expandedSlice$conten.nodeSize) || 0); } else { var _expandedSlice$conten2; nodesStartPos[i] = nodesEndPos[i - 1]; nodesEndPos[i] = nodesStartPos[i] + (((_expandedSlice$conten2 = expandedSlice.content.maybeChild(i)) === null || _expandedSlice$conten2 === void 0 ? void 0 : _expandedSlice$conten2.nodeSize) || 0); } // when the node is before the handle, calculate the height of the node if (nodesEndPos[i] <= startPos) { // eslint-disable-next-line @atlaskit/editor/no-as-casting var currentNodeElement = findDomRefAtPos(nodesStartPos[i], domAtPos); var maybeCurrentNode = expandedSlice.content.maybeChild(i); var currentNodeSpacing = maybeCurrentNode ? getNodeMargins(maybeCurrentNode).top + getNodeMargins(maybeCurrentNode).bottom : 0; domElementsHeightBeforeHandle = domElementsHeightBeforeHandle + currentNodeElement.offsetHeight + currentNodeSpacing; } else { // when the node is after the handle, calculate the top margin of the active node var maybeNextNode = expandedSlice.content.maybeChild(i); activeNodeMarginTop = maybeNextNode ? getNodeMargins(maybeNextNode).top : 0; break; } } return { x: 0, y: domElementsHeightBeforeHandle + activeNodeMarginTop }; } }, render: function render(_ref8) { var container = _ref8.container; var dom = view.dom.querySelector("[".concat(getAnchorAttrName(), "=\"").concat(anchorName, "\"]")); if (!dom) { return; } if (!isDraggingMultiLine) { return dragPreview(container, { dom: dom, nodeType: nodeType }); } else { var domAtPos = view.domAtPos.bind(view); var previewContent = []; expandedSlice.content.descendants(function (node, pos) { // Get the dom element of the node //eslint-disable-next-line @atlaskit/editor/no-as-casting var nodeDomElement = findDomRefAtPos(sliceFrom + pos, domAtPos); var currentNodeSpacing = getNodeSpacingForPreview(node); previewContent.push({ dom: nodeDomElement, nodeType: node.type.name, nodeSpacing: currentNodeSpacing }); return false; // Only iterate through the first level of nodes }); return dragPreview(container, previewContent); } }, nativeSetDragImage: nativeSetDragImage }); }, onDragStart: function onDragStart() { var _api$core7; if (start === undefined) { return; } api === null || api === void 0 || (_api$core7 = api.core) === null || _api$core7 === void 0 || _api$core7.actions.execute(function (_ref9) { var _api$blockControls$sh3, _api$blockControls7, _api$analytics3; var tr = _ref9.tr; var nodeTypes, hasSelectedMultipleNodes; var resolvedMovingNode = tr.doc.resolve(start); var maybeNode = resolvedMovingNode.nodeAfter; var mSelect = api === null || api === void 0 || (_api$blockControls$sh3 = api.blockControls.sharedState.currentState()) === null || _api$blockControls$sh3 === void 0 ? void 0 : _api$blockControls$sh3.multiSelectDnD; if (mSelect) { var attributes = getMultiSelectAnalyticsAttributes(tr, mSelect.anchor, mSelect.head); nodeTypes = attributes.nodeTypes; hasSelectedMultipleNodes = attributes.hasSelectedMultipleNodes; } else { nodeTypes = maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name; hasSelectedMultipleNodes = false; } api === null || api === void 0 || (_api$blockControls7 = api.blockControls) === null || _api$blockControls7 === void 0 || _api$blockControls7.commands.setNodeDragged(getPos, anchorName, nodeType)({ tr: tr }); tr.setMeta('scrollIntoView', false); api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.attachAnalyticsEvent({ eventType: EVENT_TYPE.UI, action: ACTION.DRAGGED, actionSubject: ACTION_SUBJECT.ELEMENT, actionSubjectId: ACTION_SUBJECT_ID.ELEMENT_DRAG_HANDLE, attributes: _objectSpread({ nodeDepth: resolvedMovingNode.depth, nodeType: (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.type.name) || '' }, isMultiSelect && { nodeTypes: nodeTypes, hasSelectedMultipleNodes: hasSelectedMultipleNodes }) })(tr); return tr; }); view.focus(); } }); }, [anchorName, api, getPos, isMultiSelect, nodeType, start, view]); var positionStyles = useMemo(function () { if (!editorExperiment('platform_editor_block_control_optimise_render', true)) { return {}; } // This is a no-op to allow recalculatePosition to be used as a dependency if (recalculatePosition) { setRecalculatePosition(recalculatePosition); } var pos = getPos(); var $pos = expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? typeof pos === 'number' && view.state.doc.resolve(pos) : pos && view.state.doc.resolve(pos); var parentPos = $pos && $pos.depth ? $pos.before() : undefined; var node = parentPos !== undefined ? view.state.doc.nodeAt(parentPos) : undefined; var parentNodeType = node === null || node === void 0 ? void 0 : node.type.name; var supportsAnchor = CSS.supports('top', "anchor(".concat(anchorName, " start)")) && CSS.supports('left', "anchor(".concat(anchorName, " start)")); var safeAnchorName = editorExperiment('platform_editor_controls', 'variant1') ? refreshAnchorName({ getPos: getPos, view: view, anchorName: anchorName }) : anchorName; var dom = view.dom.querySelector("[".concat(getAnchorAttrName(), "=\"").concat(safeAnchorName, "\"]")); var hasResizer = nodeType === 'table' || nodeType === 'mediaSingle'; var isExtension = nodeType === 'extension' || nodeType === 'bodiedExtension' || nodeType === 'multiBodiedExtension'; var isBlockCard = nodeType === 'blockCard'; var isEmbedCard = nodeType === 'embedCard'; var isMacroInteractionUpdates = macroInteractionUpdates && isExtension; var innerContainer = null; if (dom) { if (isEmbedCard) { innerContainer = dom.querySelector('.rich-media-item'); } else if (hasResizer) { innerContainer = dom.querySelector('.resizer-item'); } else if (isExtension) { innerContainer = dom.querySelector('.extension-container[data-layout]'); } else if (isBlockCard) { //specific to datasource blockCard innerContainer = dom.querySelector('.datasourceView-content-inner-wrap'); } } var isEdgeCase = (hasResizer || isExtension || isEmbedCard || isBlockCard) && innerContainer; var isSticky = shouldBeSticky(nodeType); if (supportsAnchor) { var bottom = editorExperiment('platform_editor_controls', 'variant1') ? getControlBottomCSSValue(safeAnchorName, isSticky, isTopLevelNodeValue, isLayoutColumn) : {}; return _objectSpread({ left: isEdgeCase ? "calc(anchor(".concat(safeAnchorName, " start) + ").concat(getLeftPosition(dom, nodeType, innerContainer, isMacroInteractionUpdates, parentNodeType), ")") : editorExperiment('advanced_layouts', true) && isLayoutColumn ? "calc((anchor(".concat(safeAnchorName, " right) + anchor(").concat(safeAnchorName, " left))/2 - ").concat(DRAG_HANDLE_HEIGHT / 2, "px)") : "calc(anchor(".concat(safeAnchorName, " start) - ").concat(DRAG_HANDLE_WIDTH, "px - ").concat(dragHandleGap(nodeType, parentNodeType), "px)"), top: editorExperiment('advanced_layouts', true) && isLayoutColumn ? "calc(anchor(".concat(safeAnchorName, " top) - ").concat(DRAG_HANDLE_WIDTH, "px)") : "calc(anchor(".concat(safeAnchorName, " start) + ").concat(topPositionAdjustment(expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? $pos && $pos.nodeAfter && getNodeTypeWithLevel($pos.nodeAfter) || nodeType : nodeType, (dom === null || dom === void 0 ? void 0 : dom.getAttribute('layout')) || ''), "px)") }, bottom); } var height = editorExperiment('platform_editor_controls', 'variant1') ? getControlHeightCSSValue(getNodeHeight(dom, safeAnchorName, anchorRectCache) || 0, isSticky, isTopLevelNodeValue, "".concat(DRAG_HANDLE_HEIGHT), isLayoutColumn) : {}; return _objectSpread({ 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), top: getTopPosition(dom, nodeType) }, height); }, [anchorName, getPos, view, nodeType, macroInteractionUpdates, anchorRectCache, isTopLevelNodeValue, isLayoutColumn, recalculatePosition]); var calculatePositionOld = useCallback(function () { var pos = getPos(); var $pos = expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? typeof pos === 'number' && view.state.doc.resolve(pos) : pos && view.state.doc.resolve(pos); var parentPos = $pos && $pos.depth ? $pos.before() : undefined; var node = parentPos !== undefined ? view.state.doc.nodeAt(parentPos) : undefined; var parentNodeType = node === null || node === void 0 ? void 0 : node.type.name; var supportsAnchor = CSS.supports('top', "anchor(".concat(anchorName, " start)")) && CSS.supports('left', "anchor(".concat(anchorName, " start)")); var safeAnchorName = editorExperiment('platform_editor_controls', 'variant1') ? refreshAnchorName({ getPos: getPos, view: view, anchorName: anchorName }) : anchorName; var dom = view.dom.querySelector("[".concat(getAnchorAttrName(), "=\"").concat(safeAnchorName, "\"]")); var hasResizer = nodeType === 'table' || nodeType === 'mediaSingle'; var isExtension = nodeType === 'extension' || nodeType === 'bodiedExtension' || nodeType === 'multiBodiedExtension'; var isBlockCard = nodeType === 'blockCard' && !!blockCardWidth; var isEmbedCard = nodeType === 'embedCard'; var isMacroInteractionUpdates = macroInteractionUpdates && isExtension; var innerContainer = null; if (dom) { if (isEmbedCard) { innerContainer = dom.querySelector('.rich-media-item'); } else if (hasResizer) { innerContainer = dom.querySelector('.resizer-item'); } else if (isExtension) { innerContainer = dom.querySelector('.extension-container[data-layout]'); } else if (isBlockCard) { //specific to datasource blockCard innerContainer = dom.querySelector('.datasourceView-content-inner-wrap'); } } var isEdgeCase = (hasResizer || isExtension || isEmbedCard || isBlockCard) && innerContainer; var isSticky = shouldBeSticky(nodeType); if (su