diff --git a/packages/core/src/css_composer/index.ts b/packages/core/src/css_composer/index.ts index 99d18a831..89a486246 100644 --- a/packages/core/src/css_composer/index.ts +++ b/packages/core/src/css_composer/index.ts @@ -42,6 +42,7 @@ import { ObjectAny, PrevToNewIdMap } from '../common'; import { UpdateStyleOptions } from '../domain_abstract/model/StyleableModel'; import { CssEvents } from './types'; import CssRuleView from './view/CssRuleView'; +import type { DataBindingImportPolicy } from '../data_sources/types'; /** @private */ interface RuleOptions { @@ -73,6 +74,12 @@ export interface GetSetRuleOptions extends UpdateStyleOptions { type CssRuleStyle = Required['style']; +export interface AddCollectionOptions extends UpdateStyleOptions { + extend?: boolean | number; + avoidUpdateStyle?: boolean; + dataBindingImportPolicy?: DataBindingImportPolicy; +} + export default class CssComposer extends ItemManagerModule { classes = { CssRule, @@ -295,10 +302,10 @@ export default class CssComposer extends ItemManagerModule} * @private */ - addCollection(data: string | CssRuleJSON[], opts: Record = {}, props = {}) { + addCollection(data: string | CssRuleJSON[], opts: AddCollectionOptions = {}, props = {}) { const { em } = this; const result: CssRule[] = []; - const parsedImportOpts = { parsedImportSource: 'css', ...opts }; + const parsedImportOpts: AddCollectionOptions = { ...opts, parsedImportSource: 'css' as const }; if (isString(data)) { data = em.Parser.parseCss(data); diff --git a/packages/core/src/dom_components/model/Components.ts b/packages/core/src/dom_components/model/Components.ts index d76ac7ec0..9492f3265 100644 --- a/packages/core/src/dom_components/model/Components.ts +++ b/packages/core/src/dom_components/model/Components.ts @@ -17,6 +17,7 @@ import ComponentText from './ComponentText'; import ComponentWrapper from './ComponentWrapper'; import { ComponentsEvents, ParseStringOptions } from '../types'; import { isSymbolInstance, isSymbolRoot, updateSymbolComps } from './SymbolUtils'; +import type { DataBindingImportPolicy } from '../../data_sources/types'; export interface ResetCommonUpdateProps { component: Component; @@ -27,6 +28,7 @@ export interface ResetCommonUpdateProps { export interface ResetFromStringOptions { visitedCmps?: Record; keepIds?: string[]; + dataBindingImportPolicy?: DataBindingImportPolicy; updateOptions?: { onAttributes?: (props: ResetCommonUpdateProps & { attributes: Record }) => void; onStyle?: (props: ResetCommonUpdateProps & { style: Record }) => void; diff --git a/packages/core/src/dom_components/model/ModelResolverWatcher.ts b/packages/core/src/dom_components/model/ModelResolverWatcher.ts index bf16402ab..36ba59f84 100644 --- a/packages/core/src/dom_components/model/ModelResolverWatcher.ts +++ b/packages/core/src/dom_components/model/ModelResolverWatcher.ts @@ -15,6 +15,7 @@ export interface DataWatchersOptions { skipWatcherUpdates?: boolean; fromDataSource?: boolean; parsedImportSource?: DataBindingImportSource; + dataBindingImportPolicy?: DataBindingImportPolicy; } export interface ModelResolverWatcherOptions { @@ -125,7 +126,7 @@ export class ModelResolverWatcher { private applyImportPolicy(values: ObjectAny | undefined, options: DataWatchersOptions = {}) { const { parsedImportSource } = options; - const { dataBindingImportPolicy } = this.em.DataSources.config; + const dataBindingImportPolicy = options.dataBindingImportPolicy ?? this.em.DataSources.config.dataBindingImportPolicy; if (!values || !parsedImportSource || dataBindingImportPolicy === 'overwrite') return values; diff --git a/packages/core/src/dom_components/types.ts b/packages/core/src/dom_components/types.ts index 885426a2a..e9df3bc85 100644 --- a/packages/core/src/dom_components/types.ts +++ b/packages/core/src/dom_components/types.ts @@ -13,7 +13,7 @@ import type { ComponentResizeEventStartProps, ComponentResizeEventUpdateProps, } from '../commands/view/Resize'; -import type { DataBindingImportSource } from '../data_sources/types'; +import type { DataBindingImportPolicy, DataBindingImportSource } from '../data_sources/types'; import type { StyleProps } from '../domain_abstract/model/StyleableModel'; import type Selector from '../selector_manager/model/Selector'; import type Component from './model/Component'; @@ -41,6 +41,7 @@ export interface ParseStringOptions extends AddOptions, OptionAsDocument, WithHT keepIds?: string[]; cloneRules?: boolean; parsedImportSource?: DataBindingImportSource; + dataBindingImportPolicy?: DataBindingImportPolicy; } export enum ComponentsEvents { diff --git a/packages/core/test/specs/data_sources/dataBindingImportPolicy.ts b/packages/core/test/specs/data_sources/dataBindingImportPolicy.ts index 5d355132c..3683dfc45 100644 --- a/packages/core/test/specs/data_sources/dataBindingImportPolicy.ts +++ b/packages/core/test/specs/data_sources/dataBindingImportPolicy.ts @@ -115,8 +115,9 @@ describe('Data source import policy', () => { const importStaticHtml = ( html = '
Imported
', + opts = {}, ) => { - cmpRoot.components().resetFromString(html); + cmpRoot.components().resetFromString(html, opts); }; const createBoundRule = () => { @@ -132,8 +133,8 @@ describe('Data source import policy', () => { ])[0] as CssRule; }; - const importStaticCss = (css = '.bound-rule { color: green; }') => { - em.Css.addCollection(css, { extend: 1 }); + const importStaticCss = (css = '.bound-rule { color: green; }', opts = {}) => { + em.Css.addCollection(css, { extend: 1, ...opts }); }; const expectUntouchedComponentValues = ( @@ -366,6 +367,39 @@ describe('Data source import policy', () => { expectUntouchedComponentValues(component); }); + test('supports per-call override on parsed HTML import', () => { + init({ + dataSources: { dataBindingImportPolicy: 'skip' }, + }); + addBaseDataSource(); + const component = createBoundComponent(); + + importStaticHtml(undefined, { dataBindingImportPolicy: 'update' }); + + expect(dsm.getValue('records.rec1.tagName')).toBe('section'); + expect(dsm.getValue('records.rec1.title')).toBe('Imported Title'); + expect(dsm.getValue('records.rec1.color')).toBe('green'); + expect(component.get('tagName', { skipResolve: true })).toEqual(makeTagNameVar()); + expect(component.get('tagName')).toBe('section'); + expect(component.getAttributes({ skipResolve: true })['data-attr']).toEqual(makeTitleVar()); + expect(component.getStyle({ skipResolve: true }).color).toEqual(makeColorVar()); + }); + + test('supports per-call override on parsed CSS import', () => { + init({ + dataSources: { dataBindingImportPolicy: 'skip' }, + }); + addBaseDataSource(); + const rule = createBoundRule(); + + importStaticCss(undefined, { dataBindingImportPolicy: 'update' }); + + expect(dsm.getValue('records.rec1.color')).toBe('green'); + expect(rule.getStyle('', { skipResolve: true }).color).toEqual(makeColorVar()); + expect(rule.getStyle().color).toBe('green'); + expectUntouchedRuleValues(rule); + }); + test('keeps bindings and warns when update cannot write data-condition values', () => { init({ dataSources: { dataBindingImportPolicy: 'update' },