Edit block when using custom view

When using custom views for blocks, the content in view is by default not clickable and possible to open/edit block.
However it has entity action, which can we used.

We can wrap inside umb-ref-grid-block or umb-ref-item and use href propery for these, but it may not look nice as it as it add an icon and it this case image/content wasn’t clickable.

I found we can just use <a> using href:

import { html, css, customElement, LitElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
import { UmbImagingRepository } from '@umbraco-cms/backoffice/imaging';
import { type PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
import type { UmbBlockEditorCustomViewElement, UmbBlockEditorCustomViewConfiguration } from '@umbraco-cms/backoffice/block-custom-view';
import type { UmbBlockDataType } from '@umbraco-cms/backoffice/block';
import type { UmbMediaPickerPropertyValueEntry } from '@umbraco-cms/backoffice/media';

@customElement('mcb-image-block-view')
export class McbImageBlockView extends UmbElementMixin(LitElement) implements UmbBlockEditorCustomViewElement {

	@property({ attribute: false })
	config?: UmbBlockEditorCustomViewConfiguration;

	@property({ attribute: false })
	content?: UmbBlockDataType;

	@state()
	imageUrls: Map<string, string> = new Map();

	@state()
	images: UmbMediaPickerPropertyValueEntry[] = [];

	#imagingRepository = new UmbImagingRepository(this);

	// Watch for content updates
	updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
		super.updated?.(changedProperties);
		if (changedProperties.has('content') && this.content?.image) {
			this.images = this.content.image as UmbMediaPickerPropertyValueEntry[];
			this._fetchImageUrls();
		}
	}

	async _fetchImageUrls() {
		for (const item of this.images) {
			if (item.mediaKey && !this.imageUrls.has(item.mediaKey)) {
				const url = await this._resolveImageUrl(item.mediaKey);
				if (url) {
					this.imageUrls.set(item.mediaKey, url);
					this.requestUpdate(); // Trigger re-render
				}
			}
		}
	}

	async _resolveImageUrl(mediaKey: string): Promise<string> {
		try {
			const { data } = await this.#imagingRepository.requestThumbnailUrls([mediaKey], 1200, 0);
			return data?.[0]?.url ?? '';
		} catch (err) {
			console.warn('Failed to load media URL for:', mediaKey, err);
			return '';
		}
	}

	render() {
		if (!this.content?.image) {
			return html`<em>No image selected</em>`;
		}

		return html`
			<a href=${(this.config?.showContentEdit ? this.config?.editContentPath : undefined) ?? ''}>
				<div class="image-block">
					${this.images.map((item: UmbMediaPickerPropertyValueEntry) => {
						const src = this.imageUrls.get(item.mediaKey) || '';
						return src
							? html`<img src="${src}" alt="" loading="lazy" style="max-width: 100%; height: auto;" />`
							: html`<uui-loader></uui-loader>`;
					})}
				</div>
			</a>
		`;
	}

	static styles = [
		css`
			:host {
				display: block;
				box-sizing: border-box;
			}
		`
	];
}

export default McbImageBlockView;

But I wonder if there is a component for this? And instead of constructing href maybe it can just accept a property for UmbBlockEditorCustomViewConfiguration and perhaps other things the component may handle like focus outline etc.

1 Like