diff --git a/packages/core/src/dom_components/model/Component.ts b/packages/core/src/dom_components/model/Component.ts index 149725246..0903b5af3 100644 --- a/packages/core/src/dom_components/model/Component.ts +++ b/packages/core/src/dom_components/model/Component.ts @@ -225,6 +225,10 @@ export default class Component extends StyleableModel { return this.frame?.getPage(); } + getType() { + return this.get('type') || 'default'; + } + preInit() {} /** @@ -449,12 +453,11 @@ export default class Component extends StyleableModel { const { em } = this; if (!em) return; - const event = 'component:styleUpdate'; const styleKeys = keys(newStyles); const pros = { style: newStyles }; - em.trigger(event, this, pros); - styleKeys.forEach((key) => em.trigger(`${event}:${key}`, this, pros)); + this.emitWithEditor(ComponentsEvents.styleUpdate, this, pros); + styleKeys.forEach((key) => this.emitWithEditor(`${ComponentsEvents.styleUpdateProperty}${key}`, this, pros)); const collectionsStateMap = this.collectionsStateMap; const allParentCollectionIds = Object.keys(collectionsStateMap); diff --git a/packages/core/src/dom_components/types.ts b/packages/core/src/dom_components/types.ts index 188b7f9e7..9e2bc1293 100644 --- a/packages/core/src/dom_components/types.ts +++ b/packages/core/src/dom_components/types.ts @@ -53,6 +53,14 @@ export enum ComponentsEvents { update = 'component:update', updateInside = 'component:update-inside', + /** + * @event `component:styleUpdate` Component related styles are updated, the component is passed as an argument to the callback. + * @example + * editor.on('component:styleUpdate', (component) => { ... }); + */ + styleUpdate = 'component:styleUpdate', + styleUpdateProperty = 'component:styleUpdate:', + /** * @event `component:select` Component selected. * @example diff --git a/packages/core/src/style_manager/index.ts b/packages/core/src/style_manager/index.ts index 998394775..34c531c4a 100644 --- a/packages/core/src/style_manager/index.ts +++ b/packages/core/src/style_manager/index.ts @@ -805,9 +805,9 @@ export default class StyleManager extends ItemManagerModule< props.forEach((prop) => { const isVisible = prop.__checkVisibility({ target: lastTarget, + sector, component, - // @ts-ignore - sectors, + sectors: sectors.models, }); prop.set('visible', isVisible); }); diff --git a/packages/core/src/style_manager/model/Property.ts b/packages/core/src/style_manager/model/Property.ts index a248b01b6..e13cc5b6a 100644 --- a/packages/core/src/style_manager/model/Property.ts +++ b/packages/core/src/style_manager/model/Property.ts @@ -1,4 +1,4 @@ -import { isUndefined, isString, isArray, result, keys, each, includes, any } from 'underscore'; +import { isUndefined, isString, isArray, result, keys, each, includes, isFunction } from 'underscore'; import { Model } from '../../common'; import Component from '../../dom_components/model/Component'; import EditorModel from '../../editor/model/Editor'; @@ -6,6 +6,14 @@ import { capitalize, camelCase, hasWin } from '../../utils/mixins'; import Sector from './Sector'; import PropertyComposite from './PropertyComposite'; import { StyleProps } from '../../domain_abstract/model/StyleableModel'; +import { StyleTarget } from '..'; + +export type IsVisibleFn = (props: { + property: Property; + sector: Sector; + target: StyleTarget; + component?: Component; +}) => boolean | void; /** @private */ export interface PropertyProps { @@ -33,6 +41,17 @@ export interface PropertyProps { opts: any; }) => any; + /** + * Pass a custom function to check if the property should be visible. + * + * @example + * isVisible: ({ component }) => { + * // Show the property only if the selected component is an image + * return component?.is('image'); + * } + */ + isVisible?: IsVisibleFn; + /** * If true, the property will be forced to be full width */ @@ -56,9 +75,9 @@ export interface PropertyProps { * 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' + * @example + * // in this case the property is only shown when display is of value 'flex' or 'block' AND position is 'absolute' + * requires: { display: ['flex', 'block'], position: ['absolute'] }; */ requires?: Record; @@ -81,6 +100,10 @@ export type OptionsUpdate = { export type OptionsStyle = { camelCase?: boolean }; +export interface PropertyPropsCustom extends PropertyProps { + [key: string]: any; +} + type PartialPropertyProps = Partial; /** @@ -98,7 +121,7 @@ type PartialPropertyProps = Partial; * ``` * */ -export default class Property = PropertyProps> extends Model { +export default class Property extends Model { em!: EditorModel; parent?: Property; @@ -528,19 +551,31 @@ export default class Property = PropertyProps> ext }; } - __checkVisibility({ target, component, sectors }: { target: any; component?: Component; sectors?: Sector[] }) { + __checkVisibility({ + target, + component, + sector, + sectors, + }: { + target: StyleTarget; + sector: Sector; + component?: Component; + sectors?: Sector[]; + }) { const trg = component || target; if (!trg) return false; const id = this.getId(); const property = this.getName(); - const toRequire = this.get('toRequire'); - const requires = this.get('requires'); - const requiresParent = this.get('requiresParent'); + const { requires, requiresParent, toRequire, isVisible } = this.attributes; const unstylable = trg.get('unstylable'); const stylableReq = trg.get('stylable-require'); let stylable = trg.get('stylable'); + if (isFunction(isVisible)) { + return !!isVisible({ property: this, sector, target, component }); + } + // Stylable could also be an array indicating with which property // the target could be styled if (isArray(stylable)) { diff --git a/packages/core/test/specs/style_manager/model/Sectors.ts b/packages/core/test/specs/style_manager/model/Sectors.ts index f0d7e9063..f8e865044 100644 --- a/packages/core/test/specs/style_manager/model/Sectors.ts +++ b/packages/core/test/specs/style_manager/model/Sectors.ts @@ -86,5 +86,23 @@ describe('Sectors', () => { expect(prop.isVisible()).toBe(isVisible); }); }); + + test('Property with isVisible', () => { + const cmp = domc.addComponent({ tagName: 'span' }); + em.setSelected(cmp); + + s2.getProperty('color')?.set({ + isVisible: ({ component }) => component?.tagName !== 'span', + }); + + sm.__upSel(); + + [s1, s2].forEach((sector) => expect(sector.isVisible()).toBe(true)); + + s2.getProperties().forEach((prop) => { + const isVisible = prop.getName() !== 'color'; + expect(prop.isVisible()).toBe(isVisible); + }); + }); }); });