Computed Styles

Computed Styles are useful when you need to create bindings between a CSS or Util property and a component prop.

They can be defined in any place of your css() functions, by turning a property into a function.

That feature comes with an utility function that helps defining the related props.

<script setup>
import { computedStyle } from 'pinceau/runtime'
defineProps({
color: computedStyle('red')
})
</script>
<style scoped lang="ts">
css({
'.my-button': {
backgroundColor: (props) => props.color
}
})
</style>

Context

These functions creates a relation between the static styling of your component and the runtime stylesheet of Pinceau.

Every function gets replaced by a var(--css-variable) in your component CSS.

The function you wrote is moved to your <script setup> block and is bound to that CSS variable value.

It gets converted into a computed that has access to the whole <script setup> context, as if it was written at the very bottom of it.

Defining the component prop

In your computed styles functions, you have access to any part of your <script setup> context, with proper type-safety.

Pinceau provides and helper for you to define computedStyle() props.

<script setup>
import { computedStyle } from 'pinceau/runtime'
import type { PinceauTheme } from 'pinceau'
defineProps({
color: computedStyle<keyof PinceauTheme['color']>('primary')
})
</script>

In that example, the computedStyle prop color will autocomplete all the keys from color object in your theme.

The computedStyle<Generic>() will be used to define the supported values of the prop.

The computedStyle('first-argument') will be used to define the default prop value.

You can optionally pass a boolean as second argument to define the required prop value.

If you are using the Nuxt module, computedStyle will be globally available thanks to auto imports.

Typing the component prop

In the example above, you can see the generic used keyof PinceauTheme['color'].

This type takes advantage of the static typing that Pinceau generates from your theme, PinceauTheme.

That example will type that prop to all the supported colors in your theme colors.

That can be very useful when designing components that are built to support multiple color palettes.

There is two other helpful tyeps that Pinceau provides to type your components from your theme.

  • ThemeTokens<'color'>

ThemeTokens will use the list of all your tokens path, and use its argument to filter the tokens starting with the same paths.

It filters through all your tokens paths using startsWith method.

  • PropertyValue<'backgroundColor'>

PropertyValue will resolve the same type as its argument would resolve in the css() function context.

defineTheme({
color: {
red: 'red',
green: 'green',
blue: 'blue',
primary: {
1: 'purple',
2: 'violet'
}
}
})
const colors: ThemeTokens<'color'> = *
// All the tokens paths that starts with 'color'
const backgroundColors: PropertyValue<'backgroundColor'> = *
// All the tokens paths are mapped to backgroundColor CSS property
// '*' can be:
// 'color.red' | 'color.green' | 'color.blue'
// | 'color.primary.1' | 'color.primary.2'

Using the component prop

Now that you have defined your typed prop, you can consume it inside your computed styles.

You can turn any of your CSS properties into a computed style, including CSS custom properties.

That can be very useful to create single computed styles that updates multiple style properties at once.

This leads your components to have their own internal tokens, and reduces the JavaScript used for styling.

<style lang="ts">
css({
'.my-button': {
'--my-button-color': (props) => props.color,
backgroundColor: '{my.button.color}',
}
})
</style>

Using the component context

As computed styles are regular computed, you have acces and type-safety coming from the <script> context in these functions.

<script setup lang="ts">
import type { PinceauTheme } from 'pinceau'
type ThemeColors = keyof PinceauTheme['color']
const currentColor = ref<ThemeColors>('green')
const setCurrentColor = (value: ThemeColors) => (currentColor.value = value)
</script>
<style lang="ts">
css({
'.my-button': {
backgroundColor: () => currentColor.value
}
})
</style>