import * as React from 'react'; import { useMemo, useCallback, useState } from 'react'; import { useConfig, UseConfigObj } from 'docz'; import styled from 'styled-components'; import getter from 'lodash/get'; import { ClipboardAction } from './elements'; import { get } from '../Playground/theme'; import CodeMirror from '../CodeMirror'; const getLanguage = (children: any) => { const defaultLanguage = 'jsx'; if (typeof children === 'string') return defaultLanguage; const language = getter(children, 'props.props.className') || defaultLanguage; const result = language.replace('language-', ''); if (result === 'js' || result === 'javascript') return 'jsx'; if (result === 'ts' || result === 'tsx' || result === 'typescript') { return 'text/typescript'; } return result; }; const getChildren = (children: any) => children && typeof children !== 'string' ? getter(children, 'props.children') : children; const Wrapper = styled.div` margin: 30px 0; position: relative; width: 100%; border: 1px solid ${get('colors.border')}; `; const Actions = styled.div` z-index: 999; position: absolute; top: 0; right: 0; display: flex; flex-direction: column; align-items: center; padding: 5px 10px; background: transparent; `; export interface EditorProps { children: any; className?: string; editorClassName?: string; actions?: React.ReactNode; readOnly?: boolean; mode?: string; matchBrackets?: boolean; indentUnit?: number; onChange?: (code: string) => any; language?: string; withLastLine?: boolean; } export const Editor: React.FC = ({ mode, children, actions, onChange, className, editorClassName, language: defaultLanguage, ...props }) => { const config = useConfig(); const initialCode = useMemo(() => getChildren(children), [children]); const [code, setCode] = useState(initialCode); const language = defaultLanguage || getLanguage(children); const options = { ...props, tabSize: 2, mode: language || mode, lineNumbers: true, lineWrapping: true, autoCloseTags: true, theme: 'docz-light', }; const onEditorDidMount = (editor: any) => { if (editor) removeLastLine(editor); }; const removeLastLine = useCallback( (editor: any) => { if (editor && !props.withLastLine && props.readOnly) { const lastLine = editor.lastLine(); editor.doc.replaceRange('', { line: lastLine - 1 }, { line: lastLine }); } }, [props.withLastLine, props.readOnly] ); const handleChange = useCallback( (editor: any, data: any, code: string) => { onChange && onChange(code); setCode(code); }, [code] ); const editorProps = (config: UseConfigObj) => { return { value: code, className: editorClassName, editorDidMount: onEditorDidMount, onBeforeChange: handleChange, options: { ...options, theme: options.theme, }, }; }; return ( {actions || } ); }; Editor.defaultProps = { mode: 'js', readOnly: true, matchBrackets: true, indentUnit: 2, };