react-email-builder
Version:
A simple React drag and drop email builder.
241 lines (240 loc) • 7.06 kB
JavaScript
let counter = -1;
export function generateId() {
if (counter > 999999) {
counter = -1;
}
counter += 1;
return Date.now().toString(16) + '-' + counter.toString(16);
}
export function createBaseBlock(type) {
return {
id: generateId(),
type,
attrs: {},
style: {
padding: [10, 20, 10, 20]
}
};
}
export function createPlaceholder(attrs) {
const block = createBaseBlock('placeholder');
block.attrs = attrs || {};
return block;
}
export function createColumn() {
return {
id: generateId(),
attrs: {},
blocks: [createPlaceholder({ inColumn: true })]
};
}
export function createBlock(config, type) {
const block = config.blocks.find((b) => b.type === type);
const base = createBaseBlock(type);
if (block && block.createBlock) {
return block.createBlock(base, config);
}
return base;
}
export function copyBlock(block, config) {
const copy = config.blocks.find((b) => b.type === block.type)?.copyBlock;
return copy ? copy(block, config) : { ...block, id: generateId() };
}
export function namespace(module) {
const base = 'REB-' + module;
return (className) => {
return className ? base + '-' + className : base;
};
}
export function varsClass() {
return namespace('vars')();
}
export function getSelectedBlock(blocks, selectedId) {
if (selectedId) {
for (let i = 0; i < blocks.length; i += 1) {
const block = blocks[i];
if (block.id === selectedId) {
return {
block,
first: i === 0,
last: i === blocks.length - 1
};
}
if (block.type === 'columns') {
const { columns } = block
.attrs;
for (let j = 0; j < columns.length; j += 1) {
const column = columns[j];
const columnBlocks = column.blocks;
for (let k = 0; k < columnBlocks.length; k += 1) {
const columnBlock = columnBlocks[k];
if (columnBlock.id === selectedId) {
return {
columns: block,
column,
block: columnBlock,
first: k === 0,
last: k === columnBlocks.length - 1
};
}
}
}
}
}
}
return {};
}
const mCss = {};
export function getCss(module, factory) {
let css = mCss[module];
if (!css) {
css = factory(namespace(module));
mCss[module] = css;
}
return css;
}
export function getDefaultFonts() {
return [
{
value: 'Arial, helvetica, sans-serif',
label: 'Arial'
},
{
value: "'Arial black', helvetica, sans-serif",
label: 'Arial black'
},
{
value: "'Comic sans ms', cursive",
label: 'Comic sans ms'
},
{
value: "'Courier new', courier, monospace",
label: 'Courier new'
},
{
value: 'garamond, "times new roman", serif',
label: 'Garamond'
},
{
value: 'Georgia, serif',
label: 'Georgia'
},
{
value: 'Impact, Haettenschweiler',
label: 'Impact'
},
{
value: "'Lucida sans unicode', 'lucida grande', sans-serif",
label: 'Lucida sans unicode'
},
{
value: "Palatino, 'Palatino Linotype', 'Palatino LT STD', 'Book Antiqua', Georgia, serif",
label: 'Palatino'
},
{
value: 'Tahoma, geneva, sans-serif',
label: 'Tahoma'
},
{
value: "'Times new roman', times, serif",
label: 'Times new roman'
},
{
value: "'Trebuchet ms', helvetica, sans-serif",
label: 'Trebuchet ms'
},
{
value: 'Verdana, geneva, sans-serif',
label: 'Verdana'
}
];
}
export function isAbsoluteUrl(url) {
return /^[a-z][a-z0-9\-.+]*:/i.test(url) || url.startsWith('//');
}
export function normalizeUrl(url) {
if (!url) {
return '';
}
if (url.startsWith('//')) {
return 'https:' + url;
}
return isAbsoluteUrl(url) ? url : 'https://' + url;
}
export function serializeEmailBuilderState(config, state) {
const exportBlock = (block) => {
const blockConfig = config.blocks.find((b) => b.type === block.type);
const exportJSON = blockConfig?.exportJSON;
const serialized = {
...block,
attrs: exportJSON ? exportJSON(block.attrs) : block.attrs
};
if (serialized.type === 'columns') {
let attrs = serialized.attrs;
attrs = {
...attrs,
columns: attrs.columns.map((column) => ({
...column,
blocks: column.blocks.map(exportBlock)
}))
};
serialized.attrs = attrs;
}
return serialized;
};
return {
style: state.style,
blocks: state.blocks.map(exportBlock)
};
}
export function deserializeEmailBuilderState(config, serialized) {
const importBlock = (block) => {
const blockConfig = config.blocks.find((b) => b.type === block.type);
const importJSON = blockConfig?.importJSON;
const deserialized = {
...block,
attrs: importJSON ? importJSON(block.attrs) : block.attrs
};
deserialized.attrs = deserialized.attrs || {};
deserialized.style = deserialized.style || {};
if (deserialized.type === 'columns') {
let attrs = deserialized.attrs;
attrs = {
...attrs,
columns: attrs.columns.map((column) => ({
...column,
blocks: column.blocks.map(importBlock)
}))
};
deserialized.attrs = attrs;
}
return deserialized;
};
return {
style: serialized.style,
blocks: serialized.blocks.map(importBlock)
};
}
export function createEmailBuilderState(initialState) {
let state = {
style: {
padding: [32, 0, 32, 0],
bgColor: '#FFFFFF'
},
blocks: [createPlaceholder()]
};
if (typeof initialState === 'function') {
const createdState = initialState();
state = createdState || state;
}
else if (initialState) {
state = initialState;
}
if (!state.blocks.length) {
state = {
...state,
blocks: [createPlaceholder()]
};
}
return state;
}