diff --git a/ts_web/elements/wysiwyg/dees-wysiwyg-block.ts b/ts_web/elements/wysiwyg/dees-wysiwyg-block.ts index c395143..609338a 100644 --- a/ts_web/elements/wysiwyg/dees-wysiwyg-block.ts +++ b/ts_web/elements/wysiwyg/dees-wysiwyg-block.ts @@ -925,6 +925,8 @@ export class DeesWysiwygBlock extends DeesElement { e.stopPropagation(); // Focus will trigger the selection dividerBlock.focus(); + // Ensure focus handler is called immediately + this.handlers?.onFocus?.(); }); // Handle focus/blur @@ -965,6 +967,8 @@ export class DeesWysiwygBlock extends DeesElement { e.stopPropagation(); // Focus will trigger the selection imageBlock.focus(); + // Ensure focus handler is called immediately + this.handlers?.onFocus?.(); } }); diff --git a/ts_web/elements/wysiwyg/wysiwyg.keyboardhandler.ts b/ts_web/elements/wysiwyg/wysiwyg.keyboardhandler.ts index 633a697..16b0b57 100644 --- a/ts_web/elements/wysiwyg/wysiwyg.keyboardhandler.ts +++ b/ts_web/elements/wysiwyg/wysiwyg.keyboardhandler.ts @@ -237,8 +237,26 @@ export class WysiwygKeyboardHandler { if (block.type === 'divider' || block.type === 'image') { e.preventDefault(); - // Don't delete if it's the only block + // If it's the only block, delete it and create a new paragraph if (this.component.blocks.length === 1) { + // Save state for undo + this.component.saveToHistory(false); + + // Remove the block + blockOps.removeBlock(block.id); + + // Create a new paragraph block + const newBlock = blockOps.createBlock('paragraph', ''); + this.component.blocks = [newBlock]; + + // Re-render blocks + this.component.renderBlocksProgrammatically(); + + // Focus the new block + await blockOps.focusBlock(newBlock.id, 'start'); + + // Update value + this.component.updateValue(); return; } @@ -292,7 +310,13 @@ export class WysiwygKeyboardHandler { e.preventDefault(); const prevBlock = blockOps.getPreviousBlock(block.id); - if (prevBlock && prevBlock.type !== 'divider') { + if (prevBlock) { + // If previous block is non-editable (divider/image), select it first + if (prevBlock.type === 'divider' || prevBlock.type === 'image') { + await blockOps.focusBlock(prevBlock.id); + return; + } + console.log('Backspace at start: Merging with previous block'); // Save checkpoint for undo @@ -377,8 +401,26 @@ export class WysiwygKeyboardHandler { if (block.type === 'divider' || block.type === 'image') { e.preventDefault(); - // Don't delete if it's the only block + // If it's the only block, delete it and create a new paragraph if (this.component.blocks.length === 1) { + // Save state for undo + this.component.saveToHistory(false); + + // Remove the block + blockOps.removeBlock(block.id); + + // Create a new paragraph block + const newBlock = blockOps.createBlock('paragraph', ''); + this.component.blocks = [newBlock]; + + // Re-render blocks + this.component.renderBlocksProgrammatically(); + + // Focus the new block + await blockOps.focusBlock(newBlock.id, 'start'); + + // Update value + this.component.updateValue(); return; } @@ -408,7 +450,38 @@ export class WysiwygKeyboardHandler { return; } - // For editable blocks, let browser handle normal delete + // For editable blocks, check if we're at the end and next block is non-editable + const blockWrapper = this.component.shadowRoot?.querySelector(`[data-block-id="${block.id}"]`); + const blockComponent = blockWrapper?.querySelector('dees-wysiwyg-block') as any; + if (!blockComponent || !blockComponent.shadowRoot) return; + + // Get the actual editable element + const target = block.type === 'code' + ? blockComponent.shadowRoot.querySelector('.block.code') as HTMLElement + : blockComponent.shadowRoot.querySelector('.block') as HTMLElement; + if (!target) return; + + // Get cursor position + const parentComponent = blockComponent.closest('dees-input-wysiwyg'); + const shadowRoots: ShadowRoot[] = []; + if (parentComponent?.shadowRoot) shadowRoots.push(parentComponent.shadowRoot); + shadowRoots.push(blockComponent.shadowRoot); + + const cursorPos = WysiwygSelection.getCursorPositionInElement(target, ...shadowRoots); + const textLength = target.textContent?.length || 0; + + // Check if cursor is at the end of the block + if (cursorPos === textLength) { + const nextBlock = blockOps.getNextBlock(block.id); + + if (nextBlock && (nextBlock.type === 'divider' || nextBlock.type === 'image')) { + e.preventDefault(); + await blockOps.focusBlock(nextBlock.id); + return; + } + } + + // Otherwise, let browser handle normal delete } /**