fix(wysiwyg): Implement programmatic rendering to eliminate focus loss during typing

- Convert parent component to use static rendering with programmatic DOM manipulation
- Remove all reactive state that could trigger re-renders during editing
- Delay content sync to avoid interference with typing (2s auto-save)
- Update all block operations to use manual DOM updates instead of Lit re-renders
- Fix specific issue where typing + arrow keys caused focus loss
- Add comprehensive focus management documentation
This commit is contained in:
Juergen Kunz
2025-06-24 11:06:02 +00:00
parent 8b02c5aea3
commit 1c76ade150
6 changed files with 401 additions and 95 deletions

View File

@ -34,12 +34,20 @@ export class WysiwygBlockOperations {
...blocks.slice(blockIndex + 1)
];
// Insert the new block element programmatically if we have the editor
if (this.component.editorContentRef) {
const afterWrapper = this.component.editorContentRef.querySelector(`[data-block-id="${afterBlock.id}"]`);
if (afterWrapper) {
const newWrapper = this.component.createBlockElement(newBlock);
afterWrapper.insertAdjacentElement('afterend', newWrapper);
}
}
this.component.updateValue();
this.component.requestUpdate();
if (focusNewBlock && newBlock.type !== 'divider') {
// Wait for the component to update
await this.component.updateComplete;
// Give DOM time to settle
await new Promise(resolve => setTimeout(resolve, 0));
// Focus the new block
await this.focusBlock(newBlock.id, 'start');
@ -51,6 +59,15 @@ export class WysiwygBlockOperations {
*/
removeBlock(blockId: string): void {
this.component.blocks = this.component.blocks.filter((b: IBlock) => b.id !== blockId);
// Remove the block element programmatically if we have the editor
if (this.component.editorContentRef) {
const wrapper = this.component.editorContentRef.querySelector(`[data-block-id="${blockId}"]`);
if (wrapper) {
wrapper.remove();
}
}
this.component.updateValue();
}
@ -72,9 +89,6 @@ export class WysiwygBlockOperations {
* Focuses a specific block
*/
async focusBlock(blockId: string, cursorPosition: 'start' | 'end' | number = 'start'): Promise<void> {
// First ensure the component is updated
await this.component.updateComplete;
const wrapperElement = this.component.shadowRoot!.querySelector(`[data-block-id="${blockId}"]`);
if (wrapperElement) {
const blockComponent = wrapperElement.querySelector('dees-wysiwyg-block') as any;
@ -110,8 +124,13 @@ export class WysiwygBlockOperations {
if (metadata) {
block.metadata = metadata;
}
// Update the block element programmatically if we have the editor
if (this.component.editorContentRef) {
this.component.updateBlockElement(blockId);
}
this.component.updateValue();
this.component.requestUpdate();
}
}