@useinsider/guido
v3.0.0-beta.a72fd61
Published
Guido is a Vue + TypeScript wrapper for Email Plugin. Easily embed the email editor in your Vue applications.
Downloads
20,906
Readme
@useinsider/guido
Guido is a Vue 2 + TypeScript wrapper for the Stripo Email Editor plugin. Easily embed the professional email editor in your Vue applications with a clean, type-safe configuration.
Installation
npm install @useinsider/guidoPrerequisites
Your project needs:
- Vue 2.7+
- Pinia (state management)
Add these to your bundler config to optimize dependencies:
Webpack (webpack.config.js or vue.config.js):
shared: {
vue: { singleton: true },
pinia: { singleton: true },
},Vite (vite.config.js):
resolve: {
dedupe: ['vue', 'pinia'],
},Quick Start
<template>
<Guido
ref="guidoRef"
:config="config"
@ready="onReady"
@dynamic-content:open="onDynamicContentOpen"
@save:complete="onSaveComplete"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Guido } from '@useinsider/guido';
import type { GuidoConfigInput } from '@useinsider/guido';
const guidoRef = ref<InstanceType<typeof Guido> | null>(null);
const config = ref<GuidoConfigInput>({
identity: {
templateId: 'template-123',
userId: 'user-456',
},
partner: {
name: 'your-partner-name',
},
template: {
html: '<p>Initial content</p>',
css: '',
},
});
const onReady = () => console.log('Editor ready');
const onDynamicContentOpen = () => console.log('Dynamic content requested');
const onSaveComplete = (template) => console.log('Saved:', template);
</script>Configuration
Guido uses a single, validated config prop organized by domain:
import type { GuidoConfigInput } from '@useinsider/guido';
const config: GuidoConfigInput = {
// Required: Identity
identity: {
templateId: string, // Required - Template identifier
userId: string, // Required - User identifier
variationId?: string, // Optional - A/B test variation
},
// Required: Partner
partner: {
name: string, // Required - Partner name
productType?: number, // Optional - Default: 60 (Email)
messageType?: number, // Optional - Default: 1 (Promotional)
username?: string, // Optional - Default: 'Guido User'
},
// Optional: Template content
template?: {
html?: string,
css?: string,
preselectedDynamicContent?: DynamicContent[],
selectedUnsubscribePages?: number[],
forceRecreate?: boolean, // Default: false - Force recreate template in Stripo storage
},
// Optional: Editor settings
editor?: {
locale?: string, // Default: 'en'
translationsPath?: string, // Default: 'window.trans.en'
migrationDate?: number, // Stripo migration timestamp
emailHeader?: {
senderName?: string,
subject?: string,
},
savedModulesFolderName?: string, // Default: 'savedModules' - folder name for user-saved modules
defaultModulesFolderName?: string, // Default: 'defaultModules' - folder name for default/prebuilt modules
},
// Optional: UI settings
ui?: {
showHeader?: boolean, // Default: true
backButtonLabel?: string,
},
// Optional: Feature toggles
features?: {
dynamicContent?: boolean, // Default: true
saveAsTemplate?: boolean, // Default: true
versionHistory?: boolean, // Default: true
testMessage?: boolean, // Default: true
displayConditions?: boolean, // Default: true
unsubscribe?: boolean, // Default: true
modulesDisabled?: boolean, // Default: false - Disable modules panel
},
// Optional: Callbacks
callbacks?: {
externalValidation?: (data: SavedTemplateDetails) => Promise<boolean>, // Return false to cancel save
},
// Optional: Block configuration
blocks?: {
excludeDefaults?: DefaultBlockType[],
includeCustoms?: CustomBlockType[],
},
// Optional: HTML compiler
compiler?: {
customRules?: CompilerRule[],
ignoreDefaultRules?: boolean, // Default: false
},
};Events
| Event | Payload | Description |
|-------|---------|-------------|
| ready | - | Editor is loaded and ready |
| dynamic-content:open | DynamicContent \| null | User wants to insert dynamic content |
| back | - | Back button clicked |
| save:start | - | Save process started |
| save:complete | SavedTemplateDetails | Save completed successfully (includes metadata) |
| on-change | - | Template was modified |
| test-email:click | - | Test email button clicked |
| onboarding-finished | - | Onboarding popup dismissed |
save:complete Payload
The save:complete event emits a SavedTemplateDetails object containing the compiled template data along with editor metadata:
interface SavedTemplateDetails {
dynamicContentList: DynamicContent[];
compiledHtml: string;
rawHtml: string;
css: string;
ampHtml: string;
ampErrors: string[];
modules: number[];
recommendation: {
campaignUrls: Record<string, string>;
configs: Record<string, string>;
};
unsubscribe: {
status: boolean;
config: number[];
};
metadata: Metadata;
}
interface Metadata {
emailId: string;
partnerName?: string;
productType?: number;
userId: string;
username?: string;
savedModulesFolderName?: string;
defaultModulesFolderName?: string;
}⚠️ Important: The
metadataobject in thesave:completepayload must be passed directly into yourtemplateConfig/stripoConfigobject while saving. This ensures the email-service receives the correct version of sync modules features
Exposed Methods
const guidoRef = ref<InstanceType<typeof Guido> | null>(null);
// Insert dynamic content
guidoRef.value?.dynamicContent.insert({
text: 'Display Name',
value: 'variable_name',
fallback: 'Default Value',
});
// Close dynamic content modal
guidoRef.value?.dynamicContent.close();
// Silent save (no UI feedback)
guidoRef.value?.saveSilent();Block Configuration
Default Blocks (can be excluded)
type DefaultBlockType =
| 'amp-accordion'
| 'amp-carousel'
| 'amp-form-controls'
| 'banner-block'
| 'button-block'
| 'html-block'
| 'image-block'
| 'menu-block'
| 'social-block'
| 'spacer-block'
| 'text-block'
| 'timer-block'
| 'video-block';Custom Blocks (opt-in)
type CustomBlockType =
| 'dynamic-content'
| 'checkbox-block'
| 'radio-button-block'
| 'recommendation-block'
| 'unsubscribe-block'
| 'coupon-block'
| 'items-block';Examples
// Exclude specific default blocks
const config: GuidoConfigInput = {
identity: { templateId: 'tpl-123', userId: 'user-456' },
partner: { name: 'partner' },
blocks: {
excludeDefaults: ['timer-block', 'video-block'],
},
};
// Include custom blocks
const config: GuidoConfigInput = {
identity: { templateId: 'tpl-123', userId: 'user-456' },
partner: { name: 'partner' },
blocks: {
includeCustoms: ['recommendation-block', 'coupon-block', 'dynamic-content'],
},
};Module Folder Configuration
Customize the Stripo module folder names for saved and default modules. These values are passed to Stripo metadata and the dynamic folder paths are constructed in the Stripo plugin panel configuration.
const config: GuidoConfigInput = {
identity: { templateId: 'tpl-123', userId: 'user-456' },
partner: { name: 'acme' },
editor: {
// Folder name for user-saved modules
savedModulesFolderName: 'savedModules',
// Folder name for default/prebuilt modules
defaultModulesFolderName: 'defaultModules',
},
};Default Values
| Config Option | Default Value |
|--------------|---------------|
| savedModulesFolderName | 'savedModules' |
| defaultModulesFolderName | 'defaultModules' |
Note: The actual folder paths (e.g.,
guido_acme_savedModules) are configured in the Stripo plugin panel using variable substitution like${savedModulesFolderName}.
HTML Compiler Rules
Add custom rules to transform HTML during export:
const config: GuidoConfigInput = {
identity: { templateId: 'tpl-123', userId: 'user-456' },
partner: { name: 'partner' },
compiler: {
customRules: [
// Replace rule
{
id: 'replace-domain',
type: 'replace',
search: 'old-domain.com',
replacement: 'new-domain.com',
priority: 10,
},
// Regex rule
{
id: 'remove-comments',
type: 'regex',
pattern: '<!--.*?-->',
replacement: '',
flags: 'g',
priority: 20,
},
// Custom processor
{
id: 'add-tracking',
type: 'custom',
processor: (html) => html.replace('</body>', '<img src="track.gif"/></body>'),
priority: 30,
},
],
ignoreDefaultRules: false, // Set true to skip built-in rules
},
};TypeScript Exports
// Component
import { Guido } from '@useinsider/guido';
// Types
import type {
GuidoConfig,
GuidoConfigInput,
IdentityConfig,
PartnerConfig,
TemplateConfig,
EditorConfig,
UIConfig,
FeaturesConfig,
BlocksConfig,
CompilerConfig,
DynamicContent,
DefaultBlockType,
CustomBlockType,
} from '@useinsider/guido';
// Utilities
import {
validateConfig,
parseConfig,
MessageType,
ProductType,
} from '@useinsider/guido';
// Styles
import '@useinsider/guido/style';Constants
import { MessageType, ProductType } from '@useinsider/guido';
MessageType.PROMOTIONAL // 1
MessageType.TRANSACTIONAL // 2
ProductType.EMAIL // 60
ProductType.ARCHITECT // 49
ProductType.UNSUBSCRIBE_PAGES // 97Dynamic Content Modal
When the dynamic-content:open event fires, show your custom modal and call the insert method:
<template>
<Guido ref="guidoRef" :config="config" @dynamic-content:open="showModal = true" />
<!-- Your modal must have id="guido-dynamic-content-modal" -->
<YourModal v-if="showModal" id="guido-dynamic-content-modal" @select="insertContent" @close="closeModal" />
</template>
<script setup>
const showModal = ref(false);
const insertContent = (content) => {
guidoRef.value?.dynamicContent.insert({
text: content.label,
value: content.value,
fallback: content.fallback || '',
});
showModal.value = false;
};
const closeModal = () => {
guidoRef.value?.dynamicContent.close();
showModal.value = false;
};
</script>Development
# Install
bun install
# Start dev server
bun start
# Build
bun run build
# Lint & type-check
bun run lintEnvironment Variables
VITE_STRIPO_PLUGIN_ID=your_plugin_id
VITE_STRIPO_SECRET_KEY=your_secret_key
VITE_STRIPO_ROLE=your_roleLocal Testing
# Build the package
bun run build
# Create tarball
npm pack
# Install in your project
cd ../your-project
npm install ../guido/useinsider-guido-1.0.0.tgzLicense
ISC License
