UNPKG

@atlaskit/editor-plugin-floating-toolbar

Version:

Floating toolbar plugin for @atlaskit/editor-core

163 lines (159 loc) 7.74 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; /** * @jsxRuntime classic * @jsx jsx */ import React, { useEffect, 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 rafSchedule from 'raf-schd'; import { messages } from '@atlaskit/editor-common/floating-toolbar'; import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui'; import ChevronLeftLargeIcon from '@atlaskit/icon/core/chevron-left'; import ChevronRightLargeIcon from '@atlaskit/icon/core/chevron-right'; // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage var toolbarScrollButtons = css({ display: 'grid', gridTemplateColumns: '1fr 1fr', gridGap: "var(--ds-space-050, 4px)", padding: "var(--ds-space-050, 4px)".concat(" ", "var(--ds-space-100, 8px)"), borderLeft: "solid ".concat("var(--ds-border, #0B120E24)", " ", "var(--ds-border-width, 1px)"), flexShrink: 0, alignItems: 'center' }); var LeftIcon = ChevronLeftLargeIcon; var RightIcon = ChevronRightLargeIcon; // Remove this component (replaced by ScrollButton) as part of platform_editor_controls clean up export var ScrollButtons = function ScrollButtons(_ref) { var intl = _ref.intl, scrollContainerRef = _ref.scrollContainerRef, node = _ref.node, disabled = _ref.disabled, areAnyNewToolbarFlagsEnabled = _ref.areAnyNewToolbarFlagsEnabled; var buttonsContainerRef = useRef(null); var _useState = useState(false), _useState2 = _slicedToArray(_useState, 2), needScroll = _useState2[0], setNeedScroll = _useState2[1]; var _useState3 = useState(true), _useState4 = _slicedToArray(_useState3, 2), canScrollLeft = _useState4[0], setCanScrollLeft = _useState4[1]; var _useState5 = useState(true), _useState6 = _slicedToArray(_useState5, 2), canScrollRight = _useState6[0], setCanScrollRight = _useState6[1]; var setCanScrollDebounced = rafSchedule(function () { // Refs are null before mounting and after unmount if (!scrollContainerRef.current) { return; } var _scrollContainerRef$c = scrollContainerRef.current, scrollLeft = _scrollContainerRef$c.scrollLeft, scrollWidth = _scrollContainerRef$c.scrollWidth, offsetWidth = _scrollContainerRef$c.offsetWidth; setCanScrollLeft(scrollLeft > 0); setCanScrollRight(scrollLeft + offsetWidth < scrollWidth - 1); // -1 to account for half pixel }); var onScroll = function onScroll() { return setCanScrollDebounced(); }; var scrollLeft = function scrollLeft() { var _scrollContainerRef$c2, _scrollContainerRef$c3, _scrollContainerRef$c4; var _ref2 = ((_scrollContainerRef$c2 = scrollContainerRef.current) === null || _scrollContainerRef$c2 === void 0 ? void 0 : _scrollContainerRef$c2.getBoundingClientRect()) || {}, _ref2$width = _ref2.width, scrollContainerWidth = _ref2$width === void 0 ? 0 : _ref2$width; var scrollLeft = ((_scrollContainerRef$c3 = scrollContainerRef.current) === null || _scrollContainerRef$c3 === void 0 ? void 0 : _scrollContainerRef$c3.scrollLeft) || 0; // scroll to current position - scroll container width var scrollTo = scrollLeft - scrollContainerWidth; (_scrollContainerRef$c4 = scrollContainerRef.current) === null || _scrollContainerRef$c4 === void 0 || _scrollContainerRef$c4.scrollTo({ top: 0, left: scrollTo, behavior: 'smooth' }); }; var scrollRight = function scrollRight() { var _scrollContainerRef$c5, _scrollContainerRef$c6, _scrollContainerRef$c7; var _ref3 = ((_scrollContainerRef$c5 = scrollContainerRef.current) === null || _scrollContainerRef$c5 === void 0 ? void 0 : _scrollContainerRef$c5.getBoundingClientRect()) || {}, _ref3$width = _ref3.width, scrollContainerWidth = _ref3$width === void 0 ? 0 : _ref3$width; var scrollLeft = ((_scrollContainerRef$c6 = scrollContainerRef.current) === null || _scrollContainerRef$c6 === void 0 ? void 0 : _scrollContainerRef$c6.scrollLeft) || 0; // scroll to current position + scroll container width var scrollTo = scrollLeft + scrollContainerWidth; (_scrollContainerRef$c7 = scrollContainerRef.current) === null || _scrollContainerRef$c7 === void 0 || _scrollContainerRef$c7.scrollTo({ top: 0, left: scrollTo, behavior: 'smooth' }); }; var resizeObserver = new ResizeObserver(function (t) { var _scrollContainerRef$c8, _scrollContainerRef$c9; var widthNeededToShowAllItems = ((_scrollContainerRef$c8 = scrollContainerRef.current) === null || _scrollContainerRef$c8 === void 0 ? void 0 : _scrollContainerRef$c8.scrollWidth) || 0; // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting var availableSpace = (_scrollContainerRef$c9 = scrollContainerRef.current) === null || _scrollContainerRef$c9 === void 0 || (_scrollContainerRef$c9 = _scrollContainerRef$c9.parentNode) === null || _scrollContainerRef$c9 === void 0 ? void 0 : _scrollContainerRef$c9.offsetWidth; if (availableSpace >= widthNeededToShowAllItems) { setNeedScroll(false); } else { setNeedScroll(true); onScroll(); } }); useEffect(function () { onScroll(); var scrollContainerRefCurrent = scrollContainerRef.current; if (scrollContainerRefCurrent) { // enable/disable scroll buttons depending on scroll position // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners scrollContainerRefCurrent.addEventListener('scroll', onScroll); // watch for toolbar resize and show/hide scroll buttons if needed resizeObserver.observe(scrollContainerRefCurrent); } return function () { if (scrollContainerRefCurrent) { // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners scrollContainerRefCurrent.removeEventListener('scroll', onScroll); resizeObserver.unobserve(scrollContainerRefCurrent); } setCanScrollDebounced.cancel(); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(function () { var scrollContainerRefCurrent = scrollContainerRef.current; if (scrollContainerRefCurrent) { var _scrollContainerRefCu; // reset scroll position when switching from one node with toolbar to another // scroll to made optional as it may not be rendered in testing env (_scrollContainerRefCu = scrollContainerRefCurrent.scrollTo) === null || _scrollContainerRefCu === void 0 || _scrollContainerRefCu.call(scrollContainerRefCurrent, { left: 0 }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [node.type]); return needScroll ? jsx("div", { ref: buttonsContainerRef, css: toolbarScrollButtons // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 , className: "scroll-buttons" }, jsx(Button, { title: intl.formatMessage(messages.floatingToolbarScrollLeft), icon: jsx(LeftIcon, { label: intl.formatMessage(messages.floatingToolbarScrollLeft), size: "small" }), onClick: scrollLeft, disabled: !canScrollLeft || disabled, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled }), jsx(Button, { title: intl.formatMessage(messages.floatingToolbarScrollRight), icon: jsx(RightIcon, { label: intl.formatMessage(messages.floatingToolbarScrollRight), size: "small" }), onClick: scrollRight, disabled: !canScrollRight || disabled, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled })) : null; };