Appearance
Working with Components APIs
Core API System
The Stripo Extensions SDK provides a hierarchical API system where each extension component (Block, Control, UIElement, etc.) has access to specific API methods through the this.api
property.
API Inheritance Hierarchy
javascript
BaseApi
├── BlockApi (extends BaseApi + BaseModifierApi)
├── ControlApi (extends BaseApi + BaseModifierApi)
├── UIElementApi (extends BaseApi)
├── ContextActionApi (extends BaseApi + BaseModifierApi)
├── BlockRendererApi (extends BaseApi)
├── SettingsPanelApi (extends BaseApi)
└── BlocksPanelApi (extends BaseApi)
Examples
General API Usage
Getting Editor Configuration
One of the most common tasks is configuring custom blocks based on the editor configuration. In this example, we will use the following editor configuration:
javascript
window.UIEditor.initEditor(
document.querySelector('#stripoEditorContainer'),
{
html: template.html,
css: template.css,
metadata: {
emailId: `email_1`,
username: 'Demo User'
},
...,
extensions: [
...
],
simpleBlockConfig: {
enabled: true,
item: 'IPhone 17'
}
}
);
//===========================================================
import {Block} from '@stripoinc/ui-editor-extensions';
export class SimpleBlock extends Block {
isEnabled() {
return this.api.getEditorConfig().simpleBlockConfig?.enabled || true;
}
getBlockCompositionType() {
return BlockCompositionType.STRUCTURE;
}
getTemplate() {
return `
<${BlockType.STRUCTURE}>
<${BlockType.CONTAINER}>
<${BlockType.BLOCK_TEXT}>
${this.api.getEditorConfig().simpleBlockConfig?.item || 'Unknown'}
</${BlockType.BLOCK_TEXT}>
</${BlockType.CONTAINER}>
</${BlockType.STRUCTURE}>
`
}
// Additional block configuration methods...
}
Translation and Internationalization
Use the translation API to support multiple languages:
javascript
// uk.js - Ukrainian translations
export default {
"Buy": "Купити",
"Set event-id {eventId}": "Встановлено event-id {eventId}"
}
//===============================================================
import uk from './uk';
import {Block, ModificationDescription} from '@stripoinc/ui-editor-extensions';
export class SimpleBlock extends Block {
getTemplate() {
return `
<td>
<a href="https://stripo.email/">
${this.api.translate('Buy')}
</a>
</td>
`
}
onCreated(node) {
const eventId = '1234-56';
this.api.getDocumentModifier()
.modifyHtml(node)
.setAttribute('event-id', eventId)
.apply(new ModificationDescription('Set event-id {eventId}').withParams({ eventId: eventId }));
}
// Additional block configuration methods...
}
export default new ExtensionBuilder()
.withLocalization({
'uk': uk,
})
.addBlock(SimpleBlock)
.build();
Custom Font Management
Dynamically add custom fonts to the editor:
javascript
import {Block} from '@stripoinc/ui-editor-extensions';
class SimpleBlock extends Block {
onCreated(node) {
// Add a Google Font
this.api.addCustomFont({
name: 'Roboto Slab',
fontFamily: 'Roboto Slab, serif',
url: 'https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;700'
});
}
// Additional block configuration methods...
}
Editor State Management
Monitor and respond to editor state changes:
javascript
import {Block, EditorStatePropertyType, PreviewDeviceMode} from '@stripoinc/ui-editor-extensions';
class SimpleBlock extends Block {
onCreated(node) {
// Get current editor state
const state = this.api.getEditorState();
console.log('Current device:', state.previewDeviceMode);
console.log('Panel position:', state.panelPosition);
// Subscribe to device mode changes
this.api.onEditorStatePropUpdated(
EditorStatePropertyType.previewDeviceMode,
(newMode, oldMode) => {
if (newMode === PreviewDeviceMode.MOBILE) {
console.log('Switching to mobile view');
} else {
console.log('Switching to desktop view');
}
}
);
}
// Additional block configuration methods...
}
Click Outside Behavior
Control how the editor handles clicks outside of blocks. This is particularly useful for custom toolbars and popup windows:
javascript
import {Block, EditorStatePropertyType, PreviewDeviceMode} from '@stripoinc/ui-editor-extensions';
class SimpleBlock extends Block {
onSelect(node) {
// Prevent deselection when clicking outside
this.api.ignoreClickOutside(true);
// Show custom toolbar
this.showCustomToolbar();
}
showCustomToolbar() {
const toolbar = this.createToolbar();
document.body.appendChild(toolbar);
// Re-enable normal behavior when done
toolbar.addEventListener('close', () => {
this.api.ignoreClickOutside(false);
toolbar.remove();
});
}
// Additional block configuration methods...
}
AI and Emoji Popovers
Open the default AI assistant and emoji picker popovers:
javascript
import {ExtensionPopoverType, PopoverSide, UIElement} from '@stripoinc/ui-editor-extensions';
class SimplePopoverUIElement extends UIElement {
getId() {
return 'popovers-example';
}
getTemplate() {
return `
<div>
<button class="emoji-button">Pick Emoji</button>
<button class="ai-button">Improve with AI</button>
</div>`
}
onRender(container) {
this.emojiButton = container.querySelector('.emoji-button');
this.aiButton = container.querySelector('.ai-button');
this.emojiButton.addEventListener('click', this.showEmojiPopover.bind(this));
this.aiButton.addEventListener('click', this.showAiPopover.bind(this));
}
showEmojiPopover() {
this.api.openEmojiPopover({
targetElement: this.emojiButton,
preferredSides: [PopoverSide.LEFT],
onResult: (result) => { console.log(result); }
})
}
showAiPopover() {
this.api.openAIPopover({
targetElement: this.aiButton,
value: 'Hello world',
preferredSides: [PopoverSide.LEFT],
type: ExtensionPopoverType.AI_TEXT,
onResult: (result) => { console.log(result); }
})
}
onDestroy() {
this.emojiButton.removeEventListener('click', this.showEmojiPopover.bind(this));
this.aiButton.removeEventListener('click', this.showAiPopover.bind(this));
}
}
Document Root Access
Access and traverse the document structure:
javascript
import {Block} from '@stripoinc/ui-editor-extensions';
class SimpleBlock extends Block {
onDocumentInit() {
const linksCount = this.api.getDocumentRootHtmlNode()
.querySelectorAll(`a`).length;
const h1FontFamily = this.api.getDocumentRootCssNode()
.querySelector('h1 {font-family}').getAttributeValue();
}
// Additional block configuration methods...
}
Modification API Usage
Use the Template Modification System to make template changes:
javascript
const modifier = this.api.getDocumentModifier();
Block API Usage
View-Only Mode
Control the block's state. In view-only mode, the block cannot be added to the template via drag and drop, but can still be edited using the editor's UI:
javascript
import {Block} from '@stripoinc/ui-editor-extensions';
class SimpleBlock extends Block {
onDocumentInit() {
const blocks = this.api.getDocumentRoot()
.querySelectorAll(`.${this.getUniqueBlockClassname()}`);
this.api.setViewOnly(!!blocks.length);
}
// Additional block configuration methods...
}
Control API Usage
Managing UI Element Values
Control and synchronize UI element values using the following methods:
this.api.getValues
- Retrieve current valuesthis.api.updateValues
- Update multiple values at oncethis.api.onValueChanged
- Listen for value changesthis.api.setVisibility
- Show/hide UI elementsthis.api.setUIEAttribute
- Set UI element attributes
javascript
import {Control, UEAttr, UIElementType} from '@stripoinc/ui-editor-extensions';
export class AdvancedControl extends Control {
getId() {
return 'advanced-control';
}
getTemplate() {
return `
<div class="container two-columns">
<${UIElementType.LABEL} ${UEAttr.LABEL.text}="Settings:"></${UIElementType.LABEL}>
<${UIElementType.SWITCHER} ${UEAttr.SWITCHER.name}="enableFeature"></${UIElementType.SWITCHER}>
</div>
<div>
<${UIElementType.COUNTER}
${UEAttr.COUNTER.name}="itemCount"
${UEAttr.COUNTER.minValue}="1"
${UEAttr.COUNTER.maxValue}="10"
${UEAttr.COUNTER.step}="1"></${UIElementType.COUNTER}>
<${UIElementType.SELECTPICKER} ${UEAttr.SELECTPICKER.name}="styleSelect" style="float: right">
<${UIElementType.SELECT_ITEM} ${UEAttr.SELECT_ITEM.value}="modern" ${UEAttr.SELECT_ITEM.text}="Modern"></${UIElementType.SELECT_ITEM}>
<${UIElementType.SELECT_ITEM} ${UEAttr.SELECT_ITEM.value}="classic" ${UEAttr.SELECT_ITEM.text}="Classic"></${UIElementType.SELECT_ITEM}>
</${UIElementType.SELECTPICKER}>
</div>`;
}
onRender() {
// Set initial values for all UI elements
this.api.updateValues({
'enableFeature': true,
'itemCount': 5,
'styleSelect': 'modern'
});
// Listen to individual value changes
this.api.onValueChanged('enableFeature', (enabled, wasEnabled) => {
// Show/hide related controls based on toggle
this.api.setVisibility('itemCount', enabled);
this.api.setVisibility('styleSelect', enabled);
if (enabled) {
this.getAllValues(); // Log current values
}
});
this.api.onValueChanged('styleSelect', (newValue, oldValue) => {
// Set counter max value based on selected style
const maxValue = newValue === 'modern' ? 10 : 20;
this.api.setUIEAttribute('itemCount', UEAttr.COUNTER.maxValue, maxValue);
});
}
getAllValues() {
// Get all current values at once
const values = this.api.getValues();
console.log('Current control state:', values);
return values;
}
}
UI Element API
The UI Element API provides methods for custom UI components.
Value Change Notification
Notify the editor when UI element values change:
javascript
import {UIElement} from '@stripoinc/ui-editor-extensions';
export class CustomSlider extends UIElement {
getId() {
return 'custom-slider';
}
getTemplate() {
return `
<div class="custom-slider-container">
<input type="range" class="slider" min="0" max="100" value="50">
<span class="value-display">50</span>
</div>
`;
}
onRender(container) {
this.slider = container.querySelector('.slider');
this.display = container.querySelector('.value-display');
this.slider.addEventListener('input', (event) => {
const value = parseInt(event.target.value);
this.display.textContent = value;
// Notify the editor of the value change
this.api.onValueChanged(value);
});
}
getValue() {
return parseInt(this.slider.value);
}
setValue(value) {
this.slider.value = value;
this.display.textContent = value;
}
}