feat(editor): Add wysiwyg editor

This commit is contained in:
Juergen Kunz
2025-06-23 18:07:46 +00:00
parent a1079cbbdd
commit 0f02e7d00f
2 changed files with 54 additions and 29 deletions

View File

@ -100,12 +100,20 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
}
private setBlockContents() {
// Only set content for blocks that aren't being edited
// Set content for blocks that aren't being edited and don't already have content
this.blocks.forEach(block => {
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${block.id}"]`);
if (wrapperElement) {
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
if (blockElement && document.activeElement !== blockElement && block.type !== 'divider') {
// Only set content if the element is empty or has placeholder text
const currentContent = blockElement.textContent || '';
const isEmpty = !currentContent || currentContent === 'Type \'/\' for commands...' ||
currentContent === 'Heading 1' || currentContent === 'Heading 2' ||
currentContent === 'Heading 3' || currentContent === 'Quote' ||
currentContent === 'Code block';
if (isEmpty && block.content) {
if (block.type === 'list') {
blockElement.innerHTML = WysiwygBlocks.renderListContent(block.content, block.metadata);
} else {
@ -113,6 +121,7 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
}
}
}
}
});
}
@ -256,9 +265,12 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
this.blocks = [...this.blocks.slice(0, blockIndex + 1), newBlock, ...this.blocks.slice(blockIndex + 1)];
setTimeout(() => {
const newBlockElement = this.shadowRoot!.querySelector(`[data-block-id="${newBlock.id}"]`) as HTMLDivElement;
if (newBlockElement) {
newBlockElement.focus();
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${newBlock.id}"]`);
if (wrapperElement) {
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
if (blockElement) {
blockElement.focus();
}
}
});
@ -391,10 +403,13 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
this.updateValue();
setTimeout(() => {
const prevBlockElement = this.shadowRoot!.querySelector(`[data-block-id="${prevBlock.id}"]`) as HTMLDivElement;
if (prevBlockElement && prevBlock.type !== 'divider') {
prevBlockElement.focus();
WysiwygBlocks.setCursorToEnd(prevBlockElement);
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${prevBlock.id}"]`);
if (wrapperElement && prevBlock.type !== 'divider') {
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
if (blockElement) {
blockElement.focus();
WysiwygBlocks.setCursorToEnd(blockElement);
}
}
});
}
@ -509,10 +524,13 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
const target = e.target as HTMLElement;
if (target.classList.contains('editor-content')) {
const lastBlock = this.blocks[this.blocks.length - 1];
const lastBlockElement = this.shadowRoot!.querySelector(`[data-block-id="${lastBlock.id}"]`) as HTMLDivElement;
if (lastBlockElement && lastBlock.type !== 'divider') {
lastBlockElement.focus();
WysiwygBlocks.setCursorToEnd(lastBlockElement);
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${lastBlock.id}"]`);
if (wrapperElement && lastBlock.type !== 'divider') {
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
if (blockElement) {
blockElement.focus();
WysiwygBlocks.setCursorToEnd(blockElement);
}
}
}
}
@ -535,29 +553,38 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
this.blocks = [...this.blocks.slice(0, currentBlockIndex + 1), newBlock, ...this.blocks.slice(currentBlockIndex + 1)];
setTimeout(() => {
const newBlockElement = this.shadowRoot!.querySelector(`[data-block-id="${newBlock.id}"]`) as HTMLDivElement;
if (newBlockElement) {
newBlockElement.focus();
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${newBlock.id}"]`);
if (wrapperElement) {
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
if (blockElement) {
blockElement.focus();
}
}
});
} else if (type === 'list') {
// Handle list type specially
currentBlock.metadata = { listType: 'bullet' }; // Default to bullet list
setTimeout(() => {
const blockElement = this.shadowRoot!.querySelector(`[data-block-id="${currentBlock.id}"]`) as HTMLDivElement;
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${currentBlock.id}"]`);
if (wrapperElement) {
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
if (blockElement) {
blockElement.innerHTML = '<ul><li></li></ul>';
WysiwygBlocks.focusListItem(blockElement);
}
}
});
} else {
// Force update the contenteditable element
setTimeout(() => {
const blockElement = this.shadowRoot!.querySelector(`[data-block-id="${currentBlock.id}"]`) as HTMLDivElement;
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${currentBlock.id}"]`);
if (wrapperElement) {
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
if (blockElement) {
blockElement.textContent = '';
blockElement.focus();
}
}
});
}
}

View File

@ -53,7 +53,6 @@ export class WysiwygBlocks {
return html`
<div
class="block ${block.type} ${isSelected ? 'selected' : ''}"
data-block-id="${block.id}"
contenteditable="true"
@input="${handlers.onInput}"
@keydown="${handlers.onKeyDown}"
@ -61,7 +60,6 @@ export class WysiwygBlocks {
@blur="${handlers.onBlur}"
@compositionstart="${handlers.onCompositionStart}"
@compositionend="${handlers.onCompositionEnd}"
.textContent="${block.content}"
></div>
`;
}