UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

129 lines (127 loc) 4.83 kB
import { useCallback, useMemo, useState } from 'react'; import { akEditorCalculatedWideLayoutWidth, akEditorDefaultLayoutWidth, akEditorFullWidthLayoutWidth, akEditorGutterPadding, akEditorGutterPaddingDynamic, akEditorGutterPaddingReduced, akEditorFullPageNarrowBreakout, breakoutWideScaleRatio } from '@atlaskit/editor-shared-styles'; import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments'; export const SNAP_GAP = 8; const GUIDELINE_KEYS = { lineLength: 'grid', wide: 'wide', fullWidth: 'full_width' }; const CURRENT_LAYOUT_KEYS = { lineLength: 'center', wide: 'wide', fullWidth: 'full-width' }; const roundToNearest = (value, interval = 0.5) => Math.round(value / interval) * interval; export function useBreakoutGuidelines(getEditorWidth, isResizing, dynamicFullWidthGuidelineOffset = 0) { const widthState = getEditorWidth(); const { lineLength, wide, fullWidth } = useMemo(() => { if (!isResizing) { return {}; } const { width, lineLength } = widthState || {}; const wideCalWithRatio = lineLength ? Math.round(lineLength * breakoutWideScaleRatio) : undefined; // When page is full width, lineLength from widthState can be much wider than 760. // But the lineLength variable here is being used like a const 760. // when the page is full width, the calculation of wide is wrong. // Actuall the wide is the wide breakout point, which is const wide = editorExperiment('single_column_layouts', true) ? akEditorCalculatedWideLayoutWidth : wideCalWithRatio; const padding = width && width <= akEditorFullPageNarrowBreakout && editorExperiment('platform_editor_preview_panel_responsiveness', true, { exposure: true }) ? akEditorGutterPaddingReduced : akEditorGutterPaddingDynamic(); const layoutCalculatedWidth = width ? width - (padding + dynamicFullWidthGuidelineOffset) * 2 : undefined; const fullWidth = width && layoutCalculatedWidth ? Math.min(layoutCalculatedWidth, akEditorFullWidthLayoutWidth) : undefined; return { wide, fullWidth, // When page is full width, lineLength from widthState can be much wider than 760. // But the lineLength variable here is being used like a const 760. lineLength: editorExperiment('single_column_layouts', true) ? akEditorDefaultLayoutWidth : lineLength }; }, [widthState, isResizing, dynamicFullWidthGuidelineOffset]); // calculate snapping width const defaultSnappingWidths = useMemo(() => { if (!fullWidth || !wide || !lineLength || fullWidth <= (editorExperiment('single_column_layouts', true) ? akEditorDefaultLayoutWidth : lineLength)) { return null; } if (fullWidth - wide > SNAP_GAP) { return { lineLength, wide, fullWidth }; } if (fullWidth <= wide && fullWidth - lineLength > SNAP_GAP) { return { lineLength, fullWidth }; } return null; }, [fullWidth, lineLength, wide]); const snaps = useMemo(() => { if (!isResizing || !defaultSnappingWidths) { return null; } return { x: Object.values(defaultSnappingWidths) }; }, [defaultSnappingWidths, isResizing]); // calculate guidelines, and calculate which lines are active const [currentLayout, setCurrentLayout] = useState(null); const guidelines = useMemo(() => { const guidelines = []; if (!defaultSnappingWidths) { return guidelines; } Object.entries(defaultSnappingWidths).map(([key, value]) => { if (value) { guidelines.push({ key: `${GUIDELINE_KEYS[key]}_left`, position: { x: -roundToNearest(value / 2) }, active: currentLayout === CURRENT_LAYOUT_KEYS[key] }); guidelines.push({ key: `${GUIDELINE_KEYS[key]}_right`, position: { x: roundToNearest(value / 2) }, active: currentLayout === CURRENT_LAYOUT_KEYS[key] }); } }); return guidelines; }, [defaultSnappingWidths, currentLayout]); const setCurrentWidth = useCallback(newWidth => { if (typeof newWidth !== 'number') { setCurrentLayout(null); return; } if (lineLength && Math.abs(newWidth - lineLength) < SNAP_GAP / 2) { setCurrentLayout('center'); } else if (wide && Math.abs(newWidth - wide) < SNAP_GAP / 2) { setCurrentLayout('wide'); } else if (fullWidth && ( // we only allow snap from one side, so we don't use Math.abs here fullWidth + akEditorGutterPadding - newWidth < SNAP_GAP / 2 || newWidth >= fullWidth)) { setCurrentLayout('full-width'); } else { setCurrentLayout(null); } }, [lineLength, wide, fullWidth]); return { snaps, currentLayout, guidelines, setCurrentWidth }; }