This commit is contained in:
Juergen Kunz
2025-06-24 18:43:51 +00:00
parent fca3638f7f
commit 89a4a15e78
3 changed files with 275 additions and 42 deletions

View File

@ -142,15 +142,28 @@ export class DeesWysiwygBlock extends DeesElement {
}
.block.divider {
padding: 0;
padding: 8px 0;
margin: 16px 0;
pointer-events: none;
cursor: pointer;
position: relative;
border-radius: 4px;
transition: all 0.15s ease;
}
.block.divider:focus {
outline: none;
}
.block.divider.selected {
background: ${cssManager.bdTheme('rgba(0, 102, 204, 0.05)', 'rgba(77, 148, 255, 0.08)')};
box-shadow: inset 0 0 0 2px ${cssManager.bdTheme('rgba(0, 102, 204, 0.2)', 'rgba(77, 148, 255, 0.2)')};
}
.block.divider hr {
border: none;
border-top: 1px solid ${cssManager.bdTheme('#e0e0e0', '#333')};
margin: 0;
pointer-events: none;
}
/* Formatting styles */
@ -271,6 +284,16 @@ export class DeesWysiwygBlock extends DeesElement {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.15s ease;
}
.block.image:focus {
outline: none;
}
.block.image.selected {
box-shadow: 0 0 0 3px ${cssManager.bdTheme('rgba(0, 102, 204, 0.3)', 'rgba(77, 148, 255, 0.3)')};
}
.image-upload-placeholder {
@ -349,6 +372,20 @@ export class DeesWysiwygBlock extends DeesElement {
];
protected shouldUpdate(changedProperties: Map<string, any>): boolean {
// If selection state changed, we need to update for non-editable blocks
if (changedProperties.has('isSelected') && (this.block?.type === 'divider' || this.block?.type === 'image')) {
// For non-editable blocks, we need to update the selected class
const element = this.shadowRoot?.querySelector('.block') as HTMLElement;
if (element) {
if (this.isSelected) {
element.classList.add('selected');
} else {
element.classList.remove('selected');
}
}
return false; // Don't re-render, just update the class
}
// Never update if only the block content changed
if (changedProperties.has('block') && this.block) {
const oldBlock = changedProperties.get('block');
@ -372,10 +409,13 @@ export class DeesWysiwygBlock extends DeesElement {
container.innerHTML = this.renderBlockContent();
}
// Handle image block setup
// Handle special block types
if (this.block.type === 'image') {
this.setupImageBlock();
return; // Image blocks don't need the standard editable setup
} else if (this.block.type === 'divider') {
this.setupDividerBlock();
return; // Divider blocks don't need the standard editable setup
}
// Now find the actual editable block element
@ -575,8 +615,9 @@ export class DeesWysiwygBlock extends DeesElement {
if (!this.block) return '';
if (this.block.type === 'divider') {
const selectedClass = this.isSelected ? ' selected' : '';
return `
<div class="block divider" data-block-id="${this.block.id}" data-block-type="${this.block.type}">
<div class="block divider${selectedClass}" data-block-id="${this.block.id}" data-block-type="${this.block.type}" tabindex="0">
<hr>
</div>
`;
@ -603,7 +644,7 @@ export class DeesWysiwygBlock extends DeesElement {
const isLoading = this.block.metadata?.loading || false;
return `
<div class="block image${selectedClass}" data-block-id="${this.block.id}" data-block-type="${this.block.type}">
<div class="block image${selectedClass}" data-block-id="${this.block.id}" data-block-type="${this.block.type}" tabindex="0">
${isLoading ? `
<div class="image-loading">Uploading image...</div>
` : ''}
@ -655,13 +696,19 @@ export class DeesWysiwygBlock extends DeesElement {
public focus(): void {
// Image blocks don't focus in the traditional way
// Handle non-editable blocks
if (this.block?.type === 'image') {
const imageBlock = this.shadowRoot?.querySelector('.block.image') as HTMLDivElement;
if (imageBlock) {
imageBlock.focus();
}
return;
} else if (this.block?.type === 'divider') {
const dividerBlock = this.shadowRoot?.querySelector('.block.divider') as HTMLDivElement;
if (dividerBlock) {
dividerBlock.focus();
}
return;
}
// Get the actual editable element (might be nested for code blocks)
@ -687,8 +734,8 @@ export class DeesWysiwygBlock extends DeesElement {
}
public focusWithCursor(position: 'start' | 'end' | number = 'end'): void {
// Image blocks don't support cursor positioning
if (this.block?.type === 'image') {
// Non-editable blocks don't support cursor positioning
if (this.block?.type === 'image' || this.block?.type === 'divider') {
this.focus();
return;
}
@ -866,6 +913,42 @@ export class DeesWysiwygBlock extends DeesElement {
}
}
/**
* Setup divider block functionality
*/
private setupDividerBlock(): void {
const dividerBlock = this.shadowRoot?.querySelector('.block.divider') as HTMLDivElement;
if (!dividerBlock) return;
// Handle click to select
dividerBlock.addEventListener('click', (e) => {
e.stopPropagation();
// Focus will trigger the selection
dividerBlock.focus();
});
// Handle focus/blur
dividerBlock.addEventListener('focus', () => {
this.handlers?.onFocus?.();
});
dividerBlock.addEventListener('blur', () => {
this.handlers?.onBlur?.();
});
// Handle keyboard events
dividerBlock.addEventListener('keydown', (e) => {
if (e.key === 'Backspace' || e.key === 'Delete') {
e.preventDefault();
// Let the keyboard handler in the parent component handle the deletion
this.handlers?.onKeyDown?.(e);
} else {
// Handle navigation keys
this.handlers?.onKeyDown?.(e);
}
});
}
/**
* Setup image block functionality
*/
@ -873,8 +956,17 @@ export class DeesWysiwygBlock extends DeesElement {
const imageBlock = this.shadowRoot?.querySelector('.block.image') as HTMLDivElement;
if (!imageBlock) return;
// Make the image block focusable
imageBlock.setAttribute('tabindex', '0');
// Note: tabindex is already set in the HTML
// Handle click to select the block
imageBlock.addEventListener('click', (e) => {
// Don't stop propagation for file input clicks
if ((e.target as HTMLElement).tagName !== 'INPUT') {
e.stopPropagation();
// Focus will trigger the selection
imageBlock.focus();
}
});
// Handle click on upload placeholder
const uploadPlaceholder = imageBlock.querySelector('.image-upload-placeholder');
@ -931,7 +1023,14 @@ export class DeesWysiwygBlock extends DeesElement {
// Handle keyboard events
imageBlock.addEventListener('keydown', (e) => {
this.handlers?.onKeyDown?.(e);
if (e.key === 'Backspace' || e.key === 'Delete') {
e.preventDefault();
// Let the keyboard handler in the parent component handle the deletion
this.handlers?.onKeyDown?.(e);
} else {
// Handle navigation keys
this.handlers?.onKeyDown?.(e);
}
});
}