As others have stated, the short answer is to use document.execCommand to preserve the browser's undo/redo. If you need to un-doably edit the text programmatically in any way (like to support multi-line tab indents or other shortcuts that manipulate the text), you should use document.execCommand('insertHTML') or 'insertText' when you set the new text state. insertText will create new div children as you edit, which may be troublesome, while 'insertHTML' will not (but 'insertHTML' has some IE support issues you may have to address, well-detailed elsewhere).
This part threw me for a huge loop and is why I'm writing a new answer, because I didn't find it mentioned anywhere:
You may also need to catch the paste event and turn it into an execCommand('insertHTML'), or else any programmatic selection changes you might do after that paste (like resetting the cursor, etc) run the risk of throwing you an error saying the node isn't long enough to make your new selection, though it visibly is. The DOM somehow doesn't recognize the new length of yourDiv.firstNode after you paste, but it will update it after you use execCommand('insertHTML'). There may be other solutions to that, but this was an easy one:
$("#myDiv").on( 'paste', function(e) {
e.preventDefault();
var text = e.originalEvent.clipboardData.getData("text/plain");
document.execCommand("insertHTML", false, text);
});