diff --git a/packages/core/src/css_composer/index.ts b/packages/core/src/css_composer/index.ts index d3783eeb9..f7106d6f1 100644 --- a/packages/core/src/css_composer/index.ts +++ b/packages/core/src/css_composer/index.ts @@ -111,8 +111,7 @@ export default class CssComposer extends ItemManagerModule { config: CssRuleProperties; em?: EditorModel; opt: any; + views: CssRuleView[] = []; + dataVariableListeners: Record = {}; defaults() { return { @@ -117,6 +121,7 @@ export default class CssRule extends StyleableModel { this.em = opt.em; this.ensureSelectors(null, null, {}); this.on('change', this.__onChange); + this.setStyle(this.get('style')); } __onChange(m: CssRule, opts: any) { diff --git a/packages/core/src/css_composer/view/CssRuleView.ts b/packages/core/src/css_composer/view/CssRuleView.ts index 6ec100a3f..16dd8e6c9 100644 --- a/packages/core/src/css_composer/view/CssRuleView.ts +++ b/packages/core/src/css_composer/view/CssRuleView.ts @@ -1,3 +1,4 @@ +import FrameView from '../../canvas/view/FrameView'; import { View } from '../../common'; import CssRule from '../model/CssRule'; @@ -11,9 +12,24 @@ export default class CssRuleView extends View { this.listenTo(model, 'change', this.render); this.listenTo(model, 'destroy remove', this.remove); this.listenTo(model.get('selectors'), 'change', this.render); + model.setView(this); } - // @ts-ignore + get frameView(): FrameView { + return this.config.frameView; + } + + remove() { + super.remove(); + this.model.removeView(this); + return this; + } + + updateStyles() { + this.render(); + } + + /** @ts-ignore */ tagName() { return 'style'; } diff --git a/packages/core/src/dom_components/view/ComponentView.ts b/packages/core/src/dom_components/view/ComponentView.ts index d4c8711e9..0b17c9560 100644 --- a/packages/core/src/dom_components/view/ComponentView.ts +++ b/packages/core/src/dom_components/view/ComponentView.ts @@ -304,6 +304,10 @@ TComp> { } } + updateStyles() { + this.updateStyle(); + } + /** * Update classe attribute * @private diff --git a/packages/core/src/domain_abstract/model/StyleableModel.ts b/packages/core/src/domain_abstract/model/StyleableModel.ts index 05d4579c3..02b4980f8 100644 --- a/packages/core/src/domain_abstract/model/StyleableModel.ts +++ b/packages/core/src/domain_abstract/model/StyleableModel.ts @@ -1,5 +1,5 @@ import { isArray, isString, keys } from 'underscore'; -import { Model, ObjectAny, ObjectHash, SetOptions } from '../../common'; +import { Model, ObjectAny, ObjectHash, SetOptions, View } from '../../common'; import ParserHtml from '../../parser/model/ParserHtml'; import Selectors from '../../selector_manager/model/Selectors'; import { shallowDiff } from '../../utils/mixins'; @@ -7,6 +7,9 @@ import EditorModel from '../../editor/model/Editor'; import StyleDataVariable from '../../data_sources/model/StyleDataVariable'; import { DataVariableType } from '../../data_sources/model/DataVariable'; import DataVariableListenerManager from '../../data_sources/model/DataVariableListenerManager'; +import CssRuleView from '../../css_composer/view/CssRuleView'; +import ComponentView from '../../dom_components/view/ComponentView'; +import Frame from '../../canvas/model/Frame'; export type StyleProps = Record< string, @@ -26,6 +29,8 @@ export type UpdateStyleOptions = SetOptions & { noEvent?: boolean; }; +export type StyleableView = ComponentView | CssRuleView; + const parserHtml = ParserHtml(); export const getLastStyleValue = (value: string | string[]) => { @@ -35,6 +40,12 @@ export const getLastStyleValue = (value: string | string[]) => { export default class StyleableModel extends Model { em?: EditorModel; dataVariableListeners: Record = {}; + views: StyleableView[] = []; + + constructor(attributes: T, options: { em?: EditorModel } = {}) { + super(attributes, options); + this.em = options.em; + } /** * Parse style string to an object @@ -153,6 +164,27 @@ export default class StyleableModel extends Model style[prop] = value; this.setStyle(style, { noEvent: true }); this.trigger(`change:style:${prop}`); + this.updateView(); + } + + getView(frame?: Frame) { + let { views, em } = this; + const frm = frame || em?.getCurrentFrameModel(); + return frm ? views.find((v) => v.frameView === frm.view) : views[0]; + } + + setView(view: StyleableView) { + let { views } = this; + !views.includes(view) && views.push(view); + } + + removeView(view: StyleableView) { + const { views } = this; + views.splice(views.indexOf(view), 1); + } + + updateView() { + this.views.forEach((view) => view.updateStyles()); } /** diff --git a/packages/core/test/specs/data_sources/model/StyleDataVariable.ts b/packages/core/test/specs/data_sources/model/StyleDataVariable.ts index 431b67a2b..514523e40 100644 --- a/packages/core/test/specs/data_sources/model/StyleDataVariable.ts +++ b/packages/core/test/specs/data_sources/model/StyleDataVariable.ts @@ -183,7 +183,9 @@ describe('StyleDataVariable', () => { content: 'Hello World', })[0]; - em.getEditor().CssComposer.addCollection([ + const cssComposer = em.getEditor().CssComposer; + + const [rule] = cssComposer.addCollection([ { selectors: [], selectorsAdd: selector, @@ -198,12 +200,19 @@ describe('StyleDataVariable', () => { }, ]); + cssComposer.render(); + const view = rule.getView(); + + expect(rule.getStyle()).toHaveProperty('color', 'red'); expect(em.getEditor().getCss()).toContain(`${selector}{color:red;}`); + expect(view?.el.innerHTML).toContain(`h1{color:red;}`); const ds = dsm.get(dsId); ds.getRecord(drId)?.set({ value: 'blue' }); + expect(rule.getStyle()).toHaveProperty('color', 'blue'); expect(em.getEditor().getCss()).toContain(`${selector}{color:blue;}`); + expect(view?.el.innerHTML).toContain(`h1{color:blue;}`); }); }); });