@ThemeableClass Mandatory for theming
Putting @Themeable
on your component's class makes it overridable by the theming system. It takes several parameters that allow you to control what is exposed to the outside world.
Options
Option | Description |
---|---|
Name of the prop to use to define the variants to use when using the component. If not defined, the default name is "variant". | |
Object that defines what CSS variables and selectors to expose. Refer to the following section for more detail. |
Override styles
Styles are the main elements you can override with a theme. There are three ways of doing it:
- Using css variables exposed by the component,
- Using selectors exposed by the component,
- By writing custom css code.
Variables
That's the easiest way because the end-user that will use the component doesn't need to know the inner workings of the styles to configure it. But it requires some work to the creator of the component.
@Themeable({
css: {
vars: {
backgroundColor: 'bg-color',
textColor: 'text-color',
...
}
}
})
@Component()
class Button {
...
}
TIP
If you expose many variables the object can quickly become troublesome. To make it more readable you could put it in a separate file:
Now you can override the variables in your theme by doing:
import { VueThemes } from "@banquette/vue-typescript";
VueThemes.Define('my-button', {
'*': [
{
match: '*',
cssVars: {
backgroundColor: 'blue',
textColor: 'white'
}
}
]
})
Selectors
You can also expose a selector directly:
import { ThemeConfiguration } from './theme-configuration';
@Themeable({
selectors: {
root: '&.bt-button',
content: '.inner > span'
}
})
@Component('my-button')
class Button {
...
}
The end-user can then set any css property they want via a key/value pair notation:
import { VueThemes } from "@banquette/vue-typescript";
VueThemes.Define('my-button', {
'*': [
{
match: 'danger',
cssSelectors: {
content: {
fontWeight: 'bold',
color: 'red'
}
/**
* Will result in the following CSS being generated:
*
* .inner > span {
* font-weight: bold;
* color: red;
* }
*/
}
}
]
})
TIP
If the component has scoped styles, all generated styles will be scoped automatically, at runtime. So you can even modify the example above at runtime, dynamically.
Custom CSS
Finally you can write custom raw css, using cssCode
:
import { VueThemes } from "@banquette/vue-typescript";
VueThemes.Define('my-button', {
'*': [
{
match: 'danger',
cssCode: `
@media (max-width: 1250px) {
&.bt-button {
font-size: 0.8rem;
}
}
`
}
]
})
TIP
Like for the code generated using cssSelectors
, the code you write in cssCode
will be scoped automatically if
the styles of the component are scoped.
WARNING
If you want to target the root element of the component, you must prefix your selector with &
, like in the example above.
Override props
All props are overridable as soon as you put the @Themeable
attribute on the component. You have nothing to do for that.
There is currently no way to prevent a prop from being exposed, but it could be a future feature if requested.
Limitations
There is a limitation you should be aware of when it comes to overriding props.
To illustrate we'll look at a real world example with bt-alert
.
bt-alert
has a ttl
props that controls the time it will remain visible:
<bt-alert>I'll never disappear</bt-alert>
<bt-alert :ttl="3000">I'll disappear after 3 seconds</bt-alert>
With the theming, we could assign a ttl
by default for each bt-alert
of a certain type:
VueThemes.Define('bt-alert', {
'*': [
{
match: 'success',
cssVars: {backgroundColor: 'green'},
props: {ttl: 3000}
},
{
match: 'warning',
cssVars: {backgroundColor: 'orange'},
props: {ttl: 5000}
}
]
});
So now we can do:
<bt-alert variant="success">I'll disappear after 3 seconds</bt-alert>
But the theme can be overridden by a local value given to the prop:
<bt-alert variant="success" :ttl="5000">I'll disappear after 5 seconds</bt-alert>
So far so good. The problem arises when you try to get the ttl
back to its default value (null
in that instance):
<bt-alert variant="success" :ttl="null">I'll still disappear after 3 seconds!</bt-alert>
Here it doesn't work. The alert will still disappear after 3 seconds.
That's because, internally, VueTypescript
checks if the value still has its default value to decide if it will apply the
value of the theme or not. So when you set it back to null
, because its the same as the default value, it replaces it by the value of the theme (3000
here).
I didn't find a way around this, so it will have to do until a solution is found.
TIP
A workaround this could be to split the variant into two:
VueThemes.Define('bt-alert', {
'*': [
{
id: 'success-base',
match: 'success-no-ttl',
cssVars: {backgroundColor: 'green'}
},
{
match: 'success',
apply: ['success-base'],
props: {ttl: 3000}
}
]
});
Using apply
makes the success
variant inherit from the overrides of success-base
.
You can then use it like this:
<bt-alert variant="success">I'll disappear after 3 seconds</bt-alert>
<bt-alert variant="success-no-ttl">I'll never disappear</bt-alert>