航海99 TIL[11/1]


11月から始まりました.そして、私が参加している実戦種目の2週目も始まりました.最初は6週間の時間が少し遠いと思っていましたが、すべてが過ぎ去ったので、今週も慣れたように再開しました.今日は、プロジェクトのWebサイトで使用されているテキストエディタライブラリを検索し、いくつかのライブラリをテストする時間があります.
Top 5 Rich Text Editors for React in 2021
https://blog.bitsrc.io/top-5-rich-text-editors-for-react-in-2021-628fecf0f7e0
Draft.jsテキストエディタライブラリのテスト
▶ Draft.jsはフェイスブックで公開されており、reactでテキストエディタを作成できるツールです.「WYSIWYG(What you see is you get)」と書いたときに見たのは結果と同じユーザーインタフェース
▶ import
  • draft-jsを追加する理由は、DOMに対応するテキストを追加する必要があるためです.
  • import { Editor } from "react-draft-wysiwyg";
    import { EditorState, convertToRaw } from "draft-js";
    ▶国家宣言
  • テキストを含む状態の初期値は、EditorStateです.可変オブジェクトとして表示するにはcreateEmpty()を使用します.
  • →RichTextEditorコード(JS)
    import React from "react";
    import { Editor, EditorState, getDefaultKeyBinding, RichUtils} from "draft-js";
    import './RichText.css';
    import '../../node_modules/draft-js/dist/Draft.css';
    ​
    ​
    class RichTextEditor extends React.Component {
        constructor(props) {
          super(props);
          this.state = {editorState: EditorState.createEmpty()};
    ​
          this.focus = () => this.refs.editor.focus();
          this.onChange = (editorState) => this.setState({editorState});
    ​
          this.handleKeyCommand = this._handleKeyCommand.bind(this);
          this.mapKeyToEditorCommand = this._mapKeyToEditorCommand.bind(this);
          this.toggleBlockType = this._toggleBlockType.bind(this);
          this.toggleInlineStyle = this._toggleInlineStyle.bind(this);
        }
    ​
        _handleKeyCommand(command, editorState) {
          const newState = RichUtils.handleKeyCommand(editorState, command);
          if (newState) {
            this.onChange(newState);
            return true;
          }
          return false;
        }
    ​
        _mapKeyToEditorCommand(e) {
          if (e.keyCode === 9 /* TAB */) {
            const newEditorState = RichUtils.onTab(
              e,
              this.state.editorState,
              4, /* maxDepth */
            );
            if (newEditorState !== this.state.editorState) {
              this.onChange(newEditorState);
            }
            return;
          }
          return getDefaultKeyBinding(e);
        }
    ​
        _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;
    ​
          // If the user changes block type before entering any text, we can
          // either style the placeholder or hide it. Let's just hide it now.
          let className = 'RichEditor-editor';
          var contentState = editorState.getCurrentContent();
          if (!contentState.hasText()) {
            if (contentState.getBlockMap().first().getType() !== 'unstyled') {
              className += ' RichEditor-hidePlaceholder';
            }
          }
    ​
          return (
            <div className="RichEditor-root">
              <BlockStyleControls
                editorState={editorState}
                onToggle={this.toggleBlockType}
              />
              <InlineStyleControls
                editorState={editorState}
                onToggle={this.toggleInlineStyle}
              />
              <div className={className} onClick={this.focus}>
                <Editor
                  blockStyleFn={getBlockStyle}
                  customStyleMap={styleMap}
                  editorState={editorState}
                  handleKeyCommand={this.handleKeyCommand}
                  keyBindingFn={this.mapKeyToEditorCommand}
                  onChange={this.onChange}
                  placeholder="Tell a story..."
                  ref="editor"
                  spellCheck={true}
                />
              </div>
            </div>
          );
        }
      }
    ​
      // Custom overrides for "code" style.
      const styleMap = {
        CODE: {
          backgroundColor: 'rgba(0, 0, 0, 0.05)',
          fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
          fontSize: 16,
          padding: 2,
        },
      };
    ​
      function getBlockStyle(block) {
        switch (block.getType()) {
          case 'blockquote': return 'RichEditor-blockquote';
          default: return null;
        }
      }
    ​
      class StyleButton extends React.Component {
        constructor() {
          super();
          this.onToggle = (e) => {
            e.preventDefault();
            this.props.onToggle(this.props.style);
          };
        }
    ​
        render() {
          let className = 'RichEditor-styleButton';
          if (this.props.active) {
            className += ' RichEditor-activeButton';
          }
    ​
          return (
            <span className={className} onMouseDown={this.onToggle}>
              {this.props.label}
            </span>
          );
        }
      }
    ​
      const BLOCK_TYPES = [
        {label: 'H1', style: 'header-one'},
        {label: 'H2', style: 'header-two'},
        {label: 'H3', style: 'header-three'},
        {label: 'H4', style: 'header-four'},
        {label: 'H5', style: 'header-five'},
        {label: 'H6', style: 'header-six'},
        {label: 'Blockquote', style: 'blockquote'},
        {label: 'UL', style: 'unordered-list-item'},
        {label: 'OL', style: 'ordered-list-item'},
        {label: 'Code Block', style: 'code-block'},
      ];
    ​
      const BlockStyleControls = (props) => {
        const {editorState} = props;
        const selection = editorState.getSelection();
        const blockType = editorState
          .getCurrentContent()
          .getBlockForKey(selection.getStartKey())
          .getType();
    ​
        return (
          <div className="RichEditor-controls">
            {BLOCK_TYPES.map((type) =>
              <StyleButton
                key={type.label}
                active={type.style === blockType}
                label={type.label}
                onToggle={props.onToggle}
                style={type.style}
              />
            )}
          </div>
        );
      };
    ​
      var INLINE_STYLES = [
        {label: 'Bold', style: 'BOLD'},
        {label: 'Italic', style: 'ITALIC'},
        {label: 'Underline', style: 'UNDERLINE'},
        {label: 'Monospace', style: 'CODE'},
      ];
    ​
      const InlineStyleControls = (props) => {
        const currentStyle = props.editorState.getCurrentInlineStyle();
        
        return (
          <div className="RichEditor-controls">
            {INLINE_STYLES.map((type) =>
              <StyleButton
                key={type.label}
                active={currentStyle.has(type.style)}
                label={type.label}
                onToggle={props.onToggle}
                style={type.style}
              />
            )}
          </div>
        );
      };
    ​
      export default RichTextEditor;
    →RichTextEditorコード(CSS)
    /**
     * Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
     *
     * This file provided by Facebook is for non-commercial testing and evaluation
     * purposes only. Facebook reserves all rights not expressly granted.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     */
     .RichEditor-root {
        background: #fff;
        border: 1px solid #ddd;
        font-family: 'Georgia', serif;
        font-size: 14px;
        padding: 15px;
      }
      
      .RichEditor-editor {
        border-top: 1px solid #ddd;
        cursor: text;
        font-size: 16px;
        margin-top: 10px;
      }
      
      .RichEditor-editor .public-DraftEditorPlaceholder-root,
      .RichEditor-editor .public-DraftEditor-content {
        margin: 0 -15px -15px;
        padding: 15px;
      }
      
      .RichEditor-editor .public-DraftEditor-content {
        min-height: 100px;
      }
      
      
      .RichEditor-hidePlaceholder .public-DraftEditorPlaceholder-root {
        display: none;
      }
      
      .RichEditor-editor .RichEditor-blockquote {
        border-left: 5px solid #eee;
        color: #666;
        font-family: 'Hoefler Text', 'Georgia', serif;
        font-style: italic;
        margin: 16px 0;
        padding: 10px 20px;
      }
      
      .RichEditor-editor .public-DraftStyleDefault-pre {
        background-color: rgba(0, 0, 0, 0.05);
        font-family: 'Inconsolata', 'Menlo', 'Consolas', monospace;
        font-size: 16px;
        padding: 20px;
      }
      
      .RichEditor-controls {
        font-family: 'Helvetica', sans-serif;
        font-size: 14px;
        margin-bottom: 5px;
        user-select: none;
      }
      
      .RichEditor-styleButton {
        color: #999;
        cursor: pointer;
        margin-right: 16px;
        padding: 2px 0;
        display: inline-block;
      }
      
      .RichEditor-activeButton {
        color: #5890ff;
      }
    ▶テスト画面のスクリーンショット