import React from 'react' import dynamic from 'next/dynamic' import * as hljs from 'highlight.js' import debounce from 'lodash.debounce' import ms from 'ms' import { Controlled as CodeMirror } from 'react-codemirror2' import SpinnerWrapper from './SpinnerWrapper' import WindowControls from './WindowControls' import { COLORS, LANGUAGE_MODE_HASH, LANGUAGE_NAME_HASH, LANGUAGE_MIME_HASH, DEFAULT_SETTINGS, THEMES_HASH } from '../lib/constants' const Watermark = dynamic(() => import('./svg/Watermark'), { loading: () => null }) function searchLanguage(l) { const config = LANGUAGE_NAME_HASH[l] || LANGUAGE_MODE_HASH[l] || LANGUAGE_MIME_HASH[l] if (config) { return config.mime || config.mode } } class Carbon extends React.PureComponent { static defaultProps = { onChange: () => {} } componentDidUpdate(prevProps) { // TODO keep opacities in state if ( prevProps.config.theme != this.props.config.theme || prevProps.config.language != this.props.config.language ) { this.prevLine = null } } handleLanguageChange = debounce( (newCode, language) => { if (language === 'auto') { // try to set the language const detectedLanguage = hljs.highlightAuto(newCode).language const languageMode = searchLanguage(detectedLanguage) if (languageMode) { return languageMode } } const languageMode = searchLanguage(language) if (languageMode) { return languageMode } return language }, ms('300ms'), { leading: true, trailing: true } ) onBeforeChange = (editor, meta, code) => { if (!this.props.readOnly) { this.props.onChange(code) } } prevLine = null onGutterClick = (editor, lineNumber, gutter, e) => { editor.display.view.forEach((line, i, arr) => { if (i != lineNumber) { if (this.prevLine == null) { line.text.style.opacity = 0.5 line.gutter.style.opacity = 0.5 } } else { if (e.shiftKey && this.prevLine != null) { for ( let index = Math.min(this.prevLine, i); index < Math.max(this.prevLine, i) + 1; index++ ) { arr[index].text.style.opacity = arr[this.prevLine].text.style.opacity arr[index].gutter.style.opacity = arr[this.prevLine].gutter.style.opacity } } else { line.text.style.opacity = line.text.style.opacity == 1 ? 0.5 : 1 line.gutter.style.opacity = line.gutter.style.opacity == 1 ? 0.5 : 1 } } }) this.prevLine = lineNumber } render() { const config = { ...DEFAULT_SETTINGS, ...this.props.config } const languageMode = this.handleLanguageChange( this.props.children, config.language && config.language.toLowerCase() ) const options = { lineNumbers: config.lineNumbers, mode: languageMode || 'plaintext', theme: config.theme, scrollBarStyle: null, viewportMargin: Infinity, lineWrapping: true, extraKeys: { 'Shift-Tab': 'indentLess' }, readOnly: this.props.readOnly ? 'nocursor' : false, // needs to be able to refresh every 16ms to hit 60 frames / second pollInterval: 16 } const backgroundImage = (this.props.config.backgroundImage && this.props.config.backgroundImageSelection) || this.props.config.backgroundImage const themeConfig = this.props.theme || THEMES_HASH[config.theme] const light = themeConfig && themeConfig.light const content = (