feat(editor): Add wysiwyg editor
This commit is contained in:
@ -100,16 +100,25 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setBlockContents() {
|
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 => {
|
this.blocks.forEach(block => {
|
||||||
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${block.id}"]`);
|
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${block.id}"]`);
|
||||||
if (wrapperElement) {
|
if (wrapperElement) {
|
||||||
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
|
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
|
||||||
if (blockElement && document.activeElement !== blockElement && block.type !== 'divider') {
|
if (blockElement && document.activeElement !== blockElement && block.type !== 'divider') {
|
||||||
if (block.type === 'list') {
|
// Only set content if the element is empty or has placeholder text
|
||||||
blockElement.innerHTML = WysiwygBlocks.renderListContent(block.content, block.metadata);
|
const currentContent = blockElement.textContent || '';
|
||||||
} else {
|
const isEmpty = !currentContent || currentContent === 'Type \'/\' for commands...' ||
|
||||||
blockElement.textContent = block.content;
|
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 {
|
||||||
|
blockElement.textContent = block.content;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,9 +265,12 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
|
|||||||
this.blocks = [...this.blocks.slice(0, blockIndex + 1), newBlock, ...this.blocks.slice(blockIndex + 1)];
|
this.blocks = [...this.blocks.slice(0, blockIndex + 1), newBlock, ...this.blocks.slice(blockIndex + 1)];
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const newBlockElement = this.shadowRoot!.querySelector(`[data-block-id="${newBlock.id}"]`) as HTMLDivElement;
|
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${newBlock.id}"]`);
|
||||||
if (newBlockElement) {
|
if (wrapperElement) {
|
||||||
newBlockElement.focus();
|
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
|
||||||
|
if (blockElement) {
|
||||||
|
blockElement.focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -391,10 +403,13 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
|
|||||||
this.updateValue();
|
this.updateValue();
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const prevBlockElement = this.shadowRoot!.querySelector(`[data-block-id="${prevBlock.id}"]`) as HTMLDivElement;
|
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${prevBlock.id}"]`);
|
||||||
if (prevBlockElement && prevBlock.type !== 'divider') {
|
if (wrapperElement && prevBlock.type !== 'divider') {
|
||||||
prevBlockElement.focus();
|
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
|
||||||
WysiwygBlocks.setCursorToEnd(prevBlockElement);
|
if (blockElement) {
|
||||||
|
blockElement.focus();
|
||||||
|
WysiwygBlocks.setCursorToEnd(blockElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -509,10 +524,13 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
|
|||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
if (target.classList.contains('editor-content')) {
|
if (target.classList.contains('editor-content')) {
|
||||||
const lastBlock = this.blocks[this.blocks.length - 1];
|
const lastBlock = this.blocks[this.blocks.length - 1];
|
||||||
const lastBlockElement = this.shadowRoot!.querySelector(`[data-block-id="${lastBlock.id}"]`) as HTMLDivElement;
|
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${lastBlock.id}"]`);
|
||||||
if (lastBlockElement && lastBlock.type !== 'divider') {
|
if (wrapperElement && lastBlock.type !== 'divider') {
|
||||||
lastBlockElement.focus();
|
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
|
||||||
WysiwygBlocks.setCursorToEnd(lastBlockElement);
|
if (blockElement) {
|
||||||
|
blockElement.focus();
|
||||||
|
WysiwygBlocks.setCursorToEnd(blockElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -535,28 +553,37 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
|
|||||||
this.blocks = [...this.blocks.slice(0, currentBlockIndex + 1), newBlock, ...this.blocks.slice(currentBlockIndex + 1)];
|
this.blocks = [...this.blocks.slice(0, currentBlockIndex + 1), newBlock, ...this.blocks.slice(currentBlockIndex + 1)];
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const newBlockElement = this.shadowRoot!.querySelector(`[data-block-id="${newBlock.id}"]`) as HTMLDivElement;
|
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${newBlock.id}"]`);
|
||||||
if (newBlockElement) {
|
if (wrapperElement) {
|
||||||
newBlockElement.focus();
|
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
|
||||||
|
if (blockElement) {
|
||||||
|
blockElement.focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (type === 'list') {
|
} else if (type === 'list') {
|
||||||
// Handle list type specially
|
// Handle list type specially
|
||||||
currentBlock.metadata = { listType: 'bullet' }; // Default to bullet list
|
currentBlock.metadata = { listType: 'bullet' }; // Default to bullet list
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const blockElement = this.shadowRoot!.querySelector(`[data-block-id="${currentBlock.id}"]`) as HTMLDivElement;
|
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${currentBlock.id}"]`);
|
||||||
if (blockElement) {
|
if (wrapperElement) {
|
||||||
blockElement.innerHTML = '<ul><li></li></ul>';
|
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
|
||||||
WysiwygBlocks.focusListItem(blockElement);
|
if (blockElement) {
|
||||||
|
blockElement.innerHTML = '<ul><li></li></ul>';
|
||||||
|
WysiwygBlocks.focusListItem(blockElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Force update the contenteditable element
|
// Force update the contenteditable element
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const blockElement = this.shadowRoot!.querySelector(`[data-block-id="${currentBlock.id}"]`) as HTMLDivElement;
|
const wrapperElement = this.shadowRoot!.querySelector(`[data-block-id="${currentBlock.id}"]`);
|
||||||
if (blockElement) {
|
if (wrapperElement) {
|
||||||
blockElement.textContent = '';
|
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
|
||||||
blockElement.focus();
|
if (blockElement) {
|
||||||
|
blockElement.textContent = '';
|
||||||
|
blockElement.focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,6 @@ export class WysiwygBlocks {
|
|||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
class="block ${block.type} ${isSelected ? 'selected' : ''}"
|
class="block ${block.type} ${isSelected ? 'selected' : ''}"
|
||||||
data-block-id="${block.id}"
|
|
||||||
contenteditable="true"
|
contenteditable="true"
|
||||||
@input="${handlers.onInput}"
|
@input="${handlers.onInput}"
|
||||||
@keydown="${handlers.onKeyDown}"
|
@keydown="${handlers.onKeyDown}"
|
||||||
@ -61,7 +60,6 @@ export class WysiwygBlocks {
|
|||||||
@blur="${handlers.onBlur}"
|
@blur="${handlers.onBlur}"
|
||||||
@compositionstart="${handlers.onCompositionStart}"
|
@compositionstart="${handlers.onCompositionStart}"
|
||||||
@compositionend="${handlers.onCompositionEnd}"
|
@compositionend="${handlers.onCompositionEnd}"
|
||||||
.textContent="${block.content}"
|
|
||||||
></div>
|
></div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user