6.8 KiB
6.8 KiB
WYSIWYG Editor Refactoring Progress Summary
Latest Updates
Selection Highlighting Fix ✅
- Issue: "Paragraphs are not highlighted consistently, headings are always highlighted"
- Root Cause: The
shouldUpdate
method indees-wysiwyg-block.ts
was using a generic.block
selector that would match the first element with that class, not necessarily the correct block element - Solution: Changed the selector to be more specific:
.block.${blockType}
which ensures the correct element is found for each block type - Result: All block types now highlight consistently when selected
Enter Key Block Creation Fix ✅
- Issue: "When pressing enter and jumping to new block then typing something: The cursor is not at the beginning of the new block and there is content"
- Root Cause: Block handlers were rendering content with template syntax
${block.content || ''}
in their render methods, which violates the static HTML principle - Solution:
- Removed all
${block.content}
from render methods in paragraph, heading, quote, and code block handlers - Content is now set programmatically in the setup() method only when needed
- Fixed
setCursorToStart
andsetCursorToEnd
to always find elements fresh instead of relying on cachedblockElement
- Removed all
- Result: New empty blocks remain truly empty, cursor positioning works correctly
Backspace Key Deletion Fix ✅
- Issue: "After typing in a new block, pressing backspace deletes the whole block instead of just the last character"
- Root Cause:
getCursorPositionInElement
was usingelement.contains()
which doesn't work across Shadow DOM boundaries- The backspace handler was checking
block.content === ''
which only contains the stored content, not the actual DOM content
- Solution:
- Fixed
getCursorPositionInElement
to usecontainsAcrossShadowDOM
for proper Shadow DOM support - Updated backspace handler to get actual content from DOM using
blockComponent.getContent()
instead of relying on storedblock.content
- Added debug logging to track cursor position and content state
- Fixed
- Result: Backspace now correctly deletes individual characters instead of the whole block
Arrow Left Navigation Fix ✅
- Issue: "When jumping to the previous block from the beginning of a block with arrow left, the cursor should be at the end of the previous block, not at the start"
- Root Cause: Browser's default focus behavior places cursor at the beginning of contenteditable elements, overriding our cursor positioning
- Solution: For 'end' position, set up the selection range BEFORE focusing the element:
- Create a range pointing to the end of content
- Apply the selection
- Then focus the element (which preserves the existing selection)
- Only use setCursorToEnd for empty blocks
- Result: Arrow left navigation now correctly places cursor at the end of the previous block
Completed Phases
Phase 1: Infrastructure ✅
- Created modular block handler architecture
- Implemented
IBlockHandler
interface andBaseBlockHandler
class - Created
BlockRegistry
for dynamic block type registration - Set up proper file structure under
blocks/
directory
Phase 2: Proof of Concept ✅
- Successfully migrated divider block as the simplest example
- Validated the architecture works correctly
- Established patterns for block migration
Phase 3: Text Blocks ✅
- Paragraph Block: Full editing support with text splitting, selection handling, and cursor tracking
- Heading Blocks: All three heading levels (h1, h2, h3) with unified handler
- Quote Block: Italic styling with border, full editing capabilities
- Code Block: Monospace font, tab handling, plain text paste support
- List Block: Bullet/numbered lists with proper list item management
Key Achievements
1. Preserved Critical Knowledge
- Static Rendering: Blocks use
innerHTML
infirstUpdated
to prevent focus loss during typing - Shadow DOM Selection: Implemented
containsAcrossShadowDOM
utility for proper selection detection - Cursor Position Tracking: All editable blocks track cursor position across multiple events
- Content Splitting: HTML-aware splitting using Range API preserves formatting
- Focus Management: Microtask-based focus restoration ensures reliable cursor placement
2. Enhanced Architecture
- Each block type is now self-contained in its own file
- Block handlers are dynamically registered and loaded
- Common functionality is shared through base classes
- Styles are co-located with their block handlers
3. Maintained Functionality
- All keyboard navigation works (arrows, backspace, delete, enter)
- Text selection across Shadow DOM boundaries functions correctly
- Block merging and splitting behave as before
- IME (Input Method Editor) support is preserved
- Formatting shortcuts (Cmd/Ctrl+B/I/U/K) continue to work
Code Organization
ts_web/elements/wysiwyg/
├── dees-wysiwyg-block.ts (simplified main component)
├── wysiwyg.selection.ts (Shadow DOM selection utilities)
├── wysiwyg.blockregistration.ts (handler registration)
└── blocks/
├── index.ts (exports and registry)
├── block.base.ts (base handler interface)
├── decorative/
│ └── divider.block.ts
└── text/
├── paragraph.block.ts
├── heading.block.ts
├── quote.block.ts
├── code.block.ts
└── list.block.ts
Next Steps
Phase 4: Media Blocks (In Progress)
- Image block with upload/drag-drop support
- YouTube block with video embedding
- Attachment block for file uploads
Phase 5: Content Blocks
- Markdown block with preview toggle
- HTML block with raw HTML editing
Phase 6: Cleanup
- Remove old code from main component
- Optimize bundle size
- Update documentation
Technical Improvements
- Modularity: Each block type is now completely self-contained
- Extensibility: New blocks can be added by creating a handler and registering it
- Maintainability: Files are smaller and focused on single responsibilities
- Type Safety: Strong TypeScript interfaces ensure consistent implementation
- Performance: No degradation in performance; potential for lazy loading in future
Migration Pattern
For future block migrations, follow this pattern:
- Create block handler extending
BaseBlockHandler
- Implement required methods:
render()
,setup()
,getStyles()
- Add helper methods for cursor/content management
- Handle Shadow DOM selection properly using utilities
- Register handler in
wysiwyg.blockregistration.ts
- Test all interactions (typing, selection, navigation)
The refactoring has been successful in making the codebase more maintainable while preserving all the hard-won functionality and edge case handling from the original implementation.