Conversation
0af6f58 to
f853061
Compare
701962c to
38693c4
Compare
|
I've been trying to fix this Android web issue (you can see some of my takeaways in the comments). It led me to if (!rootSpan || rootSpan.innerHTML !== dom.innerHTML) {
targetElement.innerHTML = '';
targetElement.innerText = '';
target.appendChild(dom);
if (BrowserUtils.isChromium) {
moveCursor(isFocused, alwaysMoveCursorToTheEnd, cursorPosition, target);
}
}I also contacted @BartoszGrajdek (shout out to him) to discuss it and he suggested to give this PR a try, as it refactors the web implementation. Here is what I discovered on both web and Android web: (I had to remove Case 1 - const [value, setValue] = React.useState(TEST_CONST.EXAMPLE_CONTENT);
+ const [value, setValue] = React.useState();Voice recognition works, markdown doesn't work Case 2 - const [value, setValue] = React.useState(TEST_CONST.EXAMPLE_CONTENT);
+ const [value, setValue] = React.useState('');Voice recognition doesn't work, markdown works To test the voice recognition, I started from an empty input and dictated a sentence, to test markdown I simply typed * bold * or something similar. |
17fd595 to
a1bf047
Compare
b5e9b86 to
4e895e9
Compare
| let shouldAddNewline = false; | ||
| const lastNode = target.childNodes[target.childNodes.length - 1]; | ||
| // Remove the last <br> element if it's the last child of the target element. Fixes the issue with adding extra newline when pasting into the empty input. | ||
| if (lastNode?.nodeName === 'DIV' && (lastNode as HTMLElement)?.innerHTML === '<br>') { |
There was a problem hiding this comment.
Hi @Skalakid
Can you explain why you check for <div><br></div> instead of just <br> ?
Is there any document on how browsers add <br> when input is empty
Thanks for your help
There was a problem hiding this comment.
Hello @drminh2807, it is because contenteditable tries to put everything into <div> elements by default. Especially when you have an empty input, the HTML content looks as follows:
<div><br /></div>
Because of this, when pasting text, a newline appears at the end of the new text. So we can remove it since it's kind of an "invisible" newline. There are more such situations, that's why we have inputUtils that parse contenteditable text content
There was a problem hiding this comment.
Is there any document on how browsers add
when input is empty
I haven't found one, every browser has different behaviour, so even if there is any article, it may describe only one of them
There was a problem hiding this comment.
There was a problem hiding this comment.
It still wraps line content with <div>, but after every newline, and that when this code is executed :D
Screen.Recording.2025-07-14.at.08.41.54.mov
There was a problem hiding this comment.
As far as I know, we don't have any documentation about parsing behavior. If you see that this condition is generating some issue, please submit a PR with repro steps, and we will review it ;)



Details
This PR refactors the web implementation of the Live Markdown library. The main goals of it are:
During this refactor phase we:
changed web live markdown HTML structure so now:
<p>- it makes structure much clear and organized, and enables us to apply custom logic to specific lines<span data-type="text">tag - by wrapping text with HTML element we enable many useful functions that aren't available in normal text node, for example:scrollIntoView()\ncharacters inside the input's HTML structure we use<br>tags - br tags give use much more flexibility and fix problem with cursor navigation when using arrow keys when moving between markdown components<br>tag is wrapped with<span data-type="br">tag - it fixes many problems connected to cursor positioningThanks to the new structure we enabled the usage of many styles that were generating a lot of bugs in the past, like
display: block. Also were able to remove all workarounds connected to cursor positioning.added HTML tree node structure, that represents current HTML dom and stores many important information about every element inside the input. Thanks to this tree structure we can easily interact with the markdown elements and we were able to completely refactor and improve the performance of cursor positioning algorithms
replaced all text value representation functions like
process valueornormalizeValuewith onetextContentvariable that always contains properly formatted text value without any additional newlines from contentEditablesplit long files of code into smaller ones, and sort functions into utils
prepared the code for new, more complex features like inline images
This refactor was made as a part of inline image feature. After discovering some structure and logic limitations when creating inline image POC we decided to improve Live Markdown for web.
This refactor will fix or unblock following issues:
Related Issues
GH_LINK
Manual Tests
Since it's a big change it would be great to test it in all cases connected to:
Linked PRs
Expensify/App#40181 (comment)