From 3be94a9994abd92e61324334a819244881d6c723 Mon Sep 17 00:00:00 2001 From: danstarns Date: Wed, 21 Aug 2024 20:18:04 -0700 Subject: [PATCH] feat: make DataSources work with .loadProjectData --- src/dom_components/model/Component.ts | 10 +- src/domain_abstract/model/StyleableModel.ts | 13 ++ test/specs/data_sources/serialization.ts | 232 +++++++++++++++++--- 3 files changed, 229 insertions(+), 26 deletions(-) diff --git a/src/dom_components/model/Component.ts b/src/dom_components/model/Component.ts index d97f67652..6bc1cb9ad 100644 --- a/src/dom_components/model/Component.ts +++ b/src/dom_components/model/Component.ts @@ -51,6 +51,7 @@ import { updateSymbolComps, updateSymbolProps, } from './SymbolUtils'; +import TraitDataVariable from '../../data_sources/model/TraitDataVariable'; export interface IComponent extends ExtractMethods {} @@ -744,6 +745,14 @@ export default class Component extends StyleableModel { } } + const attrDataVariable = this.get('attributes-data-variable'); + if (attrDataVariable) { + Object.entries(attrDataVariable).forEach(([key, value]) => { + const dataVariable = value instanceof TraitDataVariable ? value : new TraitDataVariable(value, { em }); + attributes[key] = dataVariable.getDataValue(); + }); + } + // Check if we need an ID on the component if (!has(attributes, 'id')) { let addId = false; @@ -895,7 +904,6 @@ export default class Component extends StyleableModel { } }); traits.length && this.set('attributes', attrs); - // store the trait data-variable attributes outside the attributes object so you can load a project with data-variable attributes Object.keys(traitDataVariableAttr).length && this.set('attributes-data-variable', traitDataVariableAttr); this.on(event, this.initTraits); changed && em && em.trigger('component:toggled'); diff --git a/src/domain_abstract/model/StyleableModel.ts b/src/domain_abstract/model/StyleableModel.ts index 526058915..be07f5841 100644 --- a/src/domain_abstract/model/StyleableModel.ts +++ b/src/domain_abstract/model/StyleableModel.ts @@ -171,6 +171,19 @@ export default class StyleableModel extends Model keys(resolvedStyle).forEach((key) => { const styleValue = resolvedStyle[key]; + if (typeof styleValue === 'string' || Array.isArray(styleValue)) { + return; + } + + if ( + typeof styleValue === 'object' && + styleValue.type === DataVariableType && + !(styleValue instanceof StyleDataVariable) + ) { + const dataVar = new StyleDataVariable(styleValue, { em: this.em }); + resolvedStyle[key] = dataVar.getDataValue(); + } + if (styleValue instanceof StyleDataVariable) { const [dsId, drId, keyPath] = stringToPath(styleValue.get('path')); const ds = this.em?.DataSources.get(dsId); diff --git a/test/specs/data_sources/serialization.ts b/test/specs/data_sources/serialization.ts index 9f83e0f5a..7123977f3 100644 --- a/test/specs/data_sources/serialization.ts +++ b/test/specs/data_sources/serialization.ts @@ -4,6 +4,7 @@ import { DataSourceProps } from '../../../src/data_sources/types'; import ComponentWrapper from '../../../src/dom_components/model/ComponentWrapper'; import { DataVariableType } from '../../../src/data_sources/model/DataVariable'; import EditorModel from '../../../src/editor/model/Editor'; +import { ProjectData } from '../../../src/storage_manager'; // Filter out the unique ids and selectors replaced with 'data-variable-id' // Makes the snapshot more stable @@ -43,13 +44,21 @@ describe('DataSource Serialization', () => { let dsm: DataSourceManager; let fixtures: HTMLElement; let cmpRoot: ComponentWrapper; - const datasource: DataSourceProps = { + const componentDataSource: DataSourceProps = { id: 'component-serialization', records: [ { id: 'id1', content: 'Hello World' }, { id: 'id2', color: 'red' }, ], }; + const styleDataSource: DataSourceProps = { + id: 'colors-data', + records: [{ id: 'id1', color: 'red' }], + }; + const traitDataSource: DataSourceProps = { + id: 'test-input', + records: [{ id: 'id1', value: 'test-value' }], + }; beforeEach(() => { editor = new Editor({ @@ -70,7 +79,10 @@ describe('DataSource Serialization', () => { wrapperEl.render(); fixtures = document.body.querySelector('#fixtures')!; fixtures.appendChild(wrapperEl.el); - dsm.add(datasource); + + dsm.add(componentDataSource); + dsm.add(styleDataSource); + dsm.add(traitDataSource); }); afterEach(() => { @@ -85,7 +97,7 @@ describe('DataSource Serialization', () => { { type: DataVariableType, value: 'default', - path: `${datasource.id}.id1.content`, + path: `${componentDataSource.id}.id1.content`, }, ], })[0]; @@ -97,18 +109,12 @@ describe('DataSource Serialization', () => { expect(html).toMatchInlineSnapshot('"

Hello World

"'); }); - // DataSources TODO - test.todo('component .getCss'); - - // DataSources TODO - test.todo('component .getJs'); - describe('.getProjectData', () => { test('ComponentDataVariable', () => { const dataVariable = { type: DataVariableType, value: 'default', - path: `${datasource.id}.id1.content`, + path: `${componentDataSource.id}.id1.content`, }; cmpRoot.append({ @@ -128,12 +134,6 @@ describe('DataSource Serialization', () => { }); test('StyleDataVariable', () => { - const styleDataSource: DataSourceProps = { - id: 'colors-data', - records: [{ id: 'id1', color: 'red' }], - }; - dsm.add(styleDataSource); - const dataVariable = { type: DataVariableType, value: 'black', @@ -166,17 +166,10 @@ describe('DataSource Serialization', () => { }); test('TraitDataVariable', () => { - const record = { id: 'id1', value: 'test-value' }; - const inputDataSource: DataSourceProps = { - id: 'test-input', - records: [record], - }; - dsm.add(inputDataSource); - const dataVariable = { type: DataVariableType, value: 'default', - path: `${inputDataSource.id}.id1.value`, + path: `${traitDataSource.id}.id1.value`, }; cmpRoot.append({ @@ -201,11 +194,200 @@ describe('DataSource Serialization', () => { value: dataVariable, }); expect(component.attributes).toEqual({ - value: record.value, + value: 'test-value', }); const snapshot = filterObjectForSnapshot(projectData); expect(snapshot).toMatchSnapshot(``); }); }); + + describe('.loadProjectData', () => { + test('ComponentDataVariable', () => { + const componentProjectData: ProjectData = { + assets: [], + pages: [ + { + frames: [ + { + component: { + components: [ + { + components: [ + { + path: 'component-serialization.id1.content', + type: 'data-variable', + value: 'default', + }, + ], + tagName: 'h1', + type: 'text', + }, + ], + docEl: { + tagName: 'html', + }, + head: { + type: 'head', + }, + stylable: [ + 'background', + 'background-color', + 'background-image', + 'background-repeat', + 'background-attachment', + 'background-position', + 'background-size', + ], + type: 'wrapper', + }, + id: 'data-variable-id', + }, + ], + id: 'data-variable-id', + type: 'main', + }, + ], + styles: [], + symbols: [], + }; + + editor.loadProjectData(componentProjectData); + const components = editor.getComponents(); + + const component = components.models[0]; + const html = component.toHTML(); + expect(html).toContain('Hello World'); + }); + + test('StyleDataVariable', () => { + const componentProjectData: ProjectData = { + assets: [], + pages: [ + { + frames: [ + { + component: { + components: [ + { + attributes: { + id: 'selectorid', + }, + content: 'Hello World', + tagName: 'h1', + type: 'text', + }, + ], + docEl: { + tagName: 'html', + }, + head: { + type: 'head', + }, + stylable: [ + 'background', + 'background-color', + 'background-image', + 'background-repeat', + 'background-attachment', + 'background-position', + 'background-size', + ], + type: 'wrapper', + }, + id: 'componentid', + }, + ], + id: 'frameid', + type: 'main', + }, + ], + styles: [ + { + selectors: ['#selectorid'], + style: { + color: { + path: 'colors-data.id1.color', + type: 'data-variable', + value: 'black', + }, + }, + }, + ], + symbols: [], + }; + + editor.loadProjectData(componentProjectData); + + const components = editor.getComponents(); + const component = components.models[0]; + const style = component.getStyle(); + + expect(style).toEqual({ + color: 'red', + }); + }); + + test('TraitDataVariable', () => { + const componentProjectData: ProjectData = { + assets: [], + pages: [ + { + frames: [ + { + component: { + components: [ + { + attributes: { + value: 'default', + }, + 'attributes-data-variable': { + value: { + path: 'test-input.id1.value', + type: 'data-variable', + value: 'default', + }, + }, + tagName: 'input', + void: true, + }, + ], + docEl: { + tagName: 'html', + }, + head: { + type: 'head', + }, + stylable: [ + 'background', + 'background-color', + 'background-image', + 'background-repeat', + 'background-attachment', + 'background-position', + 'background-size', + ], + type: 'wrapper', + }, + id: 'frameid', + }, + ], + id: 'pageid', + type: 'main', + }, + ], + styles: [], + symbols: [], + }; + + editor.loadProjectData(componentProjectData); + + const components = editor.getComponents(); + const component = components.models[0]; + const value = component.getAttributes(); + expect(value).toEqual({ + value: 'test-value', + }); + }); + }); });