LOADING...

Preview

Pen ID
Unlock Campus Themeforest adv

 

Code

COMMENTS

Riccardo
Riccardo on MARCH 7, 2016
"Draft.js is a framework for building rich text editors in React, powered by an immutable model and abstracting over cross-browser differences."

Draft.js home page.
Riccardo
Riccardo on MARCH 7, 2016
This demo demonstrate a basic implementation of Draft.js
It's a powerfoul React framework. You can try styling your comment with the pleasure of see the effects live instead of the guard characters of markdown.


Watch the official presentation at the React.js Conf 2016. WATCH!!
Riccardo
Riccardo on MARCH 7, 2016
Try actions like keyboard shortcuts for inline styling. Also try tagging someone! Maybe me @rkpasia :)

Have fun.
Be cool.

LEAVE A COMMENT

CSS
body {
  background-color: #191919;
  font-family: "Lato";
}

.comments-section {
  margin: 0 15px;
  position: absolute;
  left: 50%;
  -webkit-transform: translate(-50%, 0);
          transform: translate(-50%, 0);
  top: 5%;
  width: 600px;
  margin-bottom: 10%;
}
.comments-section h4 {
  margin: 0;
  margin-top: 40px;
  margin-bottom: 10px;
  font-weight: bold;
  font-size: 1.2rem;
  color: white;
  border-bottom: 1px solid #666;
  padding-bottom: 5px;
}
.comments-section .comments {
  color: white;
}
.comments-section .comments h4 {
  border: 0;
}
.comments-section .comment {
  background: #28282B;
  padding: 20px;
  font-size: 15px;
  margin-bottom: 20px;
}
.comments-section .comment blockquote {
  color: #eee;
  padding: 1em;
  border-left: 2px solid #76daff;
  background: rgba(0, 0, 0, 0.05);
}
.comments-section .comment code {
  font-family: Menlo, Monaco, monospace;
  background: rgba(0, 0, 0, 0.2);
  padding: 2px 5px;
  margin: 0 2px;
  border-radius: 2px;
}
.comments-section .comment .box {
  background: #1d1f20;
  padding: 20px;
}
.comments-section .comment .box pre {
  overflow: auto;
  margin: 0;
}
.comments-section .comment .box pre code {
  background: transparent;
}
.comments-section .comment .box + .box {
  padding-top: 0px;
}
.comments-section .comment a {
  color: #76daff;
  text-decoration: none;
}
.comments-section .comment .comment-user {
  border-bottom: 1px solid #555;
  padding: 10px 45px 20px;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
}
.comments-section .comment .comment-user .avatar img {
  width: 35px;
  height: 35px;
}
.comments-section .comment .comment-user .username {
  color: #76daff;
}
.comments-section .comment .comment-user .user-details {
  color: #666;
  margin-left: 10px;
}
.comments-section .comment .comment-user .user-details span:last-child {
  color: #999;
  font-size: 80%;
}
.comments-section .comment .comment-text {
  padding: 10px 45px 20px;
}

/* EDITOR STYLE */
.CodepenCommentEditor-root {
  background: transparent;
  font-family: "Lato", serif;
  font-size: 14px;
}

.CodepenCommentEditor-editor {
  background: #fff;
  border: 3px solid #ccc;
  cursor: text;
  font-size: 13px;
  margin-top: 10px;
  font-family: "Lato";
  -webkit-transition: all 0.2s ease-in;
  transition: all 0.2s ease-in;
}

.CodepenCommentEditor-focus {
  border-color: #555;
}

.CodepenCommentEditor-editor .public-DraftEditorPlaceholder-root,
.CodepenCommentEditor-editor .public-DraftEditor-content {
  padding-left: 5px;
  padding-top: 5px;
}

.CodepenCommentEditor-editor .public-DraftEditor-content {
  min-height: 100px;
}

.CodepenCommentEditor-hidePlaceholder .public-DraftEditorPlaceholder-root {
  display: none;
}

.CodepenCommentEditor-editor .CodepenCommentEditor-blockquote {
  border-left: 2px solid #76daff;
  background-color: rgba(0, 0, 0, 0.05);
  color: #666;
  font-style: italic;
  margin: 16px 0;
  margin-right: 5px;
  padding: 10px 20px;
}

.CodepenCommentEditor-editor .public-DraftStyleDefault-pre {
  margin-right: 5px;
  background-color: rgba(0, 0, 0, 0.05);
  font-family: 'Inconsolata', 'Menlo', 'Consolas', monospace;
  font-size: 16px;
  padding: 20px;
}

.CodepenCommentEditor-controls {
  font-family: "Lato", sans-serif;
  font-size: 12px;
  margin-bottom: 2px;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}

.CodepenCommentEditor-styleButton {
  display: inline-block;
  color: #fff;
  cursor: pointer;
  margin-right: 16px;
  padding: 2px 7px;
  border: 1px solid transparent;
  margin: 0 5px 0 0;
  border-radius: 3px;
  background: #343436;
}

.CodepenCommentEditor-submitButton {
  color: white;
  cursor: pointer;
  float: left;
  margin-top: 5px;
  padding: 10px 16px;
  background: none;
  border: 3px solid #ccc;
  border-radius: 3px;
}
.CodepenCommentEditor-submitButton:hover {
  background: white;
  border-color: white;
  color: black;
}

.CodepenCommentEditor-activeButton {
  background: #4d4d50;
  -webkit-transform: translateY(1px);
          transform: translateY(1px);
}
JS
// IMPORT DRAFT COMPONENTS
const {Editor, EditorState, RichUtils, CompositeDecorator} = Draft;

////////////////////////////
// TAG HANDLING eg. @rkpasia

const TAG_REGEX = /\@[\w]+/g;
function tagHandle(contentBlock, callback) {
  findWithRegex(TAG_REGEX, contentBlock, callback);
}

function findWithRegex(regex, contentBlock, callback) {
  const text = contentBlock.getText();
  let matchArr, start;
  while ((matchArr = regex.exec(text)) !== null) {
    start = matchArr.index;
    callback(start, start + matchArr[0].length);
  }
}

const styles = {
  tag: {
    color: 'rgba(98, 177, 254, 1.0)',
    direction: 'ltr',
    unicodeBidi: 'bidi-override',
  }
}

const Tag = (props) => {
  return {props.children};
}

// END TAG HANDLING
///////////////////

///////////////////
// EDITOR COMPONENT

class CodepenCommentEditor extends React.Component {
  
  constructor(props) {
    super(props);
    
    // Defining decorator
    const compositeDecorator = new CompositeDecorator([
      {
        strategy: tagHandle,
        component: Tag
      }
    ]);
    
    // Connect the decorator to the obj entity
    this.state = {editorState: EditorState.createEmpty(compositeDecorator)};

    this.focus = () => this.refs.editor.focus();
    this.onChange = (editorState) => this.setState({editorState});

    this.handleKeyCommand = (command) => this._handleKeyCommand(command);
    this.toggleBlockType = (type) => this._toggleBlockType(type);
    this.toggleInlineStyle = (style) => this._toggleInlineStyle(style);
  }

  _handleKeyCommand(command) {
    const {editorState} = this.state;
    const newState = RichUtils.handleKeyCommand(editorState, command);
    if (newState) {
      this.onChange(newState);
      return true;
    }
    return false;
  }

  _toggleBlockType(blockType) {
    this.onChange(
      RichUtils.toggleBlockType(
        this.state.editorState,
        blockType
      )
    );
  }

  _toggleInlineStyle(inlineStyle) {
    this.onChange(
      RichUtils.toggleInlineStyle(
        this.state.editorState,
        inlineStyle
      )
    );
  }

  render() {
    const {editorState} = this.state;
    let className = 'CodepenCommentEditor-editor';
    var contentState = editorState.getCurrentContent();
    if (!contentState.hasText()) {
      if (contentState.getBlockMap().first().getType() !== 'unstyled') {
        className += ' CodepenCommentEditor-hidePlaceholder';
      }
    }
    
    var selectionState = editorState.getSelection();
    
    if(selectionState.getHasFocus()){
      className += ' CodepenCommentEditor-focus';
    }

    return (
      
); } } // Styles for blocks const styleMap = { CODE: { display: 'inline-block', backgroundColor: 'rgba(0, 0, 0, 0.05)', fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace', fontSize: 16, padding: 2, marginTop: 3 }, LINK: { color: '#76daff' } }; function getBlockStyle(block) { switch (block.getType()) { case 'blockquote': return 'CodepenCommentEditor-blockquote'; default: return null; } } //////////////////// // BUTTONS COMPONENT class StyleButton extends React.Component { constructor() { super(); this.onToggle = (e) => { e.preventDefault(); this.props.onToggle(this.props.style); }; } render() { let className = 'CodepenCommentEditor-styleButton'; if (this.props.active) { className += ' CodepenCommentEditor-activeButton'; } return ( {this.props.label} ); } } ////////////////////////// // SUBMIT BUTTON COMPONENT class SubmitButton extends React.Component { constructor(props) { super(props); this.onToggle = (e) => { var markup = { 'BOLD': ['', ''], 'ITALIC': ['', ''], 'LINK': ['',''], 'CODE': ['',''] }; e.preventDefault(); var editorState = this.props.editorState; console.log(Draft.convertToRaw(editorState.getCurrentContent())); console.log(buildMarkup(Draft.convertToRaw(editorState.getCurrentContent()), markup)); var markuppedBlocks = buildMarkup(Draft.convertToRaw(editorState.getCurrentContent()), markup); var commentContent = (blocks) => { let commentText = ""; blocks.forEach((block, index, arr) => { if(block.blockType == "unstyled") commentText += "

" + block.styledMarkup + "

"; if(block.blockType == "blockquote") commentText += "
" + block.styledMarkup + "
"; if(block.blockType == "code-block") commentText += "
" + block.styledMarkup + "
"; }); return commentText; } let comment = commentContent(markuppedBlocks); $('#comments-container').append(`
Riccardo
Riccardo on MARCH 7, 2016
${comment}
`); } } render(){ let className = 'CodepenCommentEditor-submitButton'; return ( Submit ); } } ////////////// // BLOCK TYPES const BLOCK_TYPES = [ {label: 'Quote', style: 'blockquote'}, {label: 'Block Code', style: 'code-block'}, ]; const BlockStyleControls = (props) => { const {editorState} = props; const selection = editorState.getSelection(); const blockType = editorState .getCurrentContent() .getBlockForKey(selection.getStartKey()) .getType(); return ( {BLOCK_TYPES.map((type) => )} ); }; //////////////// // INLINE_STYLES var INLINE_STYLES = [ {label: 'Bold', style: 'BOLD'}, {label: 'Italic', style: 'ITALIC'}, {label: 'Link', style: 'LINK'}, {label: 'Inline Code', style: 'CODE'}, ]; const InlineStyleControls = (props) => { var currentStyle = props.editorState.getCurrentInlineStyle(); return ( {INLINE_STYLES.map(type => )} ); }; ReactDOM.render( , document.getElementById('comment-form') ); /////////////// // DEPENDENCIES // values in haystack must be unique function containsSome(haystack, needles) { return haystack.length > _.difference(haystack, needles).length; } function relevantStyles(offset, styleRanges) { var styles = _.filter(styleRanges, function(range) { return (offset >= range.offset && offset < (range.offset + range.length)); }); return styles.map(function (style) {return style.style}); } function buildMarkup(rawDraftContentState, markup) { var blocks = rawDraftContentState.blocks; return blocks.map(function convertBlock(block) { var outputText = []; var styleStack = []; var text = block.text; var ranges = block.inlineStyleRanges; var type = block.type; // loop over every char in this block's text for (var i = 0; i < text.length; i++) { // figure out what styles this char and the next char need // (regardless of whether there *is* a next char or not) var characterStyles = relevantStyles(i, ranges); var nextCharacterStyles = relevantStyles(i + 1, ranges); // calculate styles to add and remove var stylesToAdd = _.difference(characterStyles, styleStack); var stylesToRemove = _.difference(characterStyles, nextCharacterStyles); // add styles we will need for this char stylesToAdd.forEach(function(style) { styleStack.push(style); outputText.push(markup[style][0]); }); outputText.push(text.substr(i, 1)); // remove styles we won't need anymore while (containsSome(styleStack, stylesToRemove)) { var toRemove = styleStack.pop(); outputText.push(markup[toRemove][1]); } } return { blockType: type, styledMarkup: outputText.join('') } }); }
Host Instantly Drag and Drop Website Builder

 

Description

This pen shows an implementation of Draft.js framework built by facebook.
Term
Mon, 11/27/2017 - 21:39

Related Codes

Pen ID
Pen ID
Pen ID