Content editable with instant replace

Replaces "1" with bold text

by Arthur Lutkevichus

HTML

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/[email protected]/lodash.js"></script>
<script src="http://www.jimsproch.com/react/future/react-dom-server.js"></script>
<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

CSS

#container div {
  width: 300px;
  height: 20px;
  border: 1px solid black;
}

Babel + JSX

class Hello extends React.Component{
   constructor(props){
     super(props);
     this.state = {
        scriptString: ''
     };
     
     this.onChange = this.onChange.bind(this);
        this.saveCaretPosition = this.saveCaretPosition.bind(this);
   }

    saveCaretPosition(context) {
        const selection = window.getSelection();
        if (!selection.anchorNode) {
            return {
                pos: 0,
                restore: () => {}
            };
        }
        const range = selection.getRangeAt(0);
        range.setStart(context, 0);
        let len = range.toString().length;

        return {
            pos: len,
            restore: forcePosition => {
                let lastNode = null;

                const treeWalker = document.createTreeWalker(context, NodeFilter.SHOW_TEXT, elem => {
                    if (len > elem.textContent.length) {
                        len -= elem.textContent.length;
                        lastNode = elem;
                        return NodeFilter.FILTER_REJECT
                    }
                    return NodeFilter.FILTER_ACCEPT;
                });
                const c = treeWalker.nextNode();
                const pos = {
                    node: c ? c : context,
                    position: c ? (_.isUndefined(forcePosition) ? len : Math.max(forcePosition, 0)) : 0
                };

                selection.removeAllRanges();
                const range = new Range();
                range.setStart(pos.node, pos.position);
                selection.addRange(range);
            }
        }
    }
   
   onChange(event) { 
        const caret = this.saveCaretPosition(event.target);   
        console.log(event.target.innerHTML)
     const value = ReactDOMServer.renderToString(event.target.innerHTML).replace(/<[^>]*>/g, "").replace(/1/g, <b>1</b>);
//const value = <b onClick={()=> console.log("click")}>1</b>;
        console.log(value)
    this.setState({
    value
    }, () => {
    ...