You can install the Chamaileon SDK package from https://npmjs.com like this:
npm i @chamaileon-sdk/plugins
And use it like this
import chamaileonSdk from "@chamaileon-sdk/plugins";
Or like this
const chamaileonSdk = require("@chamaileon-sdk/plugins");
You can also import the Chamaileon SDK package from our CDN like this
<script type="module">
import chamaileonSdk from "https://cdn.chamaileon.io/sdk/##CURRENT_VERSION##/es/plugins.js";
</script>
You can find the newest version number here.
You can also use it in a script tag from our CDN like this
<script src="https://cdn.chamaileon.io/sdk/##CURRENT_VERSION##/umd/plugins.js"></script>
With this we add the library to the window object so you can access it like this:
window.chamaileonSdk({...})
You can find the newest version number here.
There are some differences in the configuration compared to the old SDK. The biggest one is that you have to call the chamaileonSdk() function directly instead of chamaileonSdk.init().
See the example below:
const accessTokenRequest = await fetch("https://sdk-api.chamaileon.io/api/v2/tokens/generate", {
method: "GET",
headers: {
"Authorization": `Bearer ${apiKey}`,
},
});
const accessTokenResponse = await accessTokenRequest.json();
const accessToken = accessTokenResponse.result
const chamaileonPlugins = await window.chamaileonSdk.init({
mode: "serverless",
accessToken: accessToken,
whitelabel: {
locale: "en",
urls: {
splashScreen: "https://chamaileon-sdk.github.io/splashscreen-and-logo-examples/splashScreen.html",
createLogoJS: "https://chamaileon-sdk.github.io/splashscreen-and-logo-examples/createLogo.js"
},
colors: {
primary: "#2D3291",
secondary: "#009f4a",
red: "#ff5546",
darkBlue: "#2d3291",
darkGreen: "#00af6e",
lightGreen: "#50d791",
weirdGreen: "#50d791",
pink: "#ff91a0",
yellow: "#ffd23c"
}
}
});
async function fetchAccessToken(){
const accessTokenRequest = await fetch("https://sdk-api.chamaileon.io/api/v2/tokens/generate", {
method: "GET",
headers: {
"Authorization": `Bearer ${apiKey}`,
},
});
if (!accessTokenRequest.ok) {
throw new Error("SDK token generation failed");
}
const accessTokenResponse = await accessTokenRequest.json();
return accessTokenResponse.result;
}
import createChamaileonPlugins as chamaileonSdk from "@chamaileon-sdk/plugins";
const accessToken = await fetchAccessToken();
const whitelabelConfig = {
locale: "en",
urls: {
splashScreen: "https://chamaileon-sdk.github.io/splashscreen-and-logo-examples/splashScreen.html",
createLogoJS: "https://chamaileon-sdk.github.io/splashscreen-and-logo-examples/createLogo.js"
},
colors: {
"primary": "#00C0E7",
"secondary": "#009f4a",
"red": "#ff5546",
"darkBlue": "#2d3291",
"darkGreen": "#00af6e",
"lightGreen": "#50d791",
"weirdGreen": "#50d791",
"pink": "#ff91a0",
"yellow": "#ffd23c"
},
};
const chamaileonPlugins = await chamaileonSdk({
...whitelabelConfig,
accessToken,
getAccessToken: fetchAccessToken,
});
serverless mode.The plugin-wrapper div now has a z-index of 2001 instead of 10.
The difference in the return object after a successful init is the following:
{
openGallery,
previewEmail,
editEmail,
createThumbnail,
editVariables,
}
{
createInlinePlugin,
createFullscreenPlugin,
destroy,
}
The createInlinePlugin and createFullscreenPlugin replaces the separated plugin load function. It also means that you have to create every plugin that you need with these and they won't be created automatically.
Until now, every plugin - except the thumbnail - was initialized as fullscreen. From now on, you can chose between inline and fullscreen plugins. The only exception is the thumbnail plugin because it can only be initialized as an inline plugin.
The destroy function was moved to the return value instead of being present as chamaileonSdk.destroy().
await chamaileonPlugins.previewEmail({
document: {},
settings: {},
hooks: {},
});
await chamaileonPlugins.createFullscreenPlugin({
plugin: "preview",
data: { document },
settings: {},
hooks: {},
});
await chamaileonPlugins.createThumbnail({
document: {},
container: "#email-thumbnail",
});
await chamaileonPlugins.createInlinePlugin(
{
plugin: "thumbnail",
data: { document },
settings: {
height: 640,
width: 480,
scale: 0.5
},
hooks: {},
},
{
container: document.getElementById("email-thumbnail"),
dimensions: {
width: 640,
height: 480,
scale: 0.5,
}
}
);
plugin type in a property instead of a custom function call.container prop got moved into the second object parameter in the call functioncontainer now accepts a HTMLElement as well as a selector| Old | New |
|---|---|
openGallery |
plugin: "gallery" |
previewEmail |
plugin: "preview" |
editEmail |
plugin: "editor" |
createThumbnail |
plugin: "thumbnail" |
editVariables |
plugin: "variable-editor" |
We modified the SDK so that most of the time you will only need one instance of every plugin. After you create an instance we will give you the option to modify the data and settings parameter of every plugin on the fly.
A plugin instance returns with the following:
{
close,
updateSettings,
setDocument,
...otherMethods
}
{
methods: {
updateSettings,
updateData,
...otherMethods
},
showSplashScreen,
hideSplashScreen,
show,
hide,
destroy,
};
{
destroy,
};
{
methods: {
updateSettings,
updateData,
...otherMethods
},
destroy,
};
setDocument was renamed to updateDataWith the show and hide functions you can avoid the old workflow of completely destroying and then re-initializing the same plugin over and over again. From now you can hide the plugin, update it's data and settings and then show it again. If you want you can even show the plugin and display the splash screen while you update the data in the plugin.
You should load every plugin you need after the SDK initialization. The best case scenario is to load it before your user wants to use it. You can then update the data object and the settings later when the user actually wants to interact with the plugin.
chamaileonPlugins.previewEmail({
document,
settings: {
...previewSettings
},
hooks: {
...previewHooks
},
})
const previewInstance = await chamaileonPlugins.createFullscreenPlugin({
plugin: "preview",
data: {},
settings: {},
hooks: {
...previewHooks
},
});
await previewInstance.methods.updateSettings({ ...previewSettings });
await previewInstance.methods.updateData({ document });
await chamaileonPlugins.previewEmail({
document: {},
settings: {},
hooks: {},
});
const previewInstance = await chamaileonPlugins.createFullscreenPlugin({
plugin: "preview",
data: { document },
settings: {},
hooks: {},
});
previewInstance.showSplashScreen(); // optional
await previewInstance.open();
previewInstance.hideSplashScreen(); // optional
The old SDK handled the close action and destroyed the plugin instance.
const previewInstance = await chamaileonPlugins.createFullscreenPlugin({
plugin: "preview",
data: { document },
settings: {},
hooks: {
close: () => {
return new Promise(resolve => {
previewInstance.hide();
resolve();
});
},
},
});
// The only exception for this is the variable editor plugin
// because you have to add your custom button for this and catch it
// on the `onButtonClicked` action
const variableEditorInstance = await chamaileonPlugins.createFullscreenPlugin({
plugin: "variable-editor",
data: { document },
settings: {},
hooks: {
onButtonClicked: ({ buttonId }) => {
return new Promise(resolve => {
if (buttonId === "close") {
variableEditorInstance.hide();
resolve();
}
reject();
});
},
},
});
code element config from settings.elements.content to settings.element.advanceduser top level property inside the settings propertydocument top level property inside the data propertygetDocument top level method inside editorInstance.methods objectgetEmailHtml top level method inside editorInstance.methods objectsetDocument method to updateData and moved it inside the editorInstance.methods objectgetEmailJson method, use the editorInstance.methods.getDocument method instead. The returned returnedObject.body will be the same as the deprecated method's result. We suggest that you save the whole returnObject from now on because it returns the fontFiles and variables as well.emailJson top level property, use the data.document.body property insteadtitle top level property, use the data.document.title property insteadautoSaveInterval top level property, use the settings.autoSaveInterval property insteadtextInsertPluginButtons top level property, use the settings.buttons.textInsert property insteadopenVariableModal function that was triggerable with the onClick config option on buttons. We have a default place for this button now.onDropdownButtonClicked hook, use the onHeaderButtonClicked hook insteademailJson parameter on onSave hook, use the returned document.body insteademailJson parameter on onAutoSave hook, use the returned document.body insteadonBeforeClose and onAfterClose hooks, use the close hook instead
close hookseditorConfig.hooks.onBeforeClose = () => { /* custom logic before the editor is closed */ };
editorConfig.hooks.onAfterClose = () => { /* custom logic after the editor is closed */ };
close hookeditorConfig.hooks.close = () => {
/* custom logic before the editor is "closed" */
await editorInstance.hide();
/* custom logic after the editor is "closed" */
};
canLockBlocks top level property, use the settings.addons.blockLock property instead
// Disabled
settings.addons.blockLock = {
enabled: false,
}
// Hidden
settings.addons.blockLock = false;
blockLibraries top level property, use the settings.blockLibraries property instead
accessLevel property and instead you can define the canDeleteBlock, canRenameBlock and canSaveBlock properties.blockLibraries config arrayblockLibraries: [
{
id: "email-blocks",
label: "Email's blocks",
accessLevel: "readOnly",
},
]
blockLibraries config arraysettings.blockLibraries: [
{
id: "email-blocks",
label: "Email's blocks",
canDeleteBlock: false,
canRenameBlock: false,
canSaveBlock: false,
},
]
dropdownButtons top level property, use the settings.buttons.header property instead
dropdownButtons content to it's itemsdropdownButtons config arraydropdownButtons: [
{
id: "test-button-1",
label: "Show preview",
icon: "short_text",
},
]
dropdownButtons config arraysettings.buttons.header = [
{
id: "dropdownButtons",
type: "dropdown",
icon: "dots-vertical",
style: "icon",
items: [
{
id: "test-button-1",
label: "Show preview",
icon: "short_text",
}
],
},
];
settings.buttons.header parameter
settings.button.header = [
{
id: "preview",
type: "button",
icon: "eye",
label: "Preview",
color: "primary",
style: "outlined",
},
{
id: "dropdownButtons",
type: "dropdown",
icon: "dots-vertical",
style: "icon",
items: [],
},
]
hooks.onHeaderButtonClicked hookconst previewInstance = await chamaileonPlugins.createFullscreenPlugin({
plugin: "preview",
data: {},
settings: {},
hooks: {},
});
const editorInstance = await chamaileonPlugins.createFullscreenPlugin({
plugin: "editor",
data: { document },
settings: {},
hooks: {
onHeaderButtonClicked: async ({ buttonId }) => {
if (buttonId === "preview") {
const currentJSON = await editorInstance.methods.getDocument();
await previewInstance.methods.updateData({ document: currentJSON });
previewInstance.show();
}
};
},
});
document top level property inside the data propertyhideHeader top level property, use the settings.hideHeader property insteadtitle top level property, use the data.document.title property insteadcontainer property from the first object property into the second. The property now accepts a HTMLElement as well as a selector.
await chamaileonPlugins.createThumbnail({
document: {},
container: "#email-thumbnail",
height: 640,
width: 480,
scale: 0.5,
scroll: true,
});
await chamaileonPlugins.createInlinePlugin(
{
plugin: "thumbnail",
data: { document },
settings: {
scroll: true,
},
hooks: {},
},
{
container: document.getElementById("email-thumbnail"),
dimensions: {
width: 640,
height: 480,
scale: 0.5,
}
}
);
DOMHeight hook to sendDOMHeightgetDocumentHeight hook into getDocumentHeight methodheight top level property inside the settings propertywidth top level property inside the settings propertyscale top level property inside the settings propertyscroll top level property inside the settings propertydocument top level property inside the data propertyeditImgSrc top level property inside the data as currentImgSrc propertydimensions top level property inside the data propertysettings.photoEditorLicece to settings.photoEditorLicensePromise that resolves with the selected image. Instead you have to call the pickImage method on the initialized instance instead.
const { src } = await chamaileonPlugins.openGallery({ editImgSrc, dimensions });
const galleryInstance = await chamaileonPlugins.createFullscreenPlugin({
plugin: "gallery",
data: {
currentImgSrc,
dimensions,
},
settings: {},
hooks: {},
});
const { src } = await galleryInstance.methods.pickImage();
setDocument to updateDatasettings.buttons.textInsertPlugin to settings.buttons.textInsert`document top level property inside the data propertyoutlined style and black colorvariableEditorConfig.settings.buttons.header = {
left: [
{
id: "close",
icon: "arrow-left"
},
],
right: [
{
id: "prev",
label: "Prev",
},
],
};
variableEditorConfig.settings.buttons.header = {
left: [
{
id: "close",
icon: "arrow-left",
color: "#000",
},
],
right: [
{
id: "prev",
label: "Prev",
style: "outlined,
color: "#000",
},
],
};
You can visit our Chamaileon SDK Playground to see the new interface in action.