UNPKG

@atlaskit/editor-plugin-floating-toolbar

Version:

Floating toolbar plugin for @atlaskit/editor-core

153 lines (149 loc) 6.98 kB
/** * @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 const toolbarScrollButtons = css({ display: 'grid', gridTemplateColumns: '1fr 1fr', gridGap: "var(--ds-space-050, 4px)", padding: `${"var(--ds-space-050, 4px)"} ${"var(--ds-space-100, 8px)"}`, borderLeft: `solid ${"var(--ds-border, #0B120E24)"} ${"var(--ds-border-width, 1px)"}`, flexShrink: 0, alignItems: 'center' }); const LeftIcon = ChevronLeftLargeIcon; const RightIcon = ChevronRightLargeIcon; // Remove this component (replaced by ScrollButton) as part of platform_editor_controls clean up export const ScrollButtons = ({ intl, scrollContainerRef, node, disabled, areAnyNewToolbarFlagsEnabled }) => { const buttonsContainerRef = useRef(null); const [needScroll, setNeedScroll] = useState(false); const [canScrollLeft, setCanScrollLeft] = useState(true); const [canScrollRight, setCanScrollRight] = useState(true); const setCanScrollDebounced = rafSchedule(() => { // Refs are null before mounting and after unmount if (!scrollContainerRef.current) { return; } const { scrollLeft, scrollWidth, offsetWidth } = scrollContainerRef.current; setCanScrollLeft(scrollLeft > 0); setCanScrollRight(scrollLeft + offsetWidth < scrollWidth - 1); // -1 to account for half pixel }); const onScroll = () => setCanScrollDebounced(); const scrollLeft = () => { var _scrollContainerRef$c, _scrollContainerRef$c2, _scrollContainerRef$c3; const { width: scrollContainerWidth = 0 } = ((_scrollContainerRef$c = scrollContainerRef.current) === null || _scrollContainerRef$c === void 0 ? void 0 : _scrollContainerRef$c.getBoundingClientRect()) || {}; const scrollLeft = ((_scrollContainerRef$c2 = scrollContainerRef.current) === null || _scrollContainerRef$c2 === void 0 ? void 0 : _scrollContainerRef$c2.scrollLeft) || 0; // scroll to current position - scroll container width const scrollTo = scrollLeft - scrollContainerWidth; (_scrollContainerRef$c3 = scrollContainerRef.current) === null || _scrollContainerRef$c3 === void 0 ? void 0 : _scrollContainerRef$c3.scrollTo({ top: 0, left: scrollTo, behavior: 'smooth' }); }; const scrollRight = () => { var _scrollContainerRef$c4, _scrollContainerRef$c5, _scrollContainerRef$c6; const { width: scrollContainerWidth = 0 } = ((_scrollContainerRef$c4 = scrollContainerRef.current) === null || _scrollContainerRef$c4 === void 0 ? void 0 : _scrollContainerRef$c4.getBoundingClientRect()) || {}; const scrollLeft = ((_scrollContainerRef$c5 = scrollContainerRef.current) === null || _scrollContainerRef$c5 === void 0 ? void 0 : _scrollContainerRef$c5.scrollLeft) || 0; // scroll to current position + scroll container width const scrollTo = scrollLeft + scrollContainerWidth; (_scrollContainerRef$c6 = scrollContainerRef.current) === null || _scrollContainerRef$c6 === void 0 ? void 0 : _scrollContainerRef$c6.scrollTo({ top: 0, left: scrollTo, behavior: 'smooth' }); }; const resizeObserver = new ResizeObserver(t => { var _scrollContainerRef$c7, _scrollContainerRef$c8, _scrollContainerRef$c9; const widthNeededToShowAllItems = ((_scrollContainerRef$c7 = scrollContainerRef.current) === null || _scrollContainerRef$c7 === void 0 ? void 0 : _scrollContainerRef$c7.scrollWidth) || 0; // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting const availableSpace = (_scrollContainerRef$c8 = scrollContainerRef.current) === null || _scrollContainerRef$c8 === void 0 ? void 0 : (_scrollContainerRef$c9 = _scrollContainerRef$c8.parentNode) === null || _scrollContainerRef$c9 === void 0 ? void 0 : _scrollContainerRef$c9.offsetWidth; if (availableSpace >= widthNeededToShowAllItems) { setNeedScroll(false); } else { setNeedScroll(true); onScroll(); } }); useEffect(() => { onScroll(); const 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 () => { 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(() => { const 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 ? 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; };