Skip to content

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...
}

Sending Custom Editor Events ​

Use sendEvent() to emit fire-and-forget events from blocks, controls, or UI elements:

javascript
class AnalyticsAwareBlock extends Block {
    onSelect(node) {
        this.api.sendEvent('extensions.analyticsAwareBlock.selected', {
            blockId: this.getId(),
            nodeId: node.getAttribute('id')
        });
    }
}

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 values
  • this.api.updateValues - Update multiple values at once
  • this.api.onValueChanged - Listen for value changes
  • this.api.setVisibility - Show/hide UI elements
  • this.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;
    }
}