import * as React from 'react'; import { useEffect, useState, useContext, CSSProperties, useRef, useCallback, FunctionComponent, useMemo, } from 'react'; import { EditorViewContext } from '../../contexts/EditorViewContext'; import { FontInfoContext } from '../../contexts/FontInfoContext'; import { LayoutInfoContext } from '../../contexts/LayoutInfoContext'; import { MouseMonitorContext } from '../../contexts/MouseMonitorContext'; import { useOnClickInside, useRefEffect } from '../../hooks'; import useTimeoutFn from '../../hooks/useTimeoutFn'; import { px } from '../../utilities'; import { EditorOption, IComputedEditorOptions, } from '../../vs/editor/common/config/editorOptions'; import { Position } from '../../vs/editor/common/core/position'; import { WritingMode } from '../../config/writingMode'; import { HorizontalScrollbar } from '../horizontalScrollbar'; import { VerticalScrollbar } from '../verticalScrollbar'; import './EditorScrollbar.css'; type Props = { options: IComputedEditorOptions; }; export const EditorScrollbar: FunctionComponent = (props) => { const { children, options } = props; const { editor, writingMode, renderingContext: ctx, } = useContext(EditorViewContext); const { layoutInfo } = useContext(LayoutInfoContext); const { fontInfo } = useContext(FontInfoContext); const { mouseDownState } = useContext(MouseMonitorContext); const [left, setLeft] = useState('unset'); const [right, setRight] = useState(0); const [top, setTop] = useState(0); const [width, setWidth] = useState(0); const [height, setHeight] = useState(0); const editorScrollableRef = useRef(null); // const _onScrollTimeout = useRef(()=>{ // }); useOnClickInside(editorScrollableRef, (evt) => { // evt.stopPropagation(); evt.preventDefault(); editor.focus(); }); const [isReady, clear, set] = useTimeoutFn(() => { onScrollTimeout(); }, 0); const onScrollTimeout = useCallback(() => { const rect = editorScrollableRef.current?.getBoundingClientRect(); if (!rect) { return; } if (mouseDownState.leftButton) { const modelData = editor.getModelData(); if (!modelData) { return; } const pos = editor.getPosition(); if (!pos) { return; } const viewPosition = modelData.viewModel.coordinatesConverter.convertModelPositionToViewPosition( pos ); if (mouseDownState.getPosition().y < rect.top) { modelData?.view.viewController.__moveToSelect( new Position(viewPosition.lineNumber - 1, viewPosition.column) ); } else if (rect.bottom < mouseDownState.getPosition().y) { modelData?.view.viewController.__moveToSelect( new Position(viewPosition.lineNumber + 1, viewPosition.column) ); } } if (mouseDownState.getPosition().y < rect.top) { set(); return; } if (rect.bottom < mouseDownState.getPosition().y) { set(); return; } }, [mouseDownState, editor, set]); const onMouseMove = useCallback( (evt: MouseEvent) => { if (!mouseDownState.leftButton) { return; } if (editorScrollableRef.current) { const rect = editorScrollableRef.current.getBoundingClientRect(); if (!rect) { return; } if (mouseDownState.getPosition().y < rect.top) { set(); } if (rect.bottom < mouseDownState.getPosition().y) { set(); } } }, [set, mouseDownState] ); useEffect(() => { document.addEventListener('mousemove', onMouseMove); return () => { document.removeEventListener('mousemove', onMouseMove); }; }, []); const leftToRightHorizontalWriting = useMemo( () => writingMode === WritingMode.LeftToRightHorizontalWriting, [writingMode] ); useEffect(() => { if (leftToRightHorizontalWriting) { setLeft(px(layoutInfo.contentLeft)); setTop(0); const minimap = options.get(EditorOption.minimap); const side = minimap.side; if (side === 'right') { setWidth(layoutInfo.contentWidth + layoutInfo.minimap.minimapWidth); } else { setWidth(layoutInfo.contentWidth); } setHeight(layoutInfo.height); return; } if (writingMode === WritingMode.RightToLeftVerticalWriting) { setLeft('unset'); setTop(layoutInfo.contentLeft); setRight(0); const minimap = options.get(EditorOption.minimap); const side = minimap.side; if (side === 'right') { setHeight(layoutInfo.contentWidth + layoutInfo.minimap.minimapWidth); } else { setHeight(layoutInfo.contentWidth); } setWidth(layoutInfo.height); return; } }, [layoutInfo, writingMode, leftToRightHorizontalWriting]); const horizontalScrollbarSize = useMemo(() => {}, []); const verticalScrollbarVisibleSize = useMemo( () => leftToRightHorizontalWriting ? layoutInfo.height : layoutInfo.contentWidth, [leftToRightHorizontalWriting, layoutInfo] ); const verticalScrollbarSize = useMemo( () => leftToRightHorizontalWriting ? layoutInfo.verticalScrollbarWidth : layoutInfo.horizontalScrollbarHeight, [leftToRightHorizontalWriting, layoutInfo] ); if (!options) { return <>; } const style: CSSProperties = { top: `${top}px`, left, right: `${right}px`, width: `${width}px`, height: `${height}px`, fontFamily: fontInfo.fontFamily, letterSpacing: fontInfo.letterSpacing, }; if (!ctx) { return <>; } return (
{children} { leftToRightHorizontalWriting ? editor.setScrollTop(scroll) : editor.setScrollLeft(scroll); }} /> { leftToRightHorizontalWriting ? editor.setScrollLeft(scroll) : editor.setScrollTop(scroll); }} />
); };