Appearance
Stripo Extensions SDK Release Notes
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 buttonsButtonTextSizeBuiltInControl
- Button text size controlButtonTextStyleAndFontColorBuiltInControl
- Combined text style and color control
New background and border controls:
ContainerBackgroundImageBuiltInControl
- Set background images on containersContainerBorderBuiltInControl
- Container border stylingStructureBackgroundImageBuiltInControl
- 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:
- If your class defines a
constructor()
, ensure you callsuper()
inside it - Ensure all required methods are implemented (validation will catch missing methods at runtime)
- 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:
- Change method signature to accept
modifier: HtmlNodeModifier
- Use the provided modifier parameter directly
- Remove return statement
- 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:
- Rename
getIconClass()
togetIcon()
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 |
---|---|---|
FontFamilyBuiltInControl | TextFontFamilyBuiltInControl | Renamed for clarity |
LinkColorBuiltInControl | TextLinkColorBuiltInControl | Renamed for clarity |
ButtonFontColorBuiltInControl | ButtonTextStyleAndFontColorBuiltInControl | Enhanced functionality |
BackgroundImageBuiltInControl | Use ContainerBackgroundImageBuiltInControl or StructureBackgroundImageBuiltInControl | Removed - 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.