CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-udecode--plate-image

Image plugin for Plate rich text editor that enables embedding, uploading, and managing images with advanced features like drag-and-drop, resizing, and captions.

Pending
Overview
Eval results
Files

hooks-state.mddocs/

Hooks and State Management

React hooks for accessing image element data, managing captions, and integrating with the image store system.

Capabilities

Image Element Hook

Hook to access the current image element data within image component contexts.

/**
 * Hook to get the current image element data
 * Must be used within an image element component context
 * @returns Current TImageElement with url, width, and caption properties
 */
function useImageElement(): TImageElement;

Usage Examples:

import { useImageElement, TImageElement } from "@udecode/plate-image";

// Access image properties in component
function MyImageComponent() {
  const element = useImageElement();
  
  return (
    <div>
      <img src={element.url} style={{ width: element.width }} />
      {element.caption && (
        <figcaption>
          Caption has {element.caption.length} nodes
        </figcaption>
      )}
    </div>
  );
}

// Conditional rendering based on image properties
function ConditionalImageRenderer() {
  const element = useImageElement();
  
  const hasCaption = element.caption && element.caption.length > 0;
  const hasWidth = element.width && element.width > 0;
  
  return (
    <figure className={`image ${hasCaption ? 'with-caption' : ''}`}>
      <img 
        src={element.url}
        style={{ 
          width: hasWidth ? `${element.width}px` : '100%',
          maxWidth: '100%'
        }}
        draggable={true}
      />
      {hasCaption && (
        <figcaption>Image has caption content</figcaption>
      )}
    </figure>
  );
}

Image Caption String Hook

Hook to extract and memoize the caption text as a plain string from the image element.

/**
 * Hook to get image caption as a plain string
 * Extracts text content from caption descendant nodes and memoizes the result
 * @returns String representation of the caption content (empty string if no caption)
 */
function useImageCaptionString(): string;

Usage Examples:

import { useImageCaptionString } from "@udecode/plate-image";

// Use caption string for alt text
function AccessibleImage() {
  const captionString = useImageCaptionString();
  const element = useImageElement();
  
  return (
    <img 
      src={element.url}
      alt={captionString || 'Image'}
      title={captionString}
    />
  );
}

// Conditional rendering based on caption content
function CaptionDisplay() {
  const captionString = useImageCaptionString();
  
  if (!captionString.length) {
    return <div className="no-caption">No caption available</div>;
  }
  
  return (
    <figcaption className="image-caption">
      {captionString}
      <span className="caption-length">({captionString.length} characters)</span>
    </figcaption>
  );
}

// Search and filtering based on caption content
function SearchableImageList({ searchTerm }: { searchTerm: string }) {
  const captionString = useImageCaptionString();
  
  const matchesSearch = captionString.toLowerCase().includes(
    searchTerm.toLowerCase()
  );
  
  if (!matchesSearch) return null;
  
  return (
    <div className="search-result">
      <Image.Img />
      <div className="caption-match">
        Caption: "{captionString}"
      </div>
    </div>
  );
}

Store Management System

Image Store

Atom store for managing image-specific state like width during resize operations.

/**
 * Atom store for image-specific state management
 * Manages width property for individual image elements
 */
const imageStore: {
  get: {
    width(): CSSProperties['width'];
  };
  set: {
    width(value: CSSProperties['width']): void;
  };
};

/**
 * Hook to access imageStore state
 * Provides reactive access to image store properties
 */
function useImageStore(): {
  get: {
    width(): CSSProperties['width'];
  };
  set: {
    width(value: CSSProperties['width']): void;
  };
  use: {
    width(): [CSSProperties['width'], (value: CSSProperties['width']) => void];
  };
};

Usage Examples:

import { useImageStore } from "@udecode/plate-image";

// Access current width in resize component
function ResizeDisplayComponent() {
  const imageStore = useImageStore();
  const [width, setWidth] = imageStore.use.width();
  
  return (
    <div>
      <div>Current width: {width}</div>
      <button onClick={() => setWidth(300)}>
        Set width to 300px
      </button>
    </div>
  );
}

// Monitor width changes during resize
function ResizeMonitor() {
  const imageStore = useImageStore();
  const width = imageStore.get.width();
  
  React.useEffect(() => {
    console.log('Image width changed:', width);
  }, [width]);
  
  return <div>Width: {width}</div>;
}

Global Image Store

Global store for managing cross-image state like caption focus coordination.

/**
 * Global store for cross-image state management
 * Coordinates focus states across different image elements
 */
const imageGlobalStore: {
  get: {
    focusEndCaptionPath(): TPath | null;
    focusStartCaptionPath(): TPath | null;
  };
  set: {
    focusEndCaptionPath(path: TPath | null): void;
    focusStartCaptionPath(path: TPath | null): void;
  };
  use: {
    focusEndCaptionPath(): TPath | null;
    focusStartCaptionPath(): TPath | null;
  };
};

Focus Management:

  • focusEndCaptionPath: Triggers focus to end of caption textarea for specified image path
  • focusStartCaptionPath: Triggers focus to start of caption textarea for specified image path
  • Paths are automatically cleared after focusing to prevent repeated focus events

Usage Examples:

import { imageGlobalStore } from "@udecode/plate-image";
import { findNodePath } from "@udecode/plate-core";

// Programmatically focus image caption
function FocusImageCaption() {
  const element = useImageElement();
  const editor = useEditorRef();
  
  const focusCaption = () => {
    const path = findNodePath(editor, element);
    if (path) {
      imageGlobalStore.set.focusEndCaptionPath(path);
    }
  };
  
  return (
    <button onClick={focusCaption}>
      Focus Image Caption
    </button>
  );
}

// Monitor focus state changes
function FocusStateMonitor() {
  const focusPath = imageGlobalStore.use.focusEndCaptionPath();
  
  return (
    <div>
      {focusPath ? (
        <div>Caption focus requested for path: {focusPath.join('.')}</div>
      ) : (
        <div>No caption focus pending</div>
      )}
    </div>
  );
}

Component Hook Integration Patterns

Custom Image Component with Hooks

import { 
  useImageElement, 
  useImageCaptionString, 
  useImageStore 
} from "@udecode/plate-image";

function CustomImageComponent() {
  // Access image data
  const element = useImageElement();
  const captionString = useImageCaptionString();
  const imageStore = useImageStore();
  
  // Local state for interaction
  const [isHovered, setIsHovered] = React.useState(false);
  const [width] = imageStore.use.width();
  
  return (
    <figure 
      className="custom-image"
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
    >
      <img
        src={element.url}
        alt={captionString}
        style={{ 
          width: width || element.width || '100%',
          opacity: isHovered ? 0.9 : 1,
          transition: 'opacity 0.2s'
        }}
      />
      
      {captionString && (
        <figcaption style={{ fontStyle: 'italic' }}>
          {captionString}
        </figcaption>
      )}
      
      {isHovered && (
        <div className="image-info">
          Dimensions: {width || element.width || 'auto'}
        </div>
      )}
    </figure>
  );
}

Hook Usage in Context

// Custom hook combining multiple image hooks
function useImageInfo() {
  const element = useImageElement();
  const captionString = useImageCaptionString();
  const imageStore = useImageStore();
  
  return {
    url: element.url,
    width: element.width,
    hasCaption: captionString.length > 0,
    captionText: captionString,
    storeWidth: imageStore.get.width(),
    updateWidth: imageStore.set.width,
  };
}

// Usage of custom hook
function ImageInfoDisplay() {
  const info = useImageInfo();
  
  return (
    <div className="image-info">
      <div>URL: {info.url}</div>
      <div>Width: {info.width || 'auto'}</div>
      <div>Store Width: {info.storeWidth}</div>
      <div>Has Caption: {info.hasCaption ? 'Yes' : 'No'}</div>
      {info.hasCaption && (
        <div>Caption: "{info.captionText}"</div>
      )}
    </div>
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-udecode--plate-image

docs

editor-enhancements.md

hooks-state.md

index.md

plugin-configuration.md

react-components.md

transforms-utilities.md

types-interfaces.md

tile.json