| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| import * as React from "react"; |
| import { useEffect, useRef, SFC } from "react"; |
| import { useConfig } from "../../../../docz-lib/docz/dist"; |
| import { Controlled as BaseCodeMirror } from "react-codemirror2"; |
| import PerfectScrollbar from "react-perfect-scrollbar"; |
| import styled from "styled-components"; |
| |
| import { get } from "~utils/theme"; |
| |
| import { ScrollbarStyles } from "./ps-scrollbar"; |
| import * as themes from "./themes"; |
| |
| import "codemirror/mode/markdown/markdown"; |
| import "codemirror/mode/javascript/javascript"; |
| import "codemirror/mode/jsx/jsx"; |
| import "codemirror/mode/css/css"; |
| import "codemirror/addon/edit/matchbrackets"; |
| import "codemirror/addon/edit/closetag"; |
| import "codemirror/addon/fold/xml-fold"; |
| |
| const Scrollbar = styled(PerfectScrollbar)` |
| overflow: auto; |
| position: relative; |
| max-height: ${p => 25 * p.linesToScroll}px; |
| |
| .ps__rail-y { |
| z-index: 9; |
| opacity: 0.4; |
| } |
| `; |
| |
| const preStyles = get("styles.pre"); |
| const EditorStyled = styled(BaseCodeMirror)` |
| ${themes.dark}; |
| ${themes.light}; |
| position: relative; |
| flex: 1; |
| |
| .CodeMirror { |
| max-width: 100%; |
| height: 100%; |
| } |
| |
| .CodeMirror-gutters { |
| left: 1px !important; |
| } |
| |
| .CodeMirror-lines { |
| padding: 10px 0; |
| box-sizing: content-box; |
| } |
| |
| .CodeMirror-line { |
| padding: 0 10px; |
| } |
| |
| .CodeMirror-linenumber { |
| padding: 0 7px 0 5px; |
| } |
| |
| &, |
| .CodeMirror pre { |
| ${preStyles}; |
| } |
| `; |
| |
| const scrollbarOpts = { |
| wheelSpeed: 2, |
| wheelPropagation: true, |
| minScrollbarLength: 20, |
| suppressScrollX: true |
| }; |
| |
| const noCurrent = (val: any) => !val || !val.current; |
| |
| const CodeMirror: SFC<any> = props => { |
| const { themeConfig } = useConfig(); |
| const editor = useRef < any > null; |
| const forceUpdateEditorTimeout = useRef(0); |
| const previousEditor = useRef(0); |
| const linesToScroll = themeConfig.linesToScrollEditor || 14; |
| |
| const editorProps = { |
| ...props, |
| editorDidMount: (codemirror: any) => { |
| props.editorDidMount && props.editorDidMount(codemirror); |
| editor.current = codemirror; |
| } |
| }; |
| |
| const refreshCodeMirror = () => { |
| if (noCurrent(editor)) return; |
| editor.current.refresh(); |
| }; |
| |
| const clearForceUpdateCodeMirror = () => { |
| if (noCurrent(forceUpdateEditorTimeout)) return; |
| clearTimeout(forceUpdateEditorTimeout.current); |
| }; |
| |
| const forceUpdateCodeMirror = () => { |
| if (noCurrent(editor)) return; |
| clearForceUpdateCodeMirror(); |
| |
| forceUpdateEditorTimeout.current = setTimeout(() => { |
| const currentHeight = editor.current.getScrollInfo().height || 0; |
| const hasNoHeight = currentHeight <= 0; |
| |
| // Don't refresh if no height (CodeMirror is not visible) or |
| // Don't refresh if same height |
| if (hasNoHeight || previousEditor === currentHeight) return; |
| refreshCodeMirror(); |
| previousEditor.current = editor.current.getScrollInfo().height || 0; |
| }); |
| }; |
| |
| useEffect(() => { |
| forceUpdateCodeMirror(); |
| return () => clearForceUpdateCodeMirror(); |
| }, []); |
| |
| return ( |
| <React.Fragment> |
| <ScrollbarStyles /> |
| <Scrollbar options={scrollbarOpts} linesToScroll={linesToScroll}> |
| <EditorStyled {...editorProps} /> |
| </Scrollbar> |
| </React.Fragment> |
| ); |
| }; |
| |
| export default CodeMirror; |