Skip to content

Instantly share code, notes, and snippets.

@satya164 satya164/BasicEditor.js Secret
Created Feb 16, 2018

Embed
What would you like to do?
/* @flow */
import * as React from 'react';
import { StyleSheet, css } from 'aphrodite';
import Helmet from 'react-helmet';
import debounce from 'lodash/debounce';
import { renderOnClient } from '../common/ComponentUtils';
import EditorSessionManager from '../utils/EditorSessionManager';
import withThemeName from './theming/withThemeName';
import colors from '../configs/colors';
import type { Annotation } from '../utils/convertErrorToAnnotation';
import type { TextFileEntry } from '../types';
type Props = {|
entry: TextFileEntry,
annotations: Array<Annotation>,
onLoad?: Function,
onChangeCode: Function,
theme: string,
keybindings?: string,
|};
type State = {|
height: string | number,
width: string | number,
|};
@withThemeName
class BasicEditor extends React.PureComponent<Props, State> {
state = {
height: '100%',
width: '640px',
};
componentDidMount() {
this._phantom.contentWindow.addEventListener('resize', this._handleResize);
this._handleResize();
this._restoreSession(this.props.entry);
}
componentWillUpdate(nextProps: Props) {
if (this.props.entry.item.path !== nextProps.entry.item.path) {
this._saveSession(this.props.entry);
this._restoreSession(nextProps.entry);
}
}
componentWillUnmount() {
this._phantom.contentWindow.removeEventListener('resize', this._handleResize);
this._saveSession(this.props.entry);
}
_getMode = entry => (entry.item.path.endsWith('.json') ? 'json' : 'jsx');
_saveSession = (entry: TextFileEntry) => {
EditorSessionManager.save(entry.item.path, this._editor.getSession());
};
_restoreSession = (entry: TextFileEntry) => {
const session = EditorSessionManager.create(
entry.item.path,
entry.item.content,
`ace/mode/${this._getMode(entry)}`
);
const editor = this._editor;
// Enable text wrapping
session.setUseWrapMode(true);
// Use 2 spaces for indentation
session.setOptions({
tabSize: 2,
useSoftTabs: true,
});
editor.setSession(session);
// Don't override Ctrl+L/Cmd+L
editor.commands.removeCommands(['gotoline']);
};
_editor: any;
_phantom: any;
_adjustSoftWrap = (editor: any) => {
const characterWidth = editor.renderer.characterWidth;
const contentWidth = editor.renderer.scroller.clientWidth;
const session = editor.getSession();
if (contentWidth > 0 && session.getUseWrapMode()) {
session.setWrapLimit(parseInt((contentWidth - 24) / characterWidth, 10));
}
};
_handleResize = debounce(
() => {
const size = this._phantom.getBoundingClientRect();
this.setState(
{
height: size.height,
width: size.width,
},
() => {
if (this._editor) {
this._editor.resize();
this._adjustSoftWrap(this._editor);
}
}
);
},
100,
{ leading: true, trailing: true }
);
_handleLoad = (editor: any) => {
this._editor = editor;
if (this.props.onLoad) {
this.props.onLoad(editor);
}
};
render() {
require('brace');
const AceEditor = require('react-ace').default;
require('brace/mode/jsx');
require('brace/mode/json');
require('brace/ext/language_tools');
require('brace/ext/searchbox');
require('ayu-ace/light');
require('ayu-ace/mirage');
require('brace/keybinding/vim');
const { onChangeCode, entry, annotations, theme } = this.props;
return (
<div className={css(styles.container)}>
<iframe ref={c => (this._phantom = c)} type="text/html" className={css(styles.phantom)} />
<AceEditor
enableBasicAutocompletion
enableLiveAutocompletion
focus
mode={this._getMode(entry)}
tabSize={2}
theme={theme === 'light' ? 'ayu-light' : 'ayu-mirage'}
onChange={onChangeCode}
name="code"
value={entry.item.content}
annotations={annotations}
editorProps={{ $blockScrolling: Infinity }}
showPrintMargin={false}
scrollMargin={[16, 0, 0, 0]}
style={{
width: this.state.width,
height: this.state.height,
lineHeight: 1.5,
}}
className={css(styles.editor, styles.fill)}
onLoad={this._handleLoad}
keyboardHandler={this.props.editorMode === 'normal' ? null : this.props.editorMode}
/>
<Helmet
style={[
{
cssText: `
/* Editor styles */
.ace_gutter {
border-right: 1px solid ${colors.border}; !important;
background: none !important;
color: #999 !important;
}
.ace_gutter-cell.ace_error {
background-image: url(${require('../assets/cross-red.png')}) !important;
background-size: 16px !important;
}
.ace_search {
right: 0 !important;
bottom: 0 !important;
left: auto !important;
top: auto !important;
margin: 0 1em !important;
border-radius: 5px 5px 0 0 !important;
background-color: #fff !important;
border: 1px solid ${colors.border} !important;
border-bottom: 0 !important;
padding: 1em !important;
padding-bottom: 1em !important;
max-width: 339px !important;
}
.ace_search_form {
border-color: ${colors.border} !important;
}
.ace_search_field {
height: 28px !important;
width: 212px !important;
color: inherit;
}
.ace_searchbtn {
height: 28px !important;
width: 33px !important;
}
.ace_replacebtn {
height: 28px !important;
}
.ace_searchbtn_close {
display: none !important;
}
.ace_tooltip {
background-color: #fbfbfb !important;
background-image: none !important;
border-color: lightgray !important;
border-radius: 0 !important;
}
/* Theme specific */
.ace_editor.ace_autocomplete.ace-ayu-mirage {
background-color: ${colors.ayu.mirage.background};
border-color: ${colors.ayu.mirage.border};
color: ${colors.ayu.mirage.text};
}
.ace_editor.ace_autocomplete.ace-ayu-mirage .ace_completion-highlight {
color: #FFCC66;
}
.ace_editor.ace_autocomplete.ace-ayu-mirage .ace_marker-layer .ace_active-line,
.ace_editor.ace_autocomplete.ace-ayu-mirage .ace_marker-layer .ace_line-hover {
background-color: rgba(255, 255, 255, .1);
border-color: transparent;
}
.ace_editor.ace-ayu-mirage .ace_search {
background-color: ${colors.ayu.mirage.background} !important;
border-color: ${colors.ayu.mirage.border} !important;
}
.ace_editor.ace-ayu-mirage .ace_search_form,
.ace_editor.ace-ayu-mirage .ace_replace_form {
border-color: ${colors.ayu.mirage.border} !important;
}
.ace_editor.ace-ayu-mirage .ace_search_field,
.ace_editor.ace-ayu-mirage .ace_searchbtn,
.ace_editor.ace-ayu-mirage .ace_replacebtn,
.ace_editor.ace-ayu-mirage .ace_searchbtn_close {
background-color: ${colors.background.dark} !important;
border-color: ${colors.ayu.mirage.border} !important;
color: inherit;
}
.ace_editor.ace-ayu-mirage .ace_button {
background-color: ${colors.background.dark} !important;
color: inherit;
}
.ace_editor.ace-ayu-mirage .ace_button:not(.checked) {
border-color: ${colors.ayu.mirage.border} !important;
}
.ace_editor.ace-ayu-mirage .ace_tooltip {
background-color: ${colors.ayu.mirage.background} !important;
border-color: ${colors.ayu.mirage.border} !important;
color: ${colors.ayu.mirage.text};
}
`,
},
]}
/>
</div>
);
}
}
export default renderOnClient(BasicEditor);
const styles = StyleSheet.create({
container: {
flex: 1,
display: 'flex',
position: 'relative',
overflow: 'hidden',
},
fill: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
},
resizable: {
opacity: 0,
},
editor: {
backgroundColor: 'transparent',
fontFamily: [
'Fira Code',
'Fira Mono',
'Monaco',
'Menlo',
'Ubuntu Mono',
'Consolas',
'source-code-pro',
'monospace',
],
},
phantom: {
display: 'block',
position: 'absolute',
left: 0,
top: 0,
height: '100%',
width: '100%',
pointerEvents: 'none',
opacity: 0,
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.