Ivan - Create Ticket Form - Create Basic TextEditor component using draft.js [skip ci]

This commit is contained in:
ivan 2016-08-17 22:29:47 -03:00
parent 8b6266c6c8
commit 95290e97f7
10 changed files with 305 additions and 5 deletions

View File

@ -55,6 +55,7 @@
"dependencies": {
"app-module-path": "^1.0.3",
"classnames": "^2.1.3",
"draft-js": "^0.8.1",
"jquery": "^2.1.4",
"keycode": "^2.1.4",
"localStorage": "^1.0.3",

View File

@ -0,0 +1,33 @@
import React from 'react';
import ReCAPTCHA from 'react-google-recaptcha';
import i18n from 'lib-app/i18n';
import API from 'lib-app/api-call';
import SubmitButton from 'core-components/submit-button';
import Message from 'core-components/message';
import Form from 'core-components/form';
import Input from 'core-components/input';
import TextEditor from 'core-components/text-editor';
import DropDown from 'core-components/drop-down';
import Widget from 'core-components/widget';
class CreateTicketForm extends React.Component {
render() {
return (
<div>
<Form>
<DropDown items={[
{content: 'Department1'},
{content: 'Department2'},
{content: 'Department3'}
]} />
<Input label="Title" name="title" required />
<TextEditor label="Content" name="content" required />
</Form>
</div>
);
}
}
export default CreateTicketForm;

View File

@ -1,11 +1,13 @@
import React from 'react';
import CreateTicketForm from 'app/main/dashboard/dashboard-create-ticket/create-ticket-form';
class DashboardCreateTicketPage extends React.Component {
render() {
return (
<div>
DASHBOARD CREATE TICKET
<CreateTicketForm />
</div>
);
}

View File

@ -9,7 +9,7 @@ class MainLayout extends React.Component {
return (
<div className="main-layout">
<MainHeader />
<div className="main-layout--content">
<div className="main-layout--content row">
{this.props.children}
</div>
<MainFooter />

View File

@ -6,6 +6,9 @@ import classNames from 'classnames';
// CORE LIBS
import callback from 'lib-core/callback';
// CORE COMPONENTS
import Icon from 'core-components/icon';
class Button extends React.Component {
static contextTypes = {
@ -16,6 +19,7 @@ class Button extends React.Component {
children: React.PropTypes.node,
type: React.PropTypes.oneOf([
'primary',
'primary-icon',
'clean',
'link'
]),
@ -23,7 +27,8 @@ class Button extends React.Component {
to: React.PropTypes. string.isRequired,
params: React.PropTypes.object,
query: React.PropTypes.query
})
}),
iconName: React.PropTypes.string
};
static defaultProps = {
@ -33,7 +38,7 @@ class Button extends React.Component {
render() {
return (
<button {...this.getProps()}>
{this.props.children}
{(this.props.iconName) ? <Icon size="sm" name={this.props.iconName}/> : this.props.children}
</button>
);
}

View File

@ -2,7 +2,8 @@
.button {
&-primary {
&-primary,
&-primary-icon {
background-color: $primary-red;
border: solid transparent;
border-radius: 4px;
@ -12,6 +13,11 @@
width: 239px;
}
&-primary-icon {
width: initial;
height: initial;
}
&-clean {
background: none;
border: none;

View File

@ -0,0 +1,84 @@
import React from 'react';
import classNames from 'classnames';
import _ from 'lodash';
import TextEditor from 'core-components/text-editor';
class TextArea extends React.Component {
static contextTypes = {
loading: React.PropTypes.bool
};
static propTypes = {
value: React.PropTypes.string,
validation: React.PropTypes.string,
onChange: React.PropTypes.func,
required: React.PropTypes.bool,
error: React.PropTypes.string
};
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty()
};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
return (
<label className={this.getClass()}>
<span className="text-area__label">{this.props.label}</span>
<TextEditor />
{this.renderError()}
</label>
);
}
renderError() {
let error = null;
if (this.props.error){
error = <span className="text-area__error"> {this.props.error} </span>;
}
return error;
}
/*getEditorProps() {
let props = _.clone(this.props);
props['aria-required'] = this.props.required;
props.className = 'text-area__input';
props.ref = 'nativeTextArea';
props.disabled = this.context.loading;
delete props.required;
delete props.validation;
delete props.error;
delete props.password;
return props;
}*/
getClass() {
let classes = {
'text-area': true,
'text-area_with-error': (this.props.error),
[this.props.className]: (this.props.className)
};
return classNames(classes);
}
focus() {
if (this.refs.nativeTextArea) {
this.refs.nativeTextArea.focus();
}
}
}
export default TextArea;

View File

@ -0,0 +1,42 @@
@import "../scss/vars";
.text-area {
display: block;
&__editor {
border: 1px solid $grey;
border-radius: 3px;
padding: 8px;
width: 100%;
&:hover {
border-color: $medium-grey;
}
&:focus {
outline: none;
border-color: $primary-blue;
}
}
&__label {
color: $primary-black;
font-size: 15px;
display: block;
padding: 3px 0;
text-align: left;
}
&_with-error {
.text-area__error {
color: $primary-red;
font-size: $font-size--sm;
display: block;
position: absolute;
}
.text-area__text {
border: 1px solid $primary-red;
}
}
}

View File

@ -0,0 +1,94 @@
import React from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
import _ from 'lodash';
import {Editor, EditorState, RichUtils} from 'draft-js';
import Button from 'core-components/button';
class TextEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
focused: false
};
}
render() {
return (
<div className={this.getClass()}>
{this.renderEditOptions()}
<div className="text-editor__editor" onClick={this.focus.bind(this)}>
<Editor {...this.getEditorProps()} />
</div>
</div>
);
}
renderEditOptions() {
const onBoldClick = (event) => {
event.preventDefault();
this.onEditorChange(RichUtils.toggleInlineStyle(this.state.editorState, 'BOLD'));
};
const onItalicsClick = (event) => {
event.preventDefault();
this.onEditorChange(RichUtils.toggleInlineStyle(this.state.editorState, 'ITALICS'));
};
const onUnderlineClick = (event) => {
event.preventDefault();
this.onEditorChange(RichUtils.toggleInlineStyle(this.state.editorState, 'UNDERLINE'));
};
return (
<div className="text-editor__options">
<Button type="primary-icon" iconName="bold" onClick={onBoldClick.bind(this)} onMouseDown={(e) => {e.preventDefault()}} />
<Button type="primary-icon" iconName="italic" onClick={onItalicsClick.bind(this)} onMouseDown={(e) => {e.preventDefault()}} />
<Button type="primary-icon" iconName="underline" onClick={onUnderlineClick.bind(this)} onMouseDown={(e) => {e.preventDefault()}} />
</div>
)
}
getClass() {
let classes = {
'text-editor': true,
'text-editor_focused': (this.state.focused),
[this.props.className]: (this.props.className)
};
return classNames(classes);
}
getEditorProps() {
return {
editorState: this.state.editorState,
ref: 'editor',
onChange: this.onEditorChange.bind(this),
onFocus: this.onEditorFocus.bind(this),
onBlur: this.onBlur.bind(this)
};
}
onEditorChange(editorState) {
this.setState({editorState});
}
onEditorFocus() {
this.setState({focused: true});
}
onBlur() {
this.setState({focused: false});
}
focus() {
if (this.refs.editor) {
this.refs.editor.focus();
}
}
}
export default TextEditor;

View File

@ -0,0 +1,33 @@
@import "../scss/vars";
.text-editor {
&__editor {
border: 1px solid $grey;
border-radius: 3px;
padding: 8px;
width: 100%;
height: 200px;
text-align: left;
overflow: auto;
&:hover {
border-color: $medium-grey;
}
}
&__options {
text-align: left;
margin-bottom: 5px;
.button {
margin-right: 3px;
}
}
&_focused {
.text-editor__editor {
border-color: $primary-blue;
}
}
}