grapesjs-clot
Version:
Free and Open Source Web Builder Framework
403 lines (381 loc) • 15.5 kB
JavaScript
import { isFunction, isString } from 'underscore';
const getOptions = items => items.map(item => ({ id: item }));
export default class PropertyFactory {
constructor() {
this.typeNumber = 'number';
this.typeColor = 'color';
this.typeRadio = 'radio';
this.typeSelect = 'select';
this.typeFile = 'file';
this.typeSlider = 'slider';
this.typeComposite = 'composite';
this.typeStack = 'stack';
this.unitsSize = ['px', '%', 'em', 'rem', 'vh', 'vw'];
this.unitsSizeNoPerc = ['px', 'em', 'rem', 'vh', 'vw'];
this.unitsTime = ['s', 'ms'];
this.unitsAngle = ['deg', 'rad', 'grad'];
this.fixedValues = ['initial', 'inherit', 'auto'];
const ss = ', sans-serif';
const optsFlex = ['flex-start', 'flex-end', 'center'];
const optsFlexAlign = [...optsFlex, 'baseline', 'stretch'];
this.optsBgSize = getOptions(['auto', 'cover', 'contain']);
this.optsBgAttach = getOptions(['scroll', 'fixed', 'local']);
this.optsBgRepeat = getOptions(['repeat', 'repeat-x', 'repeat-y', 'no-repeat']);
this.optsWrap = getOptions(['nowrap', 'wrap', 'wrap-reverse']);
this.optsOverflow = getOptions(['visible', 'hidden', 'scroll', 'auto']);
this.optsDir = getOptions(['row', 'row-reverse', 'column', 'column-reverse']);
this.opstDisplay = getOptions(['block', 'inline', 'inline-block', 'flex', 'none']);
this.optsTransitFn = getOptions(['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out']);
this.optsCursor = getOptions(['auto', 'pointer', 'copy', 'crosshair', 'grab', 'grabbing', 'help', 'move', 'text']);
this.optsFloat = getOptions(['none', 'left', 'right']);
this.optsPos = getOptions(['static', 'relative', 'absolute', 'fixed']);
this.optsTextAlign = getOptions(['left', 'center', 'right', 'justify']);
this.optsFlexAlign = getOptions(optsFlexAlign);
this.optsJustCont = getOptions([...optsFlex, 'space-between', 'space-around', 'space-evenly']);
this.optsAlignCont = getOptions([...optsFlex, 'space-between', 'space-around', 'stretch']);
this.optsAlignSelf = getOptions(['auto', ...optsFlexAlign]);
this.optsTransitProp = getOptions([
'all',
'width',
'height',
'background-color',
'transform',
'box-shadow',
'opacity',
]);
this.optsBorderStyle = getOptions([
'none',
'solid',
'dotted',
'dashed',
'double',
'groove',
'ridge',
'inset',
'outset',
]);
this.optsBgPos = getOptions([
'left top',
'left center',
'left bottom',
'right top',
'right center',
'right bottom',
'center top',
'center center',
'center bottom',
]);
this.optsWeight = [
{ id: '100', label: 'Thin' },
{ id: '200', label: 'Extra-Light' },
{ id: '300', label: 'Light' },
{ id: '400', label: 'Normal' },
{ id: '500', label: 'Medium' },
{ id: '600', label: 'Semi-Bold' },
{ id: '700', label: 'Bold' },
{ id: '800', label: 'Extra-Bold' },
{ id: '900', label: 'Ultra-Bold' },
];
this.optsShadowType = [
{ id: '', label: 'Outside' },
{ id: 'inset', label: 'Inside' },
];
this.optsFonts = [
'Arial, Helvetica' + ss,
'Arial Black, Gadget' + ss,
'Brush Script MT' + ss,
'Comic Sans MS, cursive' + ss,
'Courier New, Courier, monospace',
'Georgia, serif',
'Helvetica' + ss,
'Impact, Charcoal' + ss,
'Lucida Sans Unicode, Lucida Grande' + ss,
'Tahoma, Geneva' + ss,
'Times New Roman, Times, serif',
'Trebuchet MS, Helvetica' + ss,
'Verdana, Geneva' + ss,
].map(font => {
return { id: font, label: font.split(',')[0] };
});
// Fixed values
this.fixedFontSizes = [
'medium',
'xx-small',
'x-small',
'small',
'large',
'x-large',
'xx-large',
'smaller',
'larger',
'length',
'initial',
'inherit',
];
this.fixedLetSpace = ['normal', 'initial', 'inherit'];
this.requireFlex = { display: ['flex'] };
this.init();
}
__sub(items) {
return () =>
items.map(p => {
if (isString(p)) return this.get(p);
const { extend, ...rest } = p;
return {
...this.get(extend),
...rest,
};
});
}
init() {
const { fixedValues, requireFlex, typeNumber } = this;
this.props = {};
// Build default built-in properties (the order, in the array here below, matters)
// [propertyName, propertyDefinition, extendFromProperty]
[
// Number types
['text-shadow-h', { type: typeNumber, default: '0', units: this.unitsSizeNoPerc }],
['top', { default: 'auto', units: this.unitsSize, fixedValues }, 'text-shadow-h'],
['right', {}, 'top'],
['bottom', {}, 'top'],
['left', {}, 'top'],
['margin-top', { default: '0' }, 'top'],
['margin-right', {}, 'margin-top'],
['margin-bottom', {}, 'margin-top'],
['margin-left', {}, 'margin-top'],
['padding-top', { min: 0 }, 'margin-top'],
['padding-right', {}, 'padding-top'],
['padding-bottom', {}, 'padding-top'],
['padding-left', {}, 'padding-top'],
['width', { min: 0 }, 'top'],
['min-width', {}, 'width'],
['max-width', {}, 'width'],
['height', {}, 'width'],
['min-height', {}, 'width'],
['max-height', {}, 'width'],
['flex-basis', { requiresParent: requireFlex }, 'width'],
['font-size', { default: 'medium', fixedValues: this.fixedFontSizes }, 'width'],
['letter-spacing', { default: 'normal', fixedValues: this.fixedLetSpace }, 'top'],
['line-height', {}, 'letter-spacing'],
['text-shadow-v', {}, 'text-shadow-h'],
['text-shadow-blur', { min: 0 }, 'text-shadow-h'],
['border-radius-c', { property: 'border-radius', fixedValues: undefined }, 'padding-top'],
['border-top-left-radius', {}, 'border-radius-c'],
['border-top-right-radius', {}, 'border-radius-c'],
['border-bottom-left-radius', {}, 'border-radius-c'],
['border-bottom-right-radius', {}, 'border-radius-c'],
['border-width', { units: this.unitsSizeNoPerc }, 'border-radius-c'],
['box-shadow-h', {}, 'text-shadow-h'],
['box-shadow-v', {}, 'text-shadow-h'],
['box-shadow-blur', { default: '5px' }, 'text-shadow-blur'],
['box-shadow-spread', {}, 'text-shadow-h'],
['transition-duration', { default: '2s', units: this.unitsTime }, 'border-radius-c'],
['perspective', {}, 'border-radius-c'],
['transform-rotate-x', { functionName: 'rotateX', units: this.unitsAngle, default: '0', type: typeNumber }],
['transform-rotate-y', { functionName: 'rotateY' }, 'transform-rotate-x'],
['transform-rotate-z', { functionName: 'rotateZ' }, 'transform-rotate-x'],
['transform-scale-x', { default: '1', functionName: 'scaleX', units: undefined }, 'transform-rotate-x'],
['transform-scale-y', { functionName: 'scaleY' }, 'transform-scale-x'],
['transform-scale-z', { functionName: 'scaleZ' }, 'transform-scale-x'],
['order', { type: typeNumber, default: '0', requiresParent: requireFlex }],
['flex-grow', {}, 'order'],
['flex-shrink', { default: '1' }, 'order'],
// Radio types
['float', { type: this.typeRadio, default: 'none', options: this.optsFloat }],
['position', { default: 'static', options: this.optsPos }, 'float'],
['text-align', { default: 'left', options: this.optsTextAlign }, 'float'],
// Color types
['color', { type: this.typeColor, default: 'black' }],
['text-shadow-color', {}, 'color'],
['border-color', {}, 'color'],
['box-shadow-color', {}, 'color'],
['background-color', { default: 'none' }, 'color'],
// File type
['background-image', { type: this.typeFile, functionName: 'url', default: 'none', full: true }],
// Slider type
['opacity', { type: this.typeSlider, default: '1', min: 0, max: 1, step: 0.01 }],
// Select types
['display', { type: this.typeSelect, default: 'block', options: this.opstDisplay }],
['flex-direction', { default: 'row', options: this.optsDir, requires: requireFlex }, 'display'],
['flex-wrap', { default: 'nowrap', options: this.optsWrap }, 'flex-direction'],
['justify-content', { default: 'flex-start', options: this.optsJustCont }, 'flex-wrap'],
['align-items', { default: 'stretch', options: this.optsFlexAlign }, 'flex-wrap'],
['align-content', { options: this.optsAlignCont }, 'align-items'],
['align-self', { default: 'auto', options: this.optsAlignSelf, requiresParent: requireFlex }, 'display'],
['font-family', { default: 'Arial, Helvetica, sans-serif', options: this.optsFonts }, 'display'],
['font-weight', { default: '400', options: this.optsWeight }, 'display'],
['border-style', { default: 'solid', options: this.optsBorderStyle }, 'display'],
['box-shadow-type', { default: '', options: this.optsShadowType }, 'display'],
['background-repeat', { default: 'repeat', options: this.optsBgRepeat }, 'display'],
['background-position', { default: 'left top', options: this.optsBgPos }, 'display'],
['background-attachment', { default: 'scroll', options: this.optsBgAttach }, 'display'],
['background-size', { default: 'auto', options: this.optsBgSize }, 'display'],
['transition-property', { default: 'width', options: this.optsTransitProp }, 'display'],
['transition-timing-function', { default: 'ease', options: this.optsTransitFn }, 'display'],
['cursor', { default: 'auto', options: this.optsCursor }, 'display'],
['overflow', { default: 'visible', options: this.optsOverflow }, 'display'],
['overflow-x', {}, 'overflow'],
['overflow-y', {}, 'overflow'],
// Composite types
[
'margin',
{
type: this.typeComposite,
properties: this.__sub([
{ extend: 'margin-top', id: 'margin-top-sub' },
{ extend: 'margin-right', id: 'margin-right-sub' },
{ extend: 'margin-bottom', id: 'margin-bottom-sub' },
{ extend: 'margin-left', id: 'margin-left-sub' },
]),
},
],
[
'padding',
{
properties: this.__sub([
{ extend: 'padding-top', id: 'padding-top-sub' },
{ extend: 'padding-right', id: 'padding-right-sub' },
{ extend: 'padding-bottom', id: 'padding-bottom-sub' },
{ extend: 'padding-left', id: 'padding-left-sub' },
]),
},
'margin',
],
[
'border',
{
properties: this.__sub([
{ extend: 'border-width', id: 'border-width-sub' },
{ extend: 'border-style', id: 'border-style-sub' },
{ extend: 'border-color', id: 'border-color-sub' },
]),
},
'margin',
],
[
'border-radius',
{
properties: this.__sub([
{ extend: 'border-top-left-radius', id: 'border-top-left-radius-sub' },
{ extend: 'border-top-right-radius', id: 'border-top-right-radius-sub' },
{ extend: 'border-bottom-right-radius', id: 'border-bottom-right-radius-sub' },
{ extend: 'border-bottom-left-radius', id: 'border-bottom-left-radius-sub' },
]),
},
'margin',
],
[
'transform',
{
properties: this.__sub([
'transform-rotate-x',
'transform-rotate-y',
'transform-rotate-z',
'transform-scale-x',
'transform-scale-y',
'transform-scale-z',
]),
},
'margin',
],
// Stack types
[
'transition',
{
type: this.typeStack,
properties: this.__sub([
{ extend: 'transition-property', id: 'transition-property-sub' },
{ extend: 'transition-duration', id: 'transition-duration-sub' },
{ extend: 'transition-timing-function', id: 'transition-timing-function-sub' },
]),
},
],
[
'box-shadow',
{
preview: true,
layerLabel: (l, { values }) => {
const x = values['box-shadow-h'];
const y = values['box-shadow-v'];
const blur = values['box-shadow-blur'];
const spread = values['box-shadow-spread'];
return `${x} ${y} ${blur} ${spread}`;
},
properties: this.__sub([
'box-shadow-h',
'box-shadow-v',
'box-shadow-blur',
'box-shadow-spread',
'box-shadow-color',
'box-shadow-type',
]),
},
'transition',
],
[
'text-shadow',
{
default: 'none',
layerLabel: (l, { values }) => {
const x = values['text-shadow-h'];
const y = values['text-shadow-v'];
const blur = values['text-shadow-blur'];
return `${x} ${y} ${blur}`;
},
properties: this.__sub(['text-shadow-h', 'text-shadow-v', 'text-shadow-blur', 'text-shadow-color']),
},
'box-shadow',
],
[
'background',
{
detached: true,
layerLabel: (l, { values }) => {
const repeat = values['background-repeat-sub'];
const pos = values['background-position-sub'];
const att = values['background-attachment-sub'];
const size = values['background-size-sub'];
return `${repeat} ${pos} ${att} ${size}`;
},
properties: this.__sub([
{ extend: 'background-image', id: 'background-image-sub' },
{ extend: 'background-repeat', id: 'background-repeat-sub' },
{ extend: 'background-position', id: 'background-position-sub' },
{ extend: 'background-attachment', id: 'background-attachment-sub' },
{ extend: 'background-size', id: 'background-size-sub' },
]),
},
'box-shadow',
],
].forEach(([prop, def, from]) => {
this.add(prop, def || {}, { from });
});
return this;
}
add(property, def = {}, opts = {}) {
const from = opts.from || '';
const fromRes = this.props[from || property] || {};
const result = { ...fromRes, property, ...def };
if (result.properties && isFunction(result.properties)) {
result.properties = result.properties();
}
this.props[property] = result;
return result;
}
get(prop) {
return this.props[prop] || null;
}
/**
* Build props object by their name
* @param {Array<string>|string} props Array of properties name
* @return {Array<Object>}
*/
build(props) {
const result = [];
const propsArr = isString(props) ? [props] : props;
propsArr.forEach(prop => {
result.push(this.get(prop) || { property: prop });
});
return result;
}
}