Per element style config (#136)

* Fix brightness calculation

* Own longpress was actually never used...

* Style per element

* Delete commented out functions

* Updating documentation

* Little doc update

* Fix doc

* Linting
This commit is contained in:
Jérôme W 2019-05-01 13:40:20 +02:00 committed by GitHub
parent 56a8fac0fa
commit 7f10243f63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 296 additions and 129 deletions

217
README.md
View File

@ -54,7 +54,7 @@ Lovelace Button card for your entities.
| `hold_action` | object | optional | See [Action](#Action) | Define the type of action on hold, if undefined, nothing happens. |
| `name` | string | optional | `Air conditioner` | Define an optional text to show below the icon |
| `label` | string | optional | Any string that you want | Display a label below the card. See [Layouts](#layout) for more information. |
| `label_template` | string | optional | `states['light.mylight'].attributes.brightness` | See [templates](#templates). Any javascript code which returns a string. Overrides `label` |
| `label_template` | string | optional | | See [templates](#templates). Any javascript code which returns a string. Overrides `label` |
| `show_name` | boolean | `true` | `true` \| `false` | Wether to show the name or not. Will pick entity_id's name by default, unless redefined in the `name` property or in any state `name` property |
| `show_state` | boolean | `false` | `true` \| `false` | Show the state on the card. defaults to false if not set |
| `show_icon` | boolean | `true` | `true` \| `false` | Wether to show the icon or not. Unless redefined in `icon`, uses the default entity icon from hass |
@ -63,8 +63,7 @@ Lovelace Button card for your entities.
| `show_entity_picture` | boolean | `false` | `true` \| `false` | Replace the icon by the entity picture (if any) or the custom picture (if any). Falls back to using the icon if both are undefined |
| `entity_picture` | string | optional | Can be any of `/local/*` file or a URL | Will override the icon/the default entity_picture with your own image. Best is to use a square image. You can also define one per state |
| `units` | string | optional | `Kb/s`, `lux`, ... | Override or define the units to display after the state of the entity. If omitted, it's using the entity's units |
| `style` | object list | optional | `- text-transform: none` | Define a list of css attribute and their value to apply to the card |
| `entity_picture_style` | object list | optional | `- border-radius: 50%`, `- filter: grayscale(100%)`, ... | Style applied to the entity picture |
| `styles` | object list | optional | | See [styles](#styles) |
| `state` | object list | optional | See [State](#State) | State to use for the color, icon and style of the button. Multiple states can be defined |
| `confirmation` | string | optional | Free-form text | Show a confirmation popup on tap with defined text |
| `layout` | string | optional | See [Layout](#Layout) | The layout of the button can be modified using this option |
@ -89,12 +88,11 @@ Lovelace Button card for your entities.
| `name` | string | optional | Any string, `'Alert'`, `'My little switch is on'`, ... | if `show_name` is `true`, the name to display for this state. If undefined, uses the general config `name`, and if undefined uses the entity name |
| `icon` | string | optional | `mdi:battery` | The icon to display for this state. Defaults to the entity icon. Hide with `show_icon: false` |
| `color` | string | `var(--primary-text-color)` | Any color, eg: `rgb(28, 128, 199)` or `blue` | The color of the icon (if `color_type: icon`) or the background (if `color_type: card`) |
| `style` | string | optional | Any CSS style. If nothing is specified, the main style is used unless undefined. If you want to override the default style of the main part of the config, use `style: []` | Define a list of css attribute and their value to apply to the card |
| `styles` | string | optional | | See [styles](#styles) |
| `spin` | boolean | `false` | `true` \| `false` | Should the icon spin for this state? |
| `entity_picture` | string | optional | Can be any of `/local/*` file or a URL | Will override the icon/the default entity_picture with your own image for this state. Best is to use a square image |
| `entity_picture_style` | object list | optional | `- border-radius: 50%`, `- filter: grayscale(100%)`, ... | Style applied to the entity picture for this state |
| `label` | string | optional | Any string that you want | Display a label below the card. See [Layouts](#layout) for more information. |
| `label_template` | string | optional | `states['light.mylight'].attributes.brightness` | See [templates](#templates). Any javascript code which returns a string. Overrides `label` |
| `label_template` | string | optional | | See [templates](#templates). Any javascript code which returns a string. Overrides `label` |
### Available operators
@ -109,7 +107,7 @@ The order of your elements in the `state` object matters. The first one which is
| `>` | `12` | Current state is superior to `value` |
| `!=` | `'normal'` | Current state is not equal (`!=` javascript) to `value` |
| `regex` | `'^norm.*$'` | `value` regex applied to current state does match |
| `template` | `return states['input_select.light_mode'].state === 'night_mode'` | See [here](#state-templates) for examples. `value` needs to be a javascript expression which returns a boolean. If the boolean is true, it will match this state |
| `template` | | See [templates](#templates) for examples. `value` needs to be a javascript expression which returns a boolean. If the boolean is true, it will match this state |
| `default` | N/A | If nothing matches, this is used |
### Layout
@ -132,8 +130,9 @@ Multiple values are possible, see the image below for examples:
### Templates
`label_template` supports templating.
It will be interpreted as javascript code and the code should return a value.
`label_template` supports templating as well as `value` for `state` when `operator: template`
* `label_template`: It will be interpreted as javascript code and the code should return a string
* `value` for `state` when `operator: template`: It will be interpreted as javascript code and the code should return a boolean (`true` or `false`)
Inside the javascript code, you'll have access to those variables:
* `entity`: The current entity object, if the entity is defined in the card
@ -141,7 +140,74 @@ Inside the javascript code, you'll have access to those variables:
* `user`: The user object (equivalent to `hass.user`)
* `hass`: The complete `hass` object
See [here](#playing-with-label-templates) for some examples.
The value shouldn't be enclosed in quotes:
```yaml
label_template: >
return states['light.mylight'].attributes.brightness
```
or
```yaml
state:
- operator: template
value: >
return states['input_select.light_mode'].state === 'night_mode'
```
See [here](#templates-support) for some examples.
### Styles
For each element in the card, styles can be defined in 2 places:
* in the main part of the config
* in each state
Styles defined in each state are **additive** with the ones defined in the main part of the config. In the `state` part, just define the ones specific to your current state and keep the common ones in the main part of the config.
The `style` object members are:
* `card`: styles for the card itself. Styles that are defined here will be applied to the whole card and it's content, unless redefined in elements below.
* `icon`: styles for the icon
* `entity_picture`: styles for the picture (if any)
* `name`: styles for the name
* `state`: styles for the state
* `label`: styles for the label
```yaml
- type: custom:button-card
[...]
styles:
card:
- xxxx: value
icon:
- xxxx: value
entity_picture:
- xxxx: value
name:
- xxxx: value
state:
- xxxx: value
label:
- xxxx: value
state:
- value: 'on'
styles:
card:
- yyyy: value
icon:
- yyyy: value
entity_picture:
- yyyy: value
name:
- yyyy: value
state:
- yyyy: value
label:
- yyyy: value
```
This will render:
* The `card` with the styles `xxxx: value` **and** `yyyy: value` applied
* Same for all the others.
See [styling](#styling) for a complete example.
## Installation
@ -242,9 +308,10 @@ Light card with card color type, name, and automatic color:
tap_action:
action: more-info
name: Home
style:
- font-size: 12px
- font-weight: bold
styles:
card:
- font-size: 12px
- font-weight: bold
```
---
@ -389,8 +456,9 @@ The definition order matters, the first item to match will be the one selected.
- operator: 'default' # used if nothing matches
color: yellow
icon: mdi: thermometer
style:
- opacity: 0.5
styles:
card:
- opacity: 0.5
```
#### `tap_action` Navigate
@ -424,8 +492,9 @@ You can make the whole button blink:
- value: "on"
color: red
icon: mdi:alert
style:
- animation: blink 2s ease infinite
styles:
card:
- animation: blink 2s ease infinite
- operator: default
color: green
icon: mdi:shield-check
@ -446,48 +515,54 @@ If you specify a width for the card, it has to be in `px`. All the cards without
entity: light.test_light
color: auto
name: s:default h:200px
style:
- height: 200px
styles:
card:
- height: 200px
- type: "custom:button-card"
entity: light.test_light
color_type: card
color: auto
name: s:100% h:200px
size: 100%
style:
- height: 200px
styles:
card:
- height: 200px
- type: "custom:button-card"
entity: light.test_light
color_type: card
color: auto
size: 10%
name: s:10% h:200px
style:
- height: 200px
styles:
card:
- height: 200px
- type: horizontal-stack
cards:
- type: "custom:button-card"
entity: light.test_light
color: auto
name: 60px
style:
- height: 60px
- width: 60px
styles:
card:
- height: 60px
- width: 60px
- type: "custom:button-card"
entity: light.test_light
color_type: card
color: auto
name: 80px
style:
- height: 80px
- width: 30px
styles:
card:
- height: 80px
- width: 30px
- type: "custom:button-card"
entity: light.test_light
color_type: card
color: auto
name: 300px
style:
- height: 300px
styles:
card:
- height: 300px
```
### Templates Support
@ -504,8 +579,9 @@ If you specify a width for the card, it has to be in `px`. All the cards without
return 'Brightness: ' + (bri ? bri : '0') + '%';
show_label: true
size: 15%
style:
- height: 100px
styles:
card:
- height: 100px
- type: "custom:button-card"
color_type: icon
entity: light.test_light
@ -514,8 +590,9 @@ If you specify a width for the card, it has to be in `px`. All the cards without
return 'Other State: ' + states['switch.skylight'].state;
show_label: true
show_name: false
style:
- height: 100px
styles:
card:
- height: 100px
```
#### State Templates
@ -552,6 +629,76 @@ Example with `template`:
label: Day Mode
```
### Styling
![per-style-config](examples/per-style-config.gif)
```yaml
- type: "custom:button-card"
color_type: icon
entity: light.test_light
label_template: >
var bri = states['light.test_light'].attributes.brightness;
return 'Brightness: ' + (bri ? bri : '0') + '%';
show_label: true
show_state: true
size: 10%
styles:
card:
- height: 100px
label:
- color: gray
- font-size: 9px
- justify-self: start
- padding: 0px 5px
name:
- text-transform: uppercase
- letter-spacing: 0.5em
- font-familly: cursive
- justify-self: start
- padding: 0px 5px
state:
- justify-self: start
- font-size: 10px
- padding: 0px 5px
state:
- value: 'on'
styles:
state:
- color: green
- value: 'off'
styles:
state:
- color: red
card:
- filter: brightness(40%)
- type: "custom:button-card"
color_type: icon
entity: light.test_light
layout: icon_label
label_template: >
return 'Other State: ' + states['switch.skylight'].state;
show_label: true
show_name: false
size: 100%
styles:
card:
- height: 200px
label:
- font-weight: bold
- writing-mode: vertical-rl
- text-orientation: mixed
state:
- value: 'on'
styles:
label:
- color: red
- value: 'off'
styles:
label:
- color: green
```
## Credits
- [ciotlosm](https://github.com/ciotlosm) for the readme template and the awesome examples

96
dist/button-card.js vendored
View File

@ -3330,7 +3330,7 @@ function buildNameStateConcat(name, stateString) {
function applyBrightnessToColor(color, brightness) {
const colorObj = new TinyColor(getColorFromVariable(color));
if (colorObj.isValid) {
const validColor = colorObj.darken(100 - brightness).toString();
const validColor = colorObj.mix('black', 100 - brightness).toString();
if (validColor) return validColor;
}
return color;
@ -3614,10 +3614,10 @@ class LongPress extends HTMLElement {
customElements.define("long-press-button-card", LongPress);
const getLongPress = () => {
const body = document.body;
if (body.querySelector("long-press")) {
return body.querySelector("long-press");
if (body.querySelector("long-press-button-card")) {
return body.querySelector("long-press-button-card");
}
const longpress = document.createElement("long-press");
const longpress = document.createElement("long-press-button-card");
body.appendChild(longpress);
return longpress;
};
@ -3955,9 +3955,7 @@ let ButtonCard = class ButtonCard extends LitElement {
shouldUpdate(changedProps) {
const state = this.config.entity ? this.hass.states[this.config.entity] : undefined;
const configState = this._getMatchingConfigState(state);
const forceUpdate = this.config.show_label && (configState && configState.label_template || this.config.label_template) || this.config.state && this.config.state.find(elt => {
return elt.operator === 'template';
}) ? true : false;
const forceUpdate = this.config.show_label && (configState && configState.label_template || this.config.label_template) || this.config.state && this.config.state.find(elt => elt.operator === 'template') ? true : false;
return hasConfigOrEntityChanged(this, changedProps, forceUpdate);
}
_getMatchingConfigState(state) {
@ -4078,39 +4076,17 @@ let ButtonCard = class ButtonCard extends LitElement {
}
return entityPicture;
}
_buildStyle(state, configState) {
let cardStyle = {};
let styleArray;
if (state) {
if (configState && configState.style) {
styleArray = configState.style;
} else if (this.config.style) {
styleArray = this.config.style;
}
} else if (this.config.style) {
styleArray = this.config.style;
_buildStyleGeneric(configState, styleType) {
let style = {};
if (this.config.styles[styleType]) {
style = Object.assign(style, ...this.config.styles[styleType]);
}
if (styleArray) {
cardStyle = Object.assign(cardStyle, ...styleArray);
if (configState && configState.styles[styleType]) {
let configStateStyle = {};
configStateStyle = Object.assign(configStateStyle, ...configState.styles[styleType]);
style = Object.assign({}, style, configStateStyle);
}
return cardStyle;
}
_buildEntityPictureStyle(state, configState) {
let entityPictureStyle = {};
let styleArray;
if (state) {
if (configState && configState.entity_picture_style) {
styleArray = configState.entity_picture_style;
} else if (this.config.entity_picture_style) {
styleArray = this.config.entity_picture_style;
}
} else if (this.config.entity_picture_style) {
styleArray = this.config.entity_picture_style;
}
if (styleArray) {
entityPictureStyle = Object.assign(entityPictureStyle, ...styleArray);
}
return entityPictureStyle;
return style;
}
_buildName(state, configState) {
if (this.config.show_name === false) {
@ -4215,7 +4191,7 @@ let ButtonCard = class ButtonCard extends LitElement {
const color = this._buildCssColorAttribute(state, configState);
let buttonColor = color;
let cardStyle = {};
const configCardStyle = this._buildStyle(state, configState);
const configCardStyle = this._buildStyleGeneric(configState, 'card');
if (configCardStyle.width) {
this.style.setProperty('flex', '0 0 auto');
this.style.setProperty('max-width', 'fit-content');
@ -4260,6 +4236,9 @@ let ButtonCard = class ButtonCard extends LitElement {
const iconTemplate = this._getIconHtml(state, configState, color);
const itemClass = ['container', containerClass];
const label = this._buildLabel(state, configState);
const nameStyleFromConfig = this._buildStyleGeneric(configState, 'name');
const stateStyleFromConfig = this._buildStyleGeneric(configState, 'state');
const labelStyleFromConfig = this._buildStyleGeneric(configState, 'label');
if (!iconTemplate) itemClass.push('no-icon');
if (!name) itemClass.push('no-name');
if (!stateString) itemClass.push('no-state');
@ -4267,21 +4246,18 @@ let ButtonCard = class ButtonCard extends LitElement {
return html`
<div class=${itemClass.join(' ')}>
${iconTemplate ? iconTemplate : ''}
${name ? html`<div class="name">${name}</div>` : ''}
${stateString ? html`<div class="state">${stateString}</div>` : ''}
${label ? html`<div class="label">${label}</div>` : ''}
${name ? html`<div class="name" style=${styleMap(nameStyleFromConfig)}>${name}</div>` : ''}
${stateString ? html`<div class="state" style=${styleMap(stateStyleFromConfig)}>${stateString}</div>` : ''}
${label ? html`<div class="label" style=${styleMap(labelStyleFromConfig)}>${label}</div>` : ''}
</div>
`;
}
_getIconHtml(state, configState, color) {
const icon = this._buildIcon(state, configState);
const entityPicture = this._buildEntityPicture(state, configState);
const entityPictureStyleFromConfig = this._buildEntityPictureStyle(state, configState);
const haIconStyle = {
color,
width: this.config.size,
'min-width': this.config.size
};
const entityPictureStyleFromConfig = this._buildStyleGeneric(configState, 'entity_picture');
const haIconStyleFromConfig = this._buildStyleGeneric(configState, 'icon');
const haIconStyle = Object.assign({ color, width: this.config.size, 'min-width': this.config.size }, haIconStyleFromConfig);
const entityPictureStyle = Object.assign({}, haIconStyle, entityPictureStyleFromConfig);
if (icon || entityPicture) {
return html`
@ -4308,6 +4284,30 @@ let ButtonCard = class ButtonCard extends LitElement {
this.config.color_off = 'var(--paper-item-icon-color)';
}
this.config.color_on = 'var(--paper-item-icon-active-color)';
/* Temporary until we deprecate style and entity_picture_style config option */
if (!this.config.styles) {
this.config.styles = {};
}
if (this.config.style && !this.config.styles.card) {
this.config.styles.card = this.config.style;
}
if (this.config.entity_picture_style && !this.config.styles.entity_picture) {
this.config.styles.entity_picture = this.config.entity_picture_style;
}
if (this.config.state) {
/* eslint no-param-reassign: ["error", { "props": false }] */
this.config.state.forEach(s => {
if (!s.styles) {
s.styles = {};
}
if (s.entity_picture_style && !s.styles.entity_picture) {
s.styles.entity_picture = s.entity_picture_style;
}
if (s.style && !s.styles.card) {
s.styles.card = s.style;
}
});
}
}
// The height of your card. Home Assistant uses this to automatically
// distribute all cards over the available columns.

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 KiB

View File

@ -56,7 +56,7 @@ class ButtonCard extends LitElement {
|| this.config!.label_template)
)
|| this.config!.state
&& this.config!.state.find((elt) => { return elt.operator === 'template'; })
&& this.config!.state.find(elt => elt.operator === 'template')
? true : false;
return hasConfigOrEntityChanged(this, changedProps, forceUpdate);
}
@ -196,44 +196,23 @@ class ButtonCard extends LitElement {
return entityPicture;
}
private _buildStyle(
state: HassEntity | undefined, configState: StateConfig | undefined,
private _buildStyleGeneric(
configState: StateConfig | undefined,
styleType: string,
): StyleInfo {
let cardStyle: StyleInfo = {};
let styleArray: CssStyleConfig[] | undefined;
if (state) {
if (configState && configState.style) {
styleArray = configState.style;
} else if (this.config!.style) {
styleArray = this.config!.style;
}
} else if (this.config!.style) {
styleArray = this.config!.style;
let style: StyleInfo = {};
if (this.config!.styles[styleType]) {
style = Object.assign(style, ...this.config!.styles[styleType]);
}
if (styleArray) {
cardStyle = Object.assign(cardStyle, ...styleArray);
if (configState && configState.styles[styleType]) {
let configStateStyle: StyleInfo = {};
configStateStyle = Object.assign(configStateStyle, ...configState.styles[styleType]);
style = {
...style,
...configStateStyle,
};
}
return cardStyle;
}
private _buildEntityPictureStyle(
state: HassEntity | undefined, configState: StateConfig | undefined,
): StyleInfo {
let entityPictureStyle: StyleInfo = {};
let styleArray: CssStyleConfig[] | undefined;
if (state) {
if (configState && configState.entity_picture_style) {
styleArray = configState.entity_picture_style;
} else if (this.config!.entity_picture_style) {
styleArray = this.config!.entity_picture_style;
}
} else if (this.config!.entity_picture_style) {
styleArray = this.config!.entity_picture_style;
}
if (styleArray) {
entityPictureStyle = Object.assign(entityPictureStyle, ...styleArray);
}
return entityPictureStyle;
return style;
}
private _buildName(
@ -361,7 +340,7 @@ class ButtonCard extends LitElement {
const color = this._buildCssColorAttribute(state, configState);
let buttonColor = color;
let cardStyle: StyleInfo = {};
const configCardStyle = this._buildStyle(state, configState);
const configCardStyle = this._buildStyleGeneric(configState, 'card');
if (configCardStyle.width) {
this.style.setProperty('flex', '0 0 auto');
@ -423,6 +402,9 @@ class ButtonCard extends LitElement {
const iconTemplate = this._getIconHtml(state, configState, color);
const itemClass: string[] = ['container', containerClass];
const label = this._buildLabel(state, configState);
const nameStyleFromConfig = this._buildStyleGeneric(configState, 'name');
const stateStyleFromConfig = this._buildStyleGeneric(configState, 'state');
const labelStyleFromConfig = this._buildStyleGeneric(configState, 'label');
if (!iconTemplate) itemClass.push('no-icon');
if (!name) itemClass.push('no-name');
if (!stateString) itemClass.push('no-state');
@ -431,9 +413,9 @@ class ButtonCard extends LitElement {
return html`
<div class=${itemClass.join(' ')}>
${iconTemplate ? iconTemplate : ''}
${name ? html`<div class="name">${name}</div>` : ''}
${stateString ? html`<div class="state">${stateString}</div>` : ''}
${label ? html`<div class="label">${label}</div>` : ''}
${name ? html`<div class="name" style=${styleMap(nameStyleFromConfig)}>${name}</div>` : ''}
${stateString ? html`<div class="state" style=${styleMap(stateStyleFromConfig)}>${stateString}</div>` : ''}
${label ? html`<div class="label" style=${styleMap(labelStyleFromConfig)}>${label}</div>` : ''}
</div>
`;
}
@ -445,12 +427,14 @@ class ButtonCard extends LitElement {
): TemplateResult | undefined {
const icon = this._buildIcon(state, configState);
const entityPicture = this._buildEntityPicture(state, configState);
const entityPictureStyleFromConfig = this._buildEntityPictureStyle(state, configState);
const entityPictureStyleFromConfig = this._buildStyleGeneric(configState, 'entity_picture');
const haIconStyleFromConfig = this._buildStyleGeneric(configState, 'icon');
const haIconStyle = {
color,
width: this.config!.size,
'min-width': this.config!.size,
...haIconStyleFromConfig,
};
const entityPictureStyle = {
...haIconStyle,
@ -497,6 +481,31 @@ class ButtonCard extends LitElement {
this.config!.color_off = 'var(--paper-item-icon-color)';
}
this.config!.color_on = 'var(--paper-item-icon-active-color)';
/* Temporary until we deprecate style and entity_picture_style config option */
if (!this.config.styles) {
this.config.styles = {};
}
if (this.config.style && !this.config.styles.card) {
this.config.styles.card = this.config.style;
}
if (this.config.entity_picture_style && !this.config.styles.entity_picture) {
this.config.styles.entity_picture = this.config.entity_picture_style;
}
if (this.config.state) {
/* eslint no-param-reassign: ["error", { "props": false }] */
this.config.state.forEach((s) => {
if (!s.styles) {
s.styles = {};
}
if (s.entity_picture_style && !s.styles.entity_picture) {
s.styles.entity_picture = s.entity_picture_style;
}
if (s.style && !s.styles.card) {
s.styles.card = s.style;
}
});
}
}
// The height of your card. Home Assistant uses this to automatically

View File

@ -51,7 +51,7 @@ export function applyBrightnessToColor(
): string {
const colorObj = new TinyColor(getColorFromVariable(color));
if (colorObj.isValid) {
const validColor = colorObj.darken(100 - brightness).toString();
const validColor = colorObj.mix('black', 100 - brightness).toString();
if (validColor) return validColor;
}
return color;

View File

@ -164,11 +164,11 @@ customElements.define("long-press-button-card", LongPress);
const getLongPress = (): LongPress => {
const body = document.body;
if (body.querySelector("long-press")) {
return body.querySelector("long-press") as LongPress;
if (body.querySelector("long-press-button-card")) {
return body.querySelector("long-press-button-card") as LongPress;
}
const longpress = document.createElement("long-press");
const longpress = document.createElement("long-press-button-card");
body.appendChild(longpress);
return longpress as LongPress;
@ -184,4 +184,4 @@ export const longPressBind = (element: LongPressElement) => {
export const longPress = directive(() => (part: PropertyPart) => {
longPressBind(part.committer.element);
});
});

View File

@ -30,6 +30,7 @@ export interface ButtonCardConfig {
units?: string;
style?: CssStyleConfig[];
state?: StateConfig[];
styles: StylesConfig;
confirmation?: string;
layout: Layout;
entity_picture_style?: CssStyleConfig[];
@ -57,11 +58,21 @@ export interface StateConfig {
style?: CssStyleConfig[];
entity_picture_style?: CssStyleConfig[];
entity_picture?: string;
styles: StylesConfig;
spin?: boolean;
label?: string;
label_template?: string;
}
export interface StylesConfig {
card?: CssStyleConfig[];
entity_picture?: CssStyleConfig[];
icon?: CssStyleConfig[];
name?: CssStyleConfig[];
state?: CssStyleConfig[];
label?: CssStyleConfig[];
}
export interface CssStyleConfig {
[key: string]: any;
}