UNPKG

@atlaskit/editor-plugin-block-controls

Version:

Block controls plugin for @atlaskit/editor-core

371 lines (368 loc) • 9.75 kB
import { DRAG_HANDLE_WIDTH } from '@atlaskit/editor-common/styles/drag-handle'; import { breakoutResizableNodes, getBreakoutResizableNodes } from '@atlaskit/editor-common/utils'; import { akEditorUnitZIndex, akRichMediaResizeZIndex } from '@atlaskit/editor-shared-styles/constants'; import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled'; import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure'; export const ACTIVE_DRAG_HANDLE_ATTR = 'data-active-drag-handle'; export const ACTIVE_QUICK_INSERT_ATTR = 'data-active-quick-insert'; export const BLOCK_CONTROLS_SURFACE_SELECTOR = '[data-editor-block-controls-surface]'; export const ACTIVE_DRAG_HANDLE_FALLBACK_ANCHOR_NAME = '--editor-block-controls-active-drag-handle-anchor'; export const ACTIVE_QUICK_INSERT_FALLBACK_ANCHOR_NAME = '--editor-block-controls-active-quick-insert-anchor'; export const DRAG_HANDLE_HEIGHT = 24; export const DRAG_HANDLE_BORDER_RADIUS = 4; export const DRAG_HANDLE_ZINDEX = akRichMediaResizeZIndex + akEditorUnitZIndex; //place above legacy resizer const LEGACY_DRAG_HANDLE_DEFAULT_GAP = 8; const MIGRATED_DRAG_HANDLE_DEFAULT_GAP = 12; export const DRAG_HANDLE_NARROW_GAP = 4; export const DRAG_HANDLE_MAX_GAP = 12; export const DRAG_HANDLE_SYNCED_BLOCK_GAP = 2.5; export const DRAG_HANDLE_MAX_WIDTH_PLUS_GAP = DRAG_HANDLE_WIDTH + DRAG_HANDLE_MAX_GAP; // Non-resizable/default-sized nodes get the same gap as resizable/breakout nodes // (DRAG_HANDLE_MAX_GAP) once the registry-backed surfaces are on; kept at the legacy value // otherwise to avoid an unrelated visual change for consumers still on the old decoration path. const getDragHandleDefaultGap = () => isExperimentEnabled('platform_editor_block_control_migration') ? MIGRATED_DRAG_HANDLE_DEFAULT_GAP : LEGACY_DRAG_HANDLE_DEFAULT_GAP; export const DRAG_HANDLE_DIVIDER_TOP_ADJUSTMENT = 4 + 2; // 4px for the divider vertical padding and 2px for the divider height export const DRAG_HANDLE_H1_TOP_ADJUSTMENT = 5; export const DRAG_HANDLE_H2_TOP_ADJUSTMENT = 2; export const DRAG_HANDLE_H3_TOP_ADJUSTMENT = 1; export const DRAG_HANDLE_H4_TOP_ADJUSTMENT = 3; export const DRAG_HANDLE_H5_TOP_ADJUSTMENT = 3; export const DRAG_HANDLE_H6_TOP_ADJUSTMENT = 3; export const DRAG_HANDLE_LAYOUT_SECTION_TOP_ADJUSTMENT = 8; export const DRAG_HANDLE_PARAGRAPH_TOP_ADJUSTMENT = 2; export const DRAG_HANDLE_PARAGRAPH_SMALL_TOP_ADJUSTMENT = 0; export const DRAG_HANDLE_WRAPPED_MEDIA_EMBED_TOP_ADJUSTMENT = 8; export const STICKY_CONTROLS_TOP_MARGIN = 8; export const STICKY_CONTROLS_TOP_MARGIN_FOR_STICKY_HEADER = 24; export const QUICK_INSERT_HEIGHT = 24; export const QUICK_INSERT_WIDTH = 24; export const QUICK_INSERT_DIMENSIONS = { width: QUICK_INSERT_WIDTH, height: QUICK_INSERT_HEIGHT }; export const QUICK_INSERT_LEFT_OFFSET = 16; const nodeTypeExcludeList = ['embedCard', 'mediaSingle', 'table']; export const dragHandleGap = (nodeType, parentNodeType) => { if (parentNodeType === 'syncBlock' || parentNodeType === 'bodiedSyncBlock') { return DRAG_HANDLE_SYNCED_BLOCK_GAP; } if (parentNodeType && parentNodeType !== 'doc') { return DRAG_HANDLE_NARROW_GAP; } let breakoutResizableNodesList = []; if (isExperimentEnabled('platform_editor_lovability_resize_extensions')) { breakoutResizableNodesList = getBreakoutResizableNodes(); } else { breakoutResizableNodesList = expValEqualsNoExposure('platform_editor_lovability_resize_dividers_panels', 'isEnabled', true) ? [...breakoutResizableNodes, 'rule', 'panel'] : breakoutResizableNodes; } if (breakoutResizableNodesList.includes(nodeType)) { if (nodeType === 'layoutSection') { return DRAG_HANDLE_MAX_GAP + 20; } else { return DRAG_HANDLE_MAX_GAP; } } if (nodeType === 'layoutSection') { return getDragHandleDefaultGap() + 20; } if (nodeTypeExcludeList.includes(nodeType)) { return DRAG_HANDLE_MAX_GAP; } return getDragHandleDefaultGap(); }; // use for returning gap only for root level elements export const rootElementGap = nodeType => { let breakoutResizableNodesList = []; if (isExperimentEnabled('platform_editor_lovability_resize_extensions')) { breakoutResizableNodesList = getBreakoutResizableNodes(); } else { breakoutResizableNodesList = expValEqualsNoExposure('platform_editor_lovability_resize_dividers_panels', 'isEnabled', true) ? [...breakoutResizableNodes, 'rule', 'panel'] : breakoutResizableNodes; } if (nodeTypeExcludeList.includes(nodeType) || breakoutResizableNodesList.includes(nodeType)) { if (nodeType === 'layoutSection') { return DRAG_HANDLE_MAX_GAP + 20; } else { return DRAG_HANDLE_MAX_GAP; } } if (nodeType === 'layoutSection') { return DRAG_HANDLE_MAX_GAP + 12; } return getDragHandleDefaultGap(); }; export const getNestedNodeLeftPaddingMargin = nodeType => { switch (nodeType) { case 'bodiedExtension': return '28px'; case 'multiBodiedExtension': if (expValEquals('confluence_native_tabs_experiment', 'isEnabled', true)) { return '28px'; } return `${DRAG_HANDLE_WIDTH + DRAG_HANDLE_NARROW_GAP}px`; case 'expand': case 'nestedExpand': return '24px'; case 'layoutColumn': return '20px'; case 'panel': return '40px'; case 'tableCell': return '8px'; case 'tableHeader': return '8px'; default: return `${DRAG_HANDLE_WIDTH + DRAG_HANDLE_NARROW_GAP}px`; } }; export const topPositionAdjustment = (nodeType, layout) => { if (editorExperiment('advanced_layouts', true)) { switch (nodeType) { case 'layoutSection': return DRAG_HANDLE_LAYOUT_SECTION_TOP_ADJUSTMENT; } } if ((nodeType === 'mediaSingle' || nodeType === 'embedCard') && layout && ['wrap-left', 'wrap-right'].includes(layout)) { return DRAG_HANDLE_WRAPPED_MEDIA_EMBED_TOP_ADJUSTMENT; } switch (nodeType) { case 'rule': return -DRAG_HANDLE_DIVIDER_TOP_ADJUSTMENT; case 'table': return DRAG_HANDLE_HEIGHT; case 'paragraph': return DRAG_HANDLE_PARAGRAPH_TOP_ADJUSTMENT; case 'paragraph-small': return DRAG_HANDLE_PARAGRAPH_SMALL_TOP_ADJUSTMENT; case 'heading-1': return DRAG_HANDLE_H1_TOP_ADJUSTMENT; case 'heading-2': return DRAG_HANDLE_H2_TOP_ADJUSTMENT; case 'heading-3': return -DRAG_HANDLE_H3_TOP_ADJUSTMENT; case 'heading-4': return -DRAG_HANDLE_H4_TOP_ADJUSTMENT; case 'heading-5': return -DRAG_HANDLE_H5_TOP_ADJUSTMENT; case 'heading-6': return -DRAG_HANDLE_H6_TOP_ADJUSTMENT; default: return 0; } }; export const spacingBetweenNodesForPreview = { paragraph: { top: '0.75rem', bottom: '0' }, heading1: { top: '1.45833em', bottom: '0' }, heading2: { top: '1.4em', bottom: '0' }, heading3: { top: '1.31249em', bottom: '0' }, heading4: { top: '1.25em', bottom: '0' }, heading5: { top: '1.45833em', bottom: '0' }, heading6: { top: '1.59091em', bottom: '0' }, table: { top: '0', bottom: '0' }, bulletList: { top: '10px', bottom: '0' }, orderedList: { top: '10px', bottom: '0' }, decisionList: { top: '0.5rem', bottom: '0' }, taskList: { top: '0.75rem', bottom: '0' }, codeBlock: { top: '0.75rem', bottom: '0' }, panel: { top: '0.75rem', bottom: '0' }, rule: { top: '1.5rem', bottom: '1.5rem' }, mediaSingle: { top: '24px', bottom: '24px' }, media: { top: '24px', bottom: '24px' }, bodiedExtension: { top: '0', bottom: '0' }, multiBodiedExtension: { top: '0', bottom: '0' }, extension: { top: '0', bottom: '0' }, layoutSection: { top: '0', bottom: '0' }, blockquote: { top: '0', bottom: '0' }, embedCard: { top: '24px', bottom: '24px' }, blockCard: { top: '0.75rem', bottom: '0' }, default: { top: '0', bottom: '0' } }; // This table contains the "margins" of different nodes // Note this is not the actually margin of the DOM elements, // but a percepted margin, e.g. a paragraph has additional margin // due to the line height and the white spaces. export const nodeMargins = { table: { top: 24, bottom: 16 }, paragraph: { top: 12, bottom: 6 }, bulletList: { top: 16, bottom: 0 }, orderedList: { top: 16, bottom: 0 }, decisionList: { top: 12, bottom: 0 }, taskList: { top: 8, bottom: 0 }, codeBlock: { top: 12, bottom: 0 }, panel: { top: 8, bottom: 0 }, rule: { top: 24, bottom: 24 }, mediaSingle: { top: 24, bottom: 24 }, media: { top: 24, bottom: 24 }, bodiedExtension: { top: 0, bottom: 0 }, multiBodiedExtension: { top: 0, bottom: 0 }, extension: { top: 12, bottom: 12 }, heading1: { top: 40, bottom: 0 }, heading2: { top: 40, bottom: 0 }, heading3: { top: 36, bottom: 0 }, heading4: { top: 22, bottom: 0 }, heading5: { top: 22, bottom: 0 }, heading6: { top: 18, bottom: 0 }, layoutSection: { top: 8, bottom: 0 }, blockquote: { top: 12, bottom: 0 }, expand: { top: 4, bottom: 0 }, nestedExpand: { top: 1, bottom: 0 }, default: { top: 0, bottom: 0 } }; export const DEFAULT_COLUMN_DISTRIBUTIONS = { 1: 100, 2: 50, 3: 33.33, 4: 25, 5: 20 };