Browse Source

Up style property to TS

ts-style-manager
Artur Arseniev 4 years ago
parent
commit
ba0278c746
  1. 203
      src/style_manager/model/Property.ts

203
src/style_manager/model/Property.js → src/style_manager/model/Property.ts

@ -1,7 +1,73 @@
import { isUndefined, isString, isArray, result, keys, each, includes } from 'underscore'; import { isUndefined, isString, isArray, result, keys, each, includes } from 'underscore';
import { Model } from '../../common'; import { Model } from '../../common';
import EditorModel from '../../editor/model/Editor';
import { capitalize, camelCase, hasWin } from '../../utils/mixins'; import { capitalize, camelCase, hasWin } from '../../utils/mixins';
/** @private */
export interface PropertyProps {
name?: string;
label?: string;
id?: string;
property: string;
type?: string;
defaults?: string;
default?: string;
info?: string;
value?: any;
icon?: string;
functionName?: string;
status?: string;
visible?: boolean;
fixedValues?: string[];
onChange?: (data: {
property: Property;
from: PartialPropertyProps;
to: PartialPropertyProps;
value: any;
opts: any;
}) => any;
/**
* If true, the property will be forced to be full width
*/
full?: boolean;
/**
* If true to the value will be added '!important'
*/
important?: boolean;
/**
* If true, will be hidden by default and will show up only for targets
* which require this property (via `stylable-require`)
* Use case:
* you can add all SVG CSS properties with toRequire as true
* and then require them on SVG Components
*/
toRequire?: boolean;
/**
* Specifies dependency on other properties of the selected object.
* Property is shown only when all conditions are matched.
*
* example: { display: ['flex', 'block'], position: ['absolute'] };
* in this case the property is only shown when display is
* of value 'flex' or 'block' AND position is 'absolute'
*/
requires?: Record<string, any>;
/**
* Specifies dependency on properties of the parent of the selected object.
* Property is shown only when all conditions are matched.
*/
requiresParent?: any;
parentTarget?: any;
__p?: any;
}
type PartialPropertyProps = Partial<PropertyProps>;
/** /**
* @typedef Property * @typedef Property
* @property {String} id Property id, eg. `my-property-id`. * @property {String} id Property id, eg. `my-property-id`.
@ -17,8 +83,32 @@ import { capitalize, camelCase, hasWin } from '../../utils/mixins';
* ``` * ```
* *
*/ */
export default class Property extends Model { export default class Property extends Model<PropertyProps> {
initialize(props = {}, opts = {}) { em!: EditorModel;
defaults() {
return {
name: '',
property: '',
type: '',
defaults: '',
info: '',
value: '',
icon: '',
functionName: '',
status: '',
visible: true,
fixedValues: ['initial', 'inherit'],
full: false,
important: false,
toRequire: false,
requires: undefined,
requiresParent: null,
parentTarget: null,
};
}
initialize(props = {}, opts: any = {}) {
this.em = opts.em; this.em = opts.em;
const id = this.get('id') || ''; const id = this.get('id') || '';
const name = this.get('name') || this.get('label') || ''; const name = this.get('name') || this.get('label') || '';
@ -27,14 +117,16 @@ export default class Property extends Model {
!this.get('id') && this.set('id', prop); !this.get('id') && this.set('id', prop);
!name && this.set('name', capitalize(prop).replace(/-/g, ' ')); !name && this.set('name', capitalize(prop).replace(/-/g, ' '));
this.on('change', this.__upTargets); this.on('change', this.__upTargets);
// @ts-ignore
Property.callInit(this, props, opts); Property.callInit(this, props, opts);
} }
__getParentProp() { __getParentProp() {
// @ts-ignore
return this.collection?.opts?.parentProp; return this.collection?.opts?.parentProp;
} }
__upTargets(p, opts = {}) { __upTargets(p: any, opts: any = {}) {
const { em } = this; const { em } = this;
const sm = em.get('StyleManager'); const sm = em.get('StyleManager');
const name = this.getName(); const name = this.getName();
@ -42,11 +134,11 @@ export default class Property extends Model {
const value = isClear ? '' : this.__getFullValue(opts); const value = isClear ? '' : this.__getFullValue(opts);
const parentProp = this.__getParentProp(); const parentProp = this.__getParentProp();
const to = this.changedAttributes(); const to = this.changedAttributes() as PartialPropertyProps;
const from = keys(to).reduce((a, i) => { const from = keys(to).reduce((a, i) => {
a[i] = this.previous(i); a[i] = this.previous(i as any);
return a; return a;
}, {}); }, {} as any);
const kProps = [...keys(this.__getClearProps()), '__p']; const kProps = [...keys(this.__getClearProps()), '__p'];
const toProps = keys(to); const toProps = keys(to);
@ -58,19 +150,19 @@ export default class Property extends Model {
applyStyle && this.__upTargetsStyle({ [name]: value }, opts); applyStyle && this.__upTargetsStyle({ [name]: value }, opts);
} }
__upTargetsStyle(style, opts) { __upTargetsStyle(style: Record<string, string>, opts: any) {
const sm = this.em?.get('StyleManager'); const sm = this.em?.get('StyleManager');
sm?.addStyleTargets({ ...style, __p: !!opts.avoidStore }, opts); sm?.addStyleTargets({ ...style, __p: !!opts.avoidStore }, opts);
} }
_up(props, opts = {}) { _up(props: PartialPropertyProps, opts: any = {}) {
if (opts.noTarget) opts.__up = true; if (opts.noTarget) opts.__up = true;
const { partial, ...rest } = opts; const { partial, ...rest } = opts;
props.__p = !!(rest.avoidStore || partial); props.__p = !!(rest.avoidStore || partial);
return this.set(props, { ...rest, avoidStore: props.__p }); return this.set(props, { ...rest, avoidStore: props.__p });
} }
up(props, opts = {}) { up(props: PartialPropertyProps, opts = {}) {
this.set(props, { ...opts, __up: true }); this.set(props, { ...opts, __up: true });
} }
@ -81,7 +173,7 @@ export default class Property extends Model {
* @returns {String} * @returns {String}
*/ */
getId() { getId() {
return this.get('id'); return this.get('id')!;
} }
/** /**
@ -91,7 +183,7 @@ export default class Property extends Model {
* @returns {String} * @returns {String}
*/ */
getType() { getType() {
return this.get('type'); return this.get('type')!;
} }
/** /**
@ -99,7 +191,7 @@ export default class Property extends Model {
* @returns {String} * @returns {String}
*/ */
getName() { getName() {
return this.get('property'); return this.get('property')!;
} }
/** /**
@ -108,7 +200,7 @@ export default class Property extends Model {
* @param {Boolean} [opts.locale=true] Use the locale string from i18n module * @param {Boolean} [opts.locale=true] Use the locale string from i18n module
* @returns {String} * @returns {String}
*/ */
getLabel(opts = {}) { getLabel(opts: { locale?: boolean } = {}) {
const { locale = true } = opts; const { locale = true } = opts;
const id = this.getId(); const id = this.getId();
const name = this.get('name') || this.get('label'); const name = this.get('name') || this.get('label');
@ -121,7 +213,7 @@ export default class Property extends Model {
* @param {Boolean} [opts.noDefault=false] Avoid returning the default value * @param {Boolean} [opts.noDefault=false] Avoid returning the default value
* @returns {String} * @returns {String}
*/ */
getValue(opts = {}) { getValue(opts: { noDefault?: boolean } = {}) {
const { noDefault } = opts; const { noDefault } = opts;
const val = this.get('value'); const val = this.get('value');
return !this.hasValue() && !noDefault ? this.getDefaultValue() : val; return !this.hasValue() && !noDefault ? this.getDefaultValue() : val;
@ -133,7 +225,7 @@ export default class Property extends Model {
* @param {Boolean} [opts.noParent=false] Ignore the value if it comes from the parent target. * @param {Boolean} [opts.noParent=false] Ignore the value if it comes from the parent target.
* @returns {Boolean} * @returns {Boolean}
*/ */
hasValue(opts = {}) { hasValue(opts: { noParent?: boolean } = {}) {
const { noParent } = opts; const { noParent } = opts;
const parentValue = noParent && this.getParentTarget(); const parentValue = noParent && this.getParentTarget();
const val = this.get('value'); const val = this.get('value');
@ -158,7 +250,7 @@ export default class Property extends Model {
* console.log(property.getStyle()); * console.log(property.getStyle());
* // { color: 'red' }; * // { color: 'red' };
*/ */
getStyle(opts = {}) { getStyle(opts: { camelCase?: boolean } = {}) {
const name = this.getName(); const name = this.getName();
const key = opts.camelCase ? camelCase(name) : name; const key = opts.camelCase ? camelCase(name) : name;
return { [key]: this.__getFullValue(opts) }; return { [key]: this.__getFullValue(opts) };
@ -181,7 +273,7 @@ export default class Property extends Model {
* @param {Boolean} [opts.partial=false] If `true` the update on targets won't be considered complete (not stored in UndoManager) * @param {Boolean} [opts.partial=false] If `true` the update on targets won't be considered complete (not stored in UndoManager)
* @param {Boolean} [opts.noTarget=false] If `true` the change won't be propagated to selected targets. * @param {Boolean} [opts.noTarget=false] If `true` the change won't be propagated to selected targets.
*/ */
upValue(value, opts = {}) { upValue(value: string, opts = {}) {
const parsed = value === null || value === '' ? this.__getClearProps() : this.__parseValue(value, opts); const parsed = value === null || value === '' ? this.__getClearProps() : this.__parseValue(value, opts);
return this._up(parsed, opts); return this._up(parsed, opts);
} }
@ -200,6 +292,7 @@ export default class Property extends Model {
* @param {Object} [opts={}] Options * @param {Object} [opts={}] Options
* @param {Boolean} [opts.noTarget=false] If `true` the change won't be propagated to selected targets. * @param {Boolean} [opts.noTarget=false] If `true` the change won't be propagated to selected targets.
*/ */
// @ts-ignore
clear(opts = {}) { clear(opts = {}) {
this._up(this.__getClearProps(), { ...opts, __clear: true }); this._up(this.__getClearProps(), { ...opts, __clear: true });
} }
@ -229,7 +322,7 @@ export default class Property extends Model {
return !!this.get('full'); return !!this.get('full');
} }
__parseValue(value, opts) { __parseValue(value: string, opts: any) {
return this.parseValue(value, opts); return this.parseValue(value, opts);
} }
@ -244,7 +337,7 @@ export default class Property extends Model {
* @param {Object} [opts={}] Options * @param {Object} [opts={}] Options
* @private * @private
*/ */
setValue(value, complete = 1, opts = {}) { setValue(value: string, complete = true, opts = {}) {
const parsed = this.parseValue(value); const parsed = this.parseValue(value);
const avoidStore = !complete; const avoidStore = !complete;
!avoidStore && this.set({ value: undefined }, { avoidStore, silent: true }); !avoidStore && this.set({ value: undefined }, { avoidStore, silent: true });
@ -261,7 +354,7 @@ export default class Property extends Model {
* @private * @private
* @deprecated * @deprecated
*/ */
setValueFromInput(value, complete, opts = {}) { setValueFromInput(value: string, complete: boolean, opts = {}) {
this.setValue(value, complete, { ...opts, fromInput: 1 }); this.setValue(value, complete, { ...opts, fromInput: 1 });
} }
@ -276,13 +369,13 @@ export default class Property extends Model {
* // -> { value: 10, unit: 'deg', functionName: 'translateX' } * // -> { value: 10, unit: 'deg', functionName: 'translateX' }
* *
*/ */
parseValue(value, opts = {}) { parseValue(value: string, opts: { complete?: boolean; numeric?: boolean } = {}) {
const result = { value }; const result: PartialPropertyProps = { value };
const imp = '!important'; const imp = '!important';
if (isString(value) && value.indexOf(imp) !== -1) { if (isString(value) && value.indexOf(imp) !== -1) {
result.value = value.replace(imp, '').trim(); result.value = value.replace(imp, '').trim();
result.important = 1; result.important = true;
} }
if (!this.get('functionName') && !opts.complete) { if (!this.get('functionName') && !opts.complete) {
@ -302,10 +395,11 @@ export default class Property extends Model {
args.push(end); args.push(end);
} }
result.value = String.prototype.substring.apply(valueStr, args); result.value = String.prototype.substring.apply(valueStr, args as any);
if (opts.numeric) { if (opts.numeric) {
const num = parseFloat(result.value); const num = parseFloat(result.value);
// @ts-ignore
result.unit = result.value.replace(num, ''); result.unit = result.value.replace(num, '');
result.value = num; result.value = num;
} }
@ -350,7 +444,7 @@ export default class Property extends Model {
// return res.map(i => i.trim()); // return res.map(i => i.trim());
// } // }
__getFullValue({ withDefault } = {}) { __getFullValue({ withDefault }: any = {}) {
return !this.hasValue() && withDefault ? this.getDefaultValue() : this.getFullValue(); return !this.hasValue() && withDefault ? this.getDefaultValue() : this.getFullValue();
} }
@ -362,7 +456,7 @@ export default class Property extends Model {
* @return {string} * @return {string}
* @private * @private
*/ */
getFullValue(val, opts = {}) { getFullValue(val?: string, opts: any = {}) {
const fn = this.get('functionName'); const fn = this.get('functionName');
const def = this.getDefaultValue(); const def = this.getDefaultValue();
let value = isUndefined(val) ? this.get('value') : val; let value = isUndefined(val) ? this.get('value') : val;
@ -384,7 +478,7 @@ export default class Property extends Model {
return value || ''; return value || '';
} }
__setParentTarget(parentTarget) { __setParentTarget(parentTarget: any) {
this.up({ parentTarget }); this.up({ parentTarget });
} }
@ -402,7 +496,7 @@ export default class Property extends Model {
}; };
} }
__checkVisibility({ target, component, sectors }) { __checkVisibility({ target, component, sectors }: any) {
const trg = component || target; const trg = component || target;
if (!trg) return false; if (!trg) return false;
@ -434,8 +528,8 @@ export default class Property extends Model {
// Check if the property is available based on other property's values // Check if the property is available based on other property's values
if (sectors && requires) { if (sectors && requires) {
const properties = keys(requires); const properties = keys(requires);
sectors.forEach(sector => { sectors.forEach((sector: any) => {
sector.getProperties().forEach(model => { sector.getProperties().forEach((model: any) => {
if (includes(properties, model.id)) { if (includes(properties, model.id)) {
const values = requires[model.id]; const values = requires[model.id];
stylable = stylable && includes(values, model.get('value')); stylable = stylable && includes(values, model.get('value'));
@ -449,7 +543,7 @@ export default class Property extends Model {
const parent = component && component.parent(); const parent = component && component.parent();
const parentEl = parent && parent.getEl(); const parentEl = parent && parent.getEl();
if (parentEl) { if (parentEl) {
const styles = hasWin() ? window.getComputedStyle(parentEl) : {}; const styles: Record<string, any> = hasWin() ? window.getComputedStyle(parentEl) : {};
each(requiresParent, (values, property) => { each(requiresParent, (values, property) => {
stylable = stylable && styles[property] && includes(values, styles[property]); stylable = stylable && styles[property] && includes(values, styles[property]);
}); });
@ -462,6 +556,7 @@ export default class Property extends Model {
} }
} }
// @ts-ignore
Property.callParentInit = function (property, ctx, props, opts = {}) { Property.callParentInit = function (property, ctx, props, opts = {}) {
property.prototype.initialize.apply(ctx, [ property.prototype.initialize.apply(ctx, [
props, props,
@ -472,52 +567,12 @@ Property.callParentInit = function (property, ctx, props, opts = {}) {
]); ]);
}; };
Property.callInit = function (context, props, opts = {}) { // @ts-ignore
Property.callInit = function (context, props, opts: any = {}) {
!opts.skipInit && context.init(props, opts); !opts.skipInit && context.init(props, opts);
}; };
// @ts-ignore
Property.getDefaults = function () { Property.getDefaults = function () {
return result(this.prototype, 'defaults'); return result(this.prototype, 'defaults');
}; };
Property.prototype.defaults = {
name: '',
property: '',
type: '',
defaults: '',
info: '',
value: '',
icon: '',
functionName: '',
status: '',
visible: true,
fixedValues: ['initial', 'inherit'],
onChange: null,
// If true, the property will be forced to be full width
full: 0,
// If true to the value will be added '!important'
important: 0,
// If true, will be hidden by default and will show up only for targets
// which require this property (via `stylable-require`)
// Use case:
// you can add all SVG CSS properties with toRequire as true
// and then require them on SVG Components
toRequire: 0,
// Specifies dependency on other properties of the selected object.
// Property is shown only when all conditions are matched.
//
// example: { display: ['flex', 'block'], position: ['absolute'] };
// in this case the property is only shown when display is
// of value 'flex' or 'block' AND position is 'absolute'
requires: null,
// Specifies dependency on properties of the parent of the selected object.
// Property is shown only when all conditions are matched.
requiresParent: null,
parentTarget: null,
};
Loading…
Cancel
Save