highlightRangePart = (container, startOffset, endOffset, classNames) => {
  let spanHighlight;
  const text = container.textContent;
  const parent = container.parentNode;

  /**
   * In case we're inside another region, move the selection outside
   * to maintain proper nesting of highlight nodes
   */
  if (
    startOffset === 0 &&
    container.length === endOffset &&
    parent.classList.contains(classNames[0]) &&
    parent.innerText === text
  ) {
    const placeholder = container.ownerDocument.createElement("span");
    const parentNode = parent.parentNode;

    parentNode.replaceChild(placeholder, parent);
    spanHighlight = wrapWithSpan(parent, classNames);
    parentNode.replaceChild(spanHighlight, placeholder);
  } else {
    // Extract text content that matches offsets
    const content = text.substring(startOffset, endOffset);
    // Create text node that will be highlighted
    const highlitedNode = container.ownerDocument.createTextNode(content);

    // Split the container in three parts
    const noseNode = container.cloneNode();
    const tailNode = container.cloneNode();

    // Add all the text BEFORE selection
    noseNode.textContent = text.substring(0, startOffset);
    tailNode.textContent = text.substring(endOffset, text.length);

    // To avoid weird dom mutation we assemble replacement
    // beforehands, it allows to replace original node
    // directly without extra work
    const textFragment = container.ownerDocument.createDocumentFragment();

    spanHighlight = wrapWithSpan(highlitedNode, classNames);

    if (noseNode.length) textFragment.appendChild(noseNode);
    textFragment.appendChild(spanHighlight);
    if (tailNode.length) textFragment.appendChild(tailNode);

    // At this point we have three nodes in the tree
    // one of them is our selected range
    parent.replaceChild(textFragment, container);
  }

  return spanHighlight;
}
Takes original range and splits it into multiple text
nodes highlighting a part of the text, then replaces
original text node with highlighted one
@param {Node} container
@param {number} startOffset
@param {number} endOffset
@param {object} cssStyles
@param {string[]} classNames