UI management system for @editorjs/image providing visual state management, preview handling, image display, and tune application with comprehensive DOM manipulation and styling.
Core UI management class responsible for rendering the tool interface, managing visual states, and handling user interactions.
class Ui {
/**
* Constructor for UI management system
* @param params - UI configuration parameters
*/
constructor(params: ConstructorParams);
/**
* Apply visual representation of activated tune
* @param tuneName - Name of the tune to apply
* @param status - Enable or disable state
*/
applyTune(tuneName: string, status: boolean): void;
/**
* Render the tool UI and return the wrapper element
* @returns HTML wrapper element
*/
render(): HTMLElement;
/**
* Show uploading preloader with preview image
* @param src - Preview source URL or data URL
*/
showPreloader(src: string): void;
/**
* Hide uploading preloader and reset to empty state
*/
hidePreloader(): void;
/**
* Display image or video element in the UI
* @param url - Image or video source URL
*/
fillImage(url: string): void;
/**
* Set caption text content
* @param text - Caption content text
*/
fillCaption(text: string): void;
/**
* Change UI visual state
* @param status - New UI state (empty, uploading, filled)
*/
toggleStatus(status: UiState): void;
/**
* DOM nodes for UI components
*/
nodes: Nodes;
}
interface ConstructorParams {
api: API;
config: ImageConfig;
onSelectFile: () => void;
readOnly: boolean;
}
interface Nodes {
wrapper: HTMLElement;
imageContainer: HTMLElement;
fileButton: HTMLElement;
imageEl?: HTMLElement;
imagePreloader: HTMLElement;
caption: HTMLElement;
}
enum UiState {
Empty = 'empty',
Uploading = 'uploading',
Filled = 'filled'
}Usage Examples:
import Ui, { UiState } from './ui';
// Initialize UI system
const ui = new Ui({
api: editorApi,
config: {
captionPlaceholder: 'Enter caption...',
buttonContent: 'Select Image'
},
onSelectFile: () => {
// Handle file selection
console.log('File selection triggered');
},
readOnly: false
});
// Render UI
const element = ui.render();
document.body.appendChild(element);
// Show loading state with preview
ui.showPreloader('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAA...');
// Load image when upload completes
ui.fillImage('https://example.com/uploaded-image.jpg');
// Add caption
ui.fillCaption('Beautiful landscape photo');
// Apply tune
ui.applyTune('withBorder', true);Comprehensive state management system handling visual transitions between empty, uploading, and filled states.
/**
* UI state enumeration representing different visual states
*/
enum UiState {
/** No image loaded, showing file selection interface */
Empty = 'empty',
/** Image is being uploaded, showing preloader */
Uploading = 'uploading',
/** Image is loaded and displayed */
Filled = 'filled'
}
/**
* Toggle UI state and apply corresponding CSS classes
* @param status - Target UI state
*/
toggleStatus(status: UiState): void;Usage Examples:
// State transitions during upload process
class ImageUploadFlow {
constructor(private ui: Ui) {}
async uploadImage(file: File) {
// Start upload - show loading state
this.ui.toggleStatus(UiState.Uploading);
this.ui.showPreloader(URL.createObjectURL(file));
try {
const result = await uploadFile(file);
// Upload successful - show filled state
this.ui.fillImage(result.url);
this.ui.toggleStatus(UiState.Filled);
} catch (error) {
// Upload failed - return to empty state
this.ui.hidePreloader();
this.ui.toggleStatus(UiState.Empty);
console.error('Upload failed:', error);
}
}
}
// CSS classes applied automatically:
// .image-tool--empty (file selection visible)
// .image-tool--uploading (preloader visible)
// .image-tool--filled (image displayed)Smart content display system supporting both images and videos with automatic format detection and appropriate element creation.
/**
* Display image or video content with automatic format detection
* @param url - Media source URL
*/
fillImage(url: string): void;Usage Examples:
// Automatic image/video detection
ui.fillImage('https://example.com/photo.jpg'); // Creates <img> element
ui.fillImage('https://example.com/video.mp4'); // Creates <video> element
// Video elements automatically include:
// - autoplay, loop, muted attributes for gif-like behavior
// - playsinline for mobile compatibility
// - loadeddata event listener instead of load
// Both formats support:
// - Load event handling
// - Error handling
// - Responsive sizing
// - Accessibility attributesSystem for applying visual representations of activated tunes through CSS class management.
/**
* Apply or remove tune-specific CSS classes
* @param tuneName - Name of the tune (withBorder, stretched, withBackground, caption)
* @param status - Enable (true) or disable (false) the tune
*/
applyTune(tuneName: string, status: boolean): void;Usage Examples:
// Apply individual tunes
ui.applyTune('withBorder', true); // .image-tool--withBorder
ui.applyTune('stretched', true); // .image-tool--stretched
ui.applyTune('withBackground', true); // .image-tool--withBackground
ui.applyTune('caption', true); // .image-tool--caption
// Remove tunes
ui.applyTune('withBorder', false); // Removes .image-tool--withBorder
// Multiple tunes can be active simultaneously
ui.applyTune('withBorder', true);
ui.applyTune('stretched', true);
// Result: .image-tool--withBorder.image-tool--stretched
// Corresponding CSS styling examples:
/*
.image-tool--withBorder .image-tool__image-picture {
border: 2px solid #e6e9ec;
border-radius: 3px;
}
.image-tool--withBackground .image-tool__image {
background: #f8f9fa;
padding: 15px;
}
.image-tool--stretched {
width: 100vw;
position: relative;
left: 50%;
transform: translateX(-50%);
}
.image-tool--caption .image-tool__caption {
display: block;
}
*/Caption input system with placeholder support, content editing, and accessibility features.
/**
* Set caption content and manage caption visibility
* @param text - Caption text content (can include HTML)
*/
fillCaption(text: string): void;Usage Examples:
// Set caption content
ui.fillCaption('Beautiful sunset over the mountains');
// Caption supports HTML content
ui.fillCaption('<em>Artistic</em> black and white photography');
// Clear caption
ui.fillCaption('');
// Caption configuration
const ui = new Ui({
config: {
captionPlaceholder: 'Enter image description...' // Placeholder text
},
readOnly: false // Allow editing
});
// Read-only mode
const readOnlyUi = new Ui({
config: { /* ... */ },
readOnly: true // Caption not editable
});File selection button with customizable content and click handling integration.
/**
* Create and configure file selection button
* @returns File selection button element
*/
private createFileButton(): HTMLElement;Usage Examples:
// Default button content
const ui = new Ui({
config: {
// Uses default: IconPicture + "Select an Image"
}
});
// Custom button content
const ui = new Ui({
config: {
buttonContent: `
<svg viewBox="0 0 24 24">
<path d="M9,16V10H5L12,3L19,10H15V16H9Z"/>
</svg>
Upload Photo
`
}
});
// Internationalized button
const ui = new Ui({
config: {
buttonContent: `
${customIcon}
${i18n.t('image.button.select')}
`
}
});
// Button automatically triggers file selection
// and integrates with upload systemComprehensive CSS class system providing styling hooks for all UI states and tune configurations.
/**
* CSS class names used throughout the UI system
*/
private get CSS(): Record<string, string> {
return {
baseClass: string; // Editor.js base block class
loading: string; // Editor.js loader class
input: string; // Editor.js input class
button: string; // Editor.js button class
wrapper: string; // 'image-tool'
imageContainer: string; // 'image-tool__image'
imagePreloader: string; // 'image-tool__image-preloader'
imageEl: string; // 'image-tool__image-picture'
caption: string; // 'image-tool__caption'
};
}Usage Examples:
// CSS classes applied automatically:
// Base structure:
// .image-tool (wrapper)
// .image-tool__image (image container)
// .image-tool__image-preloader (loading preview)
// .image-tool__image-picture (actual image/video)
// .image-tool__caption (caption input)
// State classes:
// .image-tool--empty (no image)
// .image-tool--uploading (loading)
// .image-tool--filled (image loaded)
// Tune classes:
// .image-tool--withBorder (border enabled)
// .image-tool--stretched (full width)
// .image-tool--withBackground (background enabled)
// .image-tool--caption (caption visible)
// Custom styling example:
/*
.image-tool {
margin: 10px 0;
}
.image-tool--uploading .image-tool__image-preloader {
background-size: cover;
background-position: center;
opacity: 0.6;
filter: blur(2px);
}
.image-tool--filled .image-tool__image-picture {
max-width: 100%;
height: auto;
display: block;
}
*/