Skip to content
This plugin is new and currently in beta. For the stable version, please use the previous version of the plugin.

Stripo Extensions SDK Change Log

v3.2.0

Overview

Version 3.2.0 is a minor release of the Stripo Extensions SDK that introduces support for a custom image library tab and enhanced image metadata capabilities. This release maintains full backward compatibility with v3.1.0.

Release Date: 09 November 2025
Release Type: Minor Release
Version: 3.2.0
Previous Version: 3.1.0

Editor Compatibility

The npm package version 3.2.0 is fully compatible with the Stripo Editor starting from version 2.43.0 and higher.


What's New

New: ExternalImageLibraryTab Class

A new class has been introduced to enable developers to create a custom tab within the build-in Stripo image library. This allows you to organize images from different sources into a separate tab for better user experience.

typescript
import { ExternalImageLibraryTab, ExternalGalleryImageSelectCallback } from '@stripoinc/ui-editor-extensions';

class MyCustomImageTab extends ExternalImageLibraryTab {
  /**
   * Returns the translated name/label for the tab
   */
  getName(): string {
    return 'My Images';
  }

  /**
   * Opens the custom tab and renders your image library UI
   * @param container - DOM element where you should render your UI
   * @param onImageSelectCallback - Callback to invoke when user selects an image
   */
  openImageLibraryTab(
    container: HTMLElement, 
    onImageSelectCallback: ExternalGalleryImageSelectCallback
  ): void {
    // Render your custom image library UI in the container
    container.innerHTML = `
      <div class="my-image-gallery">
        <!-- Your custom image gallery UI -->
      </div>
    `;
    
    // When user selects an image, call the callback
    // onImageSelectCallback(imageData);
  }
}

// Register in ExtensionBuilder
const extension = new ExtensionBuilder()
  .withExternalImageLibraryTab(MyCustomImageTab)
  .build();

Full Example Implementation: How to Integrate an External Image Library Tab


Enhanced: ExternalGalleryImage Interface

The ExternalGalleryImage interface now supports optional metadata labels for additional image information:

typescript
import { ExternalGalleryImage } from '@stripoinc/ui-editor-extensions';

// Old (v3.1.0)
const image: ExternalGalleryImage = {
  originalName: 'product.png',
  width: 800,
  height: 600,
  sizeBytes: 102400,
  url: 'https://example.com/product.png',
  altText: 'Product image'
};

// New (v3.2.0) - with optional labels
const image: ExternalGalleryImage = {
  originalName: 'product.png',
  width: 800,
  height: 600,
  sizeBytes: 102400,
  url: 'https://example.com/product.png',
  altText: 'Product image',
  labels: {                            // NEW: Optional metadata
    category: 'Products',
    photographer: 'John Doe',
    license: 'Commercial',
    tags: 'red, clothing, winter'
  }
};

Migration Guide

From v3.1.0 to v3.2.0

No Breaking Changes - Version 3.2.0 is fully backward compatible with v3.1.0. All existing code will continue to work without modifications.

v3.1.0

Overview

Version 3.1.0 is a minor release of the Stripo Extensions SDK that introduces new UI elements for creating orderable/sortable lists, enhanced control lifecycle hooks, and additional node query capabilities. This release maintains full backward compatibility with v3.0.0.

Release Date: 03 November 2025
Release Type: Minor Release
Version: 3.1.0
Previous Version: 3.0.0

Editor Compatibility

The npm package version 3.1.0 is fully compatible with the Stripo Editor starting from version 2.42.0 and higher.


What's New

New: Orderable UI Element

A new UI element has been introduced to create orderable/sortable lists within your custom controls. These elements enable users to reorder items through drag-and-drop or positioning controls.

typescript
import { UIElementType } from '@stripoinc/ui-editor-extensions';

// Available orderable element types
UIElementType.ORDERABLE         // 'UE-ORDERABLE' - Container for orderable items
UIElementType.ORDERABLE_ITEM    // 'UE-ORDERABLE-ITEM' - Individual orderable item
UIElementType.ORDERABLE_ICON    // 'UE-ORDERABLE-ICON' - Icon for ordering controls

New: Control onDocumentChanged() Lifecycle Hook

Controls now have access to a new lifecycle hook that is called whenever any part of the document template changes.

typescript
import { Control, ImmutableHtmlNode } from '@stripoinc/ui-editor-extensions';

class MyControl extends Control {
  getId(): string { return 'my-control'; }
  getTemplate(): string { return '<div>...</div>'; }

  /**
   * NEW in v3.1.0
   * Called when any part of the document template has changed
   * @param node - The immutable HTML node representing current node instance
   */
  onDocumentChanged(node: ImmutableHtmlNode): void {
    // React to document-wide changes
    // This can be frequent; use cautiously for performance-sensitive operations
    const customValue = node.getAttribute('data-custom');
    if (customValue) {
      // Update control state based on document changes
    }
  }
}

Important Notes:

  • This hook can be called frequently during editing
  • Use cautiously for performance-sensitive operations
  • Receives the current node instance as a parameter
  • Useful for controls that need to react to global template changes

Difference from onTemplateNodeUpdated():

  • onTemplateNodeUpdated(): Called when the node associated with this control's context is updated
  • onDocumentChanged(): Called when any part of the document template changes

New: Node Module Identification

The BaseImmutableNode interface now includes a method to retrieve the closest module ID associated with a node.

typescript
import { ImmutableHtmlNode } from '@stripoinc/ui-editor-extensions';

// In your block or control
const moduleId = node.getClosestModuleId();
console.log('Closest module ID:', moduleId);

Use Cases:

  • Identifying which module a node belongs to
  • Module-specific operations and logic

Example Implementation:

The External Merge Tags Selector tutorial demonstrates practical usage of getClosestModuleId() for detecting module context and displaying contextual UI indicators.


Migration Guide

From v3.0.0 to v3.1.0

No Breaking Changes - Version 3.1.0 is fully backward compatible with v3.0.0. All existing code will continue to work without modifications.

v3.0.0

Overview

Version 3.0.0 is a major release of the Stripo Extensions SDK that introduces significant architectural improvements, enhanced TypeScript support, and new features for extending the Stripo email editor. This release includes breaking changes that require migration from v2.x.

Release Date: 20 October 2025
Release Type: Major Release
Version: 3.0.0
Previous Version: 2.0.2

Editor Compatibility

The npm package version 3.0.0 is fully compatible with the Stripo Editor starting from version 2.40.0 and higher.


What's New

Enhanced Package Distribution

The SDK now supports multiple module formats for better compatibility across different JavaScript environments:

  • ESM (ECMAScript Modules): Modern ES module format
  • CJS (CommonJS): Node.js compatible format
  • Browser Bundle: Optimized browser-ready bundle
json
{
  "exports": {
    ".": {
      "types": "./dist/types/index.d.ts",
      "import": "./dist/esm/index.js",
      "require": "./dist/cjs/index.cjs",
      "default": "./dist/esm/index.js"
    },
    "./browser": {
      "browser": "./dist/browser/index.js",
      "default": "./dist/browser/index.js"
    }
  }
}

Migration: No code changes required. The package will automatically use the appropriate format for your environment.


New: Icons Registry

A new IconsRegistry class enables registration of custom SVG icons for use throughout your extensions.

typescript
import { IconsRegistry } from '@stripoinc/ui-editor-extensions';

class MyIconsRegistry extends IconsRegistry {
  registerIconsSvg(iconsMap: Record<string, string>): void {
    iconsMap['custom-icon'] = '<svg>...</svg>';
    iconsMap['another-icon'] = '<svg>...</svg>';
  }
}

// Register in ExtensionBuilder
const extension = new ExtensionBuilder()
  .setIconsRegistry(MyIconsRegistry)
  .build();

Benefits:

  • Centralized icon management
  • SVG support for crisp, scalable icons
  • Easy to share icons across multiple components

New: Control Visibility Management

Controls can now be dynamically shown or hidden based on the selected node's state.

typescript
import { Control } from '@stripoinc/ui-editor-extensions';

class MyControl extends Control {
  // New method - implement to control visibility
  isVisible(node: ImmutableHtmlNode): boolean {
    // Show control only for specific block types
    return node.hasClass('my-custom-block');
  }

  getId(): string { return 'my-control'; }
  getTemplate(): string { return '<div>...</div>'; }
}

Use Cases:

  • Show controls only for specific block types
  • Hide controls based on user permissions
  • Conditional UI based on template state

New: Additional Built-in Controls Available

Pre-built visibility controls are now available for major block types:

  • StructureVisibilityBuiltInControl
  • ContainerVisibilityBuiltInControl
  • ImageVisibilityBuiltInControl
  • ButtonVisibilityBuiltInControl
  • TextVisibilityBuiltInControl

New typography and styling controls for button blocks:

  • ButtonFontFamilyBuiltInControl - Font family selection for buttons
  • ButtonTextSizeBuiltInControl - Button text size control
  • ButtonTextStyleAndFontColorBuiltInControl - Combined text style and color control

New background and border controls:

  • ContainerBackgroundImageBuiltInControl - Set background images on containers
  • ContainerBorderBuiltInControl - Container border styling
  • StructureBackgroundImageBuiltInControl - Structure background images

New BlocksPanel Customization

Customize the modules tab icon in the blocks panel:

typescript
import { BlocksPanel } from '@stripoinc/ui-editor-extensions';

class MyBlocksPanel extends BlocksPanel {
  getModulesTabIconName(modulesTab: {
    key: string;
    label: Record<string, string>
  }): string | undefined {
    return 'custom-modules-icon'; // Use registered icon
  }
}

Breaking Changes

1. Class Architecture: Abstract Classes Replaced with Validated Classes

BREAKING CHANGE: All extension base classes have been refactored from TypeScript abstract classes to regular classes with runtime validation.

Affected Classes
  • Block
  • Control
  • UIElement
  • ContextAction
Old Implementation (v2.x)
typescript
import { Block } from '@stripoinc/ui-editor-extensions';

export class MyBlock extends Block {
  // TypeScript enforced abstract method implementation
  abstract getId(): string;
  abstract getTemplate(): string;
  abstract getIcon(): string;
  abstract getName(): string;
  abstract getDescription(): string;
}
New Implementation (v3.0)
typescript
import { Block } from '@stripoinc/ui-editor-extensions';

export class MyBlock extends Block {
  constructor() {
    super(); // Now calls BaseValidatedClass constructor
  }

  // Methods now throw errors if not implemented
  getId(): string { return 'my-block'; }
  getTemplate(): string { return '<div>...</div>'; }
  getIcon(): string { return 'icon.svg'; }
  getName(): string { return 'My Block'; }
  getDescription(): string { return 'Description'; }
}

Why This Change?

  • Improved runtime validation with clearer error messages
  • Better developer experience with validation logging

Migration Steps:

  1. If your class defines a constructor(), ensure you call super() inside it
  2. Ensure all required methods are implemented (validation will catch missing methods at runtime)
  3. Test your extension - you'll see helpful error messages if methods are missing

2. Block Lifecycle Hooks: Signature Changes

BREAKING CHANGE: Several Block lifecycle hooks have changed their signatures.

onDocumentInit() - Return Type Removed

Old (v2.x):

typescript
onDocumentInit(): HtmlNodeModifier | undefined {
  const modifier = this.api.getDocumentModifier();
  // Make modifications
  return modifier;
}

New (v3.0):

typescript
onDocumentInit(): void {
  const modifier = this.api.getDocumentModifier();
  // Make modifications and apply them
  modifier.apply(new ModificationDescription(`Some modifications applied`))
  // No return value needed
}

Migration: Remove the return statement and apply migrations with the appropriate description manually.


onSelect() - Return Type Removed

Old (v2.x):

typescript
onSelect(node: ImmutableHtmlNode): HtmlNodeModifier | undefined {
  const modifier = this.api.getDocumentModifier();
  // Make modifications
  return modifier;
}

New (v3.0):

typescript
onSelect(node: ImmutableHtmlNode): void {
  const modifier = this.api.getDocumentModifier();
  // Make modifications and apply them
  modifier.apply(new ModificationDescription(`Some modifications applied`))
  // No return value needed
}

Migration: Remove the return statement and apply migrations with the appropriate description manually.


onCopy() - Parameters and Return Type Changed

Old (v2.x):

typescript
onCopy(
  targetNode: ImmutableHtmlNode,
  sourceNode: ImmutableHtmlNode
): HtmlNodeModifier | undefined {
  const modifier = this.api.getDocumentModifier();
  // Modify the copied node
  return modifier;
}

New (v3.0):

typescript
onCopy(modifier: HtmlNodeModifier): void {
  // Use the provided modifier directly
  // Modifier is already set up for the copy operation
  modifier.setAttribute('data-copied', 'true');
  // No return value
}

Migration:

  1. Change method signature to accept modifier: HtmlNodeModifier
  2. Use the provided modifier parameter directly
  3. Remove return statement
  4. Your modifications will now be applied directly within the copy operation.

onDelete() - Return Type Removed

Old (v2.x):

typescript
onDelete(node: ImmutableHtmlNode): HtmlNodeModifier | undefined {
  const modifier = this.api.getDocumentModifier();
  // Make modifications
  return modifier;
}

New (v3.0):

typescript
onDelete(node: ImmutableHtmlNode): void {
  const modifier = this.api.getDocumentModifier();
  // Make modifications and apply them
  modifier.apply(new ModificationDescription(`Some modifications applied`))
  // No return value needed
}

Migration: Remove the return statement and apply migrations with the appropriate description manually.


onDocumentChanged() - Now Receives Node Parameter

Old (v2.x):

typescript
onDocumentChanged(): void {
  // React to any document changes
  // No context about which node changed
}

New (v3.0):

typescript
onDocumentChanged(node: ImmutableHtmlNode): void {
  // React to document changes for this specific node
  // The node parameter indicates which extension instance triggered the event
  // For example, if you have multiple instances of a custom block (such as Coupon block), this hook will be called separately for each node, allowing you to distinguish between them (e.g., Coupon block 1 and Coupon block 2)
  if (node.getAttribute('data-custom') === 'value') {
    // Handle specific node changes
  }
}

Migration: Add the node: ImmutableHtmlNode parameter to your method signature.


3. Control Class: onTemplateNodeUpdated() Now Optional

BREAKING CHANGE: The onTemplateNodeUpdated() method is now optional with a default no-op implementation.

Old (v2.x):

typescript
import { Control } from '@stripoinc/ui-editor-extensions';

class MyControl extends Control {
  abstract onTemplateNodeUpdated(node: ImmutableHtmlNode): void;

  // HAD to implement this method
  onTemplateNodeUpdated(node: ImmutableHtmlNode): void {
    // Update UI based on node changes
  }
}

New (v3.0):

typescript
import { Control } from '@stripoinc/ui-editor-extensions';

class MyControl extends Control {
  // Now optional - only implement if needed
  onTemplateNodeUpdated(node: ImmutableHtmlNode): void {
    // Update UI based on node changes
  }

  // Or omit entirely if you don't need it
}

Migration: No changes required if you're already implementing this method. If you had empty implementations, you can remove them.


4. ContextAction: Method Renamed

BREAKING CHANGE: The getIconClass() method has been renamed to getIcon().

Old (v2.x):

typescript
import { ContextAction } from '@stripoinc/ui-editor-extensions';

class MyAction extends ContextAction {
  getIconClass(): string {
    return 'custom-icon';
  }
}

New (v3.0):

typescript
import { ContextAction } from '@stripoinc/ui-editor-extensions';

class MyAction extends ContextAction {
  getIcon(): string {
    return 'custom-icon'; // Icon name from IconsRegistry
  }
}

Migration:

  1. Rename getIconClass() to getIcon()

5. Built-in Control Renames

BREAKING CHANGE: Several built-in controls have been renamed for clarity and consistency.

Font Family Controls

Old (v2.x):

typescript
import {
  FontFamilyBuiltInControl,       // Text font control
  LinkColorBuiltInControl,        // Text Link color
  ButtonFontColorBuiltInControl,  // Button font color
  BackgroundImageBuiltInControl   // Generic background
} from '@stripoinc/ui-editor-extensions';

New (v3.0):

typescript
import {
  TextFontFamilyBuiltInControl,   // Renamed from FontFamilyBuiltInControl
  TextLinkColorBuiltInControl,    // Renamed from LinkColorBuiltInControl
  ButtonFontFamilyBuiltInControl, // New - button specific
  // BackgroundImageBuiltInControl - REMOVED, use specific controls below
  ContainerBackgroundImageBuiltInControl,  // Container specific
  StructureBackgroundImageBuiltInControl   // Structure specific
} from '@stripoinc/ui-editor-extensions';

Migration Table:

Old Name (v2.x)New Name (v3.0)Notes
FontFamilyBuiltInControlTextFontFamilyBuiltInControlRenamed for clarity
LinkColorBuiltInControlTextLinkColorBuiltInControlRenamed for clarity
ButtonFontColorBuiltInControlButtonTextStyleAndFontColorBuiltInControlEnhanced functionality
BackgroundImageBuiltInControlUse ContainerBackgroundImageBuiltInControl or StructureBackgroundImageBuiltInControlRemoved - use specific controls

Extension Class Changes

New: iconsRegistry Support

The Extension class now supports icon registry configuration.

Old (v2.x):

typescript
const extension = new ExtensionBuilder()
  .setI18n(translations)
  .setStyles(styles)
  .addBlock(MyBlock)
  .build();

New (v3.0):

typescript
const extension = new ExtensionBuilder()
  .setI18n(translations)
  .setStyles(styles)
  .setIconsRegistry(MyIconsRegistry)  // NEW
  .addBlock(MyBlock)
  .build();

The Extension class now has:

  • getIconsRegistry(): ConstructorOfType<IconsRegistry> | undefined - NEW method

Migration: No changes required unless you want to use the new IconsRegistry feature.