|
|
@ -25,7 +25,7 @@ type FromStyleDataStack = Omit<FromStyleData, 'property' | 'separator'> & { |
|
|
separatorLayers: RegExp; |
|
|
separatorLayers: RegExp; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
export type OptionStyleStack = OptionsStyle & { number?: { min?: number; max?: number } }; |
|
|
export type OptionStyleStack = OptionsStyle & { number?: { min?: number; max?: number }; __clear?: boolean }; |
|
|
|
|
|
|
|
|
/** @private */ |
|
|
/** @private */ |
|
|
export interface PropertyStackProps extends Omit<PropertyCompositeProps, 'toStyle' | 'fromStyle'> { |
|
|
export interface PropertyStackProps extends Omit<PropertyCompositeProps, 'toStyle' | 'fromStyle'> { |
|
|
@ -50,13 +50,28 @@ export interface PropertyStackProps extends Omit<PropertyCompositeProps, 'toStyl |
|
|
* Custom logic for creating layer labels. |
|
|
* Custom logic for creating layer labels. |
|
|
*/ |
|
|
*/ |
|
|
layerLabel?: (layer: Layer, data: { index: number; values: LayerValues; property: PropertyStack }) => string; |
|
|
layerLabel?: (layer: Layer, data: { index: number; values: LayerValues; property: PropertyStack }) => string; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Empty value to apply when all layers are removed. |
|
|
|
|
|
* @default 'unset' |
|
|
|
|
|
* @example |
|
|
|
|
|
* // use simple string
|
|
|
|
|
|
* emptyValue: 'inherit', |
|
|
|
|
|
* // or a function for a custom style object
|
|
|
|
|
|
* emptyValue: () => ({ |
|
|
|
|
|
* color: 'unset', |
|
|
|
|
|
* width: 'auto' |
|
|
|
|
|
* }), |
|
|
|
|
|
*/ |
|
|
|
|
|
emptyValue?: string | ((data: { property: PropertyStack }) => PropValues); |
|
|
|
|
|
|
|
|
toStyle?: (values: PropValues, data: ToStyleDataStack) => ReturnType<ToStyle>; |
|
|
toStyle?: (values: PropValues, data: ToStyleDataStack) => ReturnType<ToStyle>; |
|
|
fromStyle?: (style: StyleProps, data: FromStyleDataStack) => ReturnType<FromStyle>; |
|
|
fromStyle?: (style: StyleProps, data: FromStyleDataStack) => ReturnType<FromStyle>; |
|
|
parseLayer?: (data: { value: string; values: PropValues }) => PropValues; |
|
|
parseLayer?: (data: { value: string; values: PropValues }) => PropValues; |
|
|
emptyValue?: string | ((data: { property: PropertyStack }) => PropValues); |
|
|
|
|
|
selectedLayer?: Layer; |
|
|
selectedLayer?: Layer; |
|
|
prepend?: boolean; |
|
|
prepend?: boolean; |
|
|
__layers?: PropValues[]; |
|
|
__layers?: PropValues[]; |
|
|
|
|
|
isEmptyValue?: boolean; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -76,6 +91,17 @@ export interface PropertyStackProps extends Omit<PropertyCompositeProps, 'toStyl |
|
|
* return `A: ${values['prop-a']} B: ${values['prop-b']}`; |
|
|
* return `A: ${values['prop-a']} B: ${values['prop-b']}`; |
|
|
* } |
|
|
* } |
|
|
* ``` |
|
|
* ``` |
|
|
|
|
|
* @property {String|Function} [emptyValue='unset'] Empty value to apply when all layers are removed. |
|
|
|
|
|
* \n |
|
|
|
|
|
* ```js
|
|
|
|
|
|
* // use simple string
|
|
|
|
|
|
* emptyValue: 'inherit', |
|
|
|
|
|
* // or a function for a custom style object
|
|
|
|
|
|
* emptyValue: () => ({ |
|
|
|
|
|
* color: 'unset', |
|
|
|
|
|
* width: 'auto' |
|
|
|
|
|
* }), |
|
|
|
|
|
* ``` |
|
|
* |
|
|
* |
|
|
*/ |
|
|
*/ |
|
|
export default class PropertyStack extends PropertyComposite<PropertyStackProps> { |
|
|
export default class PropertyStack extends PropertyComposite<PropertyStackProps> { |
|
|
@ -109,16 +135,24 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
PropertyComposite.callInit(this, props, opts); |
|
|
PropertyComposite.callInit(this, props, opts); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
get layers() { |
|
|
|
|
|
return this.get('layers') as unknown as Layers; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Get all available layers. |
|
|
* Get all available layers. |
|
|
* @returns {Array<[Layer]>} |
|
|
* @returns {Array<[Layer]>} |
|
|
*/ |
|
|
*/ |
|
|
getLayers() { |
|
|
getLayers() { |
|
|
return this.__getLayers().models; |
|
|
return this.layers.models; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
__getLayers() { |
|
|
/** |
|
|
return this.get('layers') as unknown as Layers; |
|
|
* Check if the property has layers. |
|
|
|
|
|
* @returns {Boolean} |
|
|
|
|
|
*/ |
|
|
|
|
|
hasLayers() { |
|
|
|
|
|
return this.getLayers().length > 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -133,7 +167,7 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
* const layerLast = property.getLayer(layers.length - 1); |
|
|
* const layerLast = property.getLayer(layers.length - 1); |
|
|
*/ |
|
|
*/ |
|
|
getLayer(index = 0): Layer | undefined { |
|
|
getLayer(index = 0): Layer | undefined { |
|
|
return this.__getLayers().at(index) || undefined; |
|
|
return this.layers.at(index) || undefined; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -177,11 +211,12 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
* property.moveLayer(layer, 0); |
|
|
* property.moveLayer(layer, 0); |
|
|
*/ |
|
|
*/ |
|
|
moveLayer(layer: Layer, index = 0) { |
|
|
moveLayer(layer: Layer, index = 0) { |
|
|
|
|
|
const { layers } = this; |
|
|
const currIndex = layer ? layer.getIndex() : -1; |
|
|
const currIndex = layer ? layer.getIndex() : -1; |
|
|
|
|
|
|
|
|
if (currIndex >= 0 && isNumber(index) && index >= 0 && index < this.getLayers().length && currIndex !== index) { |
|
|
if (currIndex >= 0 && isNumber(index) && index >= 0 && index < layers.length && currIndex !== index) { |
|
|
this.removeLayer(layer); |
|
|
this.removeLayer(layer); |
|
|
this.__getLayers().add(layer, { at: index }); |
|
|
layers.add(layer, { at: index }); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -202,7 +237,7 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
const value = props[key]; |
|
|
const value = props[key]; |
|
|
values[key] = isUndefined(value) ? prop.getDefaultValue() : value; |
|
|
values[key] = isUndefined(value) ? prop.getDefaultValue() : value; |
|
|
}); |
|
|
}); |
|
|
const layer = this.__getLayers().push({ values } as any, opts); |
|
|
const layer = this.layers.push({ values } as any, opts); |
|
|
|
|
|
|
|
|
return layer; |
|
|
return layer; |
|
|
} |
|
|
} |
|
|
@ -216,7 +251,7 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
* property.removeLayer(layer); |
|
|
* property.removeLayer(layer); |
|
|
*/ |
|
|
*/ |
|
|
removeLayer(layer: Layer) { |
|
|
removeLayer(layer: Layer) { |
|
|
return this.__getLayers().remove(layer); |
|
|
return this.layers.remove(layer); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -344,6 +379,14 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
return isString(sep) ? new RegExp(`${sep}(?![^\\(]*\\))`) : sep; |
|
|
return isString(sep) ? new RegExp(`${sep}(?![^\\(]*\\))`) : sep; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Check if the property is with an empty value. |
|
|
|
|
|
* @returns {Boolean} |
|
|
|
|
|
*/ |
|
|
|
|
|
hasEmptyValue() { |
|
|
|
|
|
return !this.hasLayers() && !!this.attributes.isEmptyValue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
__upProperties(prop: Property, opts: any = {}) { |
|
|
__upProperties(prop: Property, opts: any = {}) { |
|
|
const layer = this.getSelectedLayer(); |
|
|
const layer = this.getSelectedLayer(); |
|
|
if (!layer) return; |
|
|
if (!layer) return; |
|
|
@ -362,7 +405,7 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
__upTargetsStyleProps(opts = {}) { |
|
|
__upTargetsStyleProps(opts = {}) { |
|
|
this.__upTargetsStyle(this.getStyleFromLayers(), opts); |
|
|
this.__upTargetsStyle(this.getStyleFromLayers(opts), opts); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
__upTargetsStyle(style: StyleProps, opts: any) { |
|
|
__upTargetsStyle(style: StyleProps, opts: any) { |
|
|
@ -394,16 +437,17 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
return this; |
|
|
return this; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
__setLayers(newLayers: PropValues[] = []) { |
|
|
__setLayers(newLayers: LayerValues[] = [], opts: { isEmptyValue?: boolean } = {}) { |
|
|
const layers = this.__getLayers(); |
|
|
const { layers } = this; |
|
|
const layersNew = newLayers.map(values => ({ values })); |
|
|
const layersNew = newLayers.map(values => ({ values })); |
|
|
|
|
|
|
|
|
if (layers.length === layersNew.length) { |
|
|
if (layers.length === layersNew.length) { |
|
|
layersNew.map((layer, n) => layers.at(n)?.upValues(layer.values)); |
|
|
layersNew.map((layer, n) => layers.at(n)?.upValues(layer.values)); |
|
|
} else { |
|
|
} else { |
|
|
this.__getLayers().reset(layersNew); |
|
|
layers.reset(layersNew); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.set({ isEmptyValue: !!opts.isEmptyValue }); |
|
|
this.__upSelected({ noEvent: true }); |
|
|
this.__upSelected({ noEvent: true }); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -431,13 +475,14 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
}, {} as PropValues); |
|
|
}, {} as PropValues); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
__getLayersFromStyle(style: StyleProps = {}) { |
|
|
__getLayersFromStyle(style: StyleProps = {}): LayerValues[] | null { |
|
|
if (!this.__styleHasProps(style)) return null; |
|
|
if (!this.__styleHasProps(style)) return null; |
|
|
|
|
|
if (this.isEmptyValueStyle(style)) return []; |
|
|
|
|
|
|
|
|
const name = this.getName(); |
|
|
const name = this.getName(); |
|
|
const props = this.getProperties(); |
|
|
const props = this.getProperties(); |
|
|
const sep = this.getLayerSeparator(); |
|
|
const sep = this.getLayerSeparator(); |
|
|
const fromStyle = this.get('fromStyle'); |
|
|
const { fromStyle } = this.attributes; |
|
|
let result = fromStyle ? fromStyle(style, { property: this, name, separatorLayers: sep }) : []; |
|
|
let result = fromStyle ? fromStyle(style, { property: this, name, separatorLayers: sep }) : []; |
|
|
|
|
|
|
|
|
if (!fromStyle) { |
|
|
if (!fromStyle) { |
|
|
@ -473,7 +518,6 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
|
|
|
|
|
|
getStyleFromLayers(opts: OptionStyleStack = {}) { |
|
|
getStyleFromLayers(opts: OptionStyleStack = {}) { |
|
|
let result: StyleProps = {}; |
|
|
let result: StyleProps = {}; |
|
|
const { emptyValue } = this.attributes; |
|
|
|
|
|
const name = this.getName(); |
|
|
const name = this.getName(); |
|
|
const layers = this.getLayers(); |
|
|
const layers = this.getLayers(); |
|
|
const props = this.getProperties(); |
|
|
const props = this.getProperties(); |
|
|
@ -508,14 +552,20 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
|
|
|
|
|
|
return { |
|
|
return { |
|
|
...result, |
|
|
...result, |
|
|
...this.getEmptyValueStyle(), |
|
|
...(opts.__clear ? {} : this.getEmptyValueStyle()), |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
getEmptyValueStyle() { |
|
|
isEmptyValueStyle(style: StyleProps = {}) { |
|
|
|
|
|
const emptyStyle = this.getEmptyValueStyle({ force: true }); |
|
|
|
|
|
const props = keys(emptyStyle); |
|
|
|
|
|
return !!props.length && props.every(prop => emptyStyle[prop] === style[prop]); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
getEmptyValueStyle(opts: { force?: boolean } = {}) { |
|
|
const { emptyValue } = this.attributes; |
|
|
const { emptyValue } = this.attributes; |
|
|
|
|
|
|
|
|
if (emptyValue && !this.getLayers().length) { |
|
|
if (emptyValue && (!this.hasLayers() || opts.force)) { |
|
|
const name = this.getName(); |
|
|
const name = this.getName(); |
|
|
const props = this.getProperties(); |
|
|
const props = this.getProperties(); |
|
|
const result = isString(emptyValue) ? emptyValue : emptyValue({ property: this }); |
|
|
const result = isString(emptyValue) ? emptyValue : emptyValue({ property: this }); |
|
|
@ -561,7 +611,7 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
hasValue(opts: { noParent?: boolean } = {}) { |
|
|
hasValue(opts: { noParent?: boolean } = {}) { |
|
|
const { noParent } = opts; |
|
|
const { noParent } = opts; |
|
|
const parentValue = noParent && this.getParentTarget(); |
|
|
const parentValue = noParent && this.getParentTarget(); |
|
|
return this.getLayers().length > 0 && !parentValue; |
|
|
return (this.hasLayers() || this.hasEmptyValue()) && !parentValue; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -569,8 +619,8 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
clear(opts = {}) { |
|
|
clear(opts = {}) { |
|
|
this.__getLayers().reset(); |
|
|
this.layers.reset(); |
|
|
this.__upTargetsStyleProps(opts); |
|
|
this.__upTargetsStyleProps({ ...opts, __clear: true }); |
|
|
PropertyBase.prototype.clear.call(this); |
|
|
PropertyBase.prototype.clear.call(this); |
|
|
return this; |
|
|
return this; |
|
|
} |
|
|
} |
|
|
@ -578,4 +628,12 @@ export default class PropertyStack extends PropertyComposite<PropertyStackProps> |
|
|
__canClearProp() { |
|
|
__canClearProp() { |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* @deprecated |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
__getLayers() { |
|
|
|
|
|
return this.layers; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|