UNPKG

@atlaskit/editor-common

Version:

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

104 lines (102 loc) 3.77 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; /** * @jsxRuntime classic * @jsx jsx */ import React, { Fragment, useContext, useMemo, useRef, useState } from 'react'; // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766 import { css, jsx } from '@emotion/react'; import memoizeOne from 'memoize-one'; import rafSchedule from 'raf-schd'; import { WidthObserver } from '@atlaskit/width-detector'; import { isSSR } from '../../core-utils/is-ssr'; var styles = css({ position: 'relative', width: '100%' }); var SCROLLBAR_WIDTH = 30; export function getBreakpoint() { var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var MAX_S = 1266; var MAX_M = 2146; if (width >= MAX_S && width < MAX_M) { return 'M'; } else if (width >= MAX_M) { return 'L'; } return 'S'; } export function createWidthContext() { var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; return { width: width, breakpoint: getBreakpoint(width) }; } export var WidthContext = /*#__PURE__*/React.createContext(createWidthContext()); var Provider = WidthContext.Provider, Consumer = WidthContext.Consumer; /** * 🧱 Internal function: Editor FE Platform * * Returns the width of the document body. * * This function is memoized to avoid forcing a layout reflow multiple times. * It uses `document.body.offsetWidth` as the source of the width, which can lead to * a layout reflow if accessed repeatedly. To mitigate performance issues, the result * is cached using `memoizeOne`. * * @returns {number} The width of the document body or 0 if the document is undefined. */ export var getBodyWidth = memoizeOne(function () { var _document$body$offset, _document$body; return isSSR() ? 0 : (_document$body$offset = (_document$body = document.body) === null || _document$body === void 0 ? void 0 : _document$body.offsetWidth) !== null && _document$body$offset !== void 0 ? _document$body$offset : 0; }); export var WidthProvider = function WidthProvider(_ref) { var className = _ref.className, shouldCheckExistingValue = _ref.shouldCheckExistingValue, children = _ref.children; var existingContextValue = useContext(WidthContext); var _useState = useState(getBodyWidth), _useState2 = _slicedToArray(_useState, 2), width = _useState2[0], setWidth = _useState2[1]; var widthRef = useRef(width); var isMountedRef = useRef(true); var providerValue = useMemo(function () { return createWidthContext(width); }, [width]); var updateWidth = useMemo(function () { return rafSchedule(function (nextWidth) { var currentWidth = widthRef.current || 0; // Ignore changes that are less than SCROLLBAR_WIDTH, otherwise it can cause infinite re-scaling if (Math.abs(currentWidth - nextWidth) < SCROLLBAR_WIDTH) { return; } // Avoid React memory leak by checking if the component is still mounted if (!isMountedRef.current) { return; } setWidth(nextWidth); }); }, []); var skipWidthDetection = shouldCheckExistingValue && existingContextValue.width > 0; React.useLayoutEffect(function () { isMountedRef.current = true; return function () { isMountedRef.current = false; }; }, []); return jsx("div", { css: styles // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 , className: className }, !skipWidthDetection && jsx(Fragment, null, jsx(WidthObserver, { setWidth: updateWidth, offscreen: true }), jsx(Provider, { value: providerValue }, children)), skipWidthDetection && children); }; export { Consumer as WidthConsumer };