Overview of Pinceau VSCode extension
main<script> blocks lighter and <style> blocks smarter within your editor. It provides autocompletion and intelligence specifically for Pinceau-related syntax and features.repository·main·Indexed 20 days ago
https://github.com/tahul/pinceauA typed styling engine and design system tool for Vite-based frameworks including Vue, React, and Svelte. Pinceau provides a robust API for managing design tokens, responsive variants, and theme swapping with SSR optimization. It features a Vite plugin and Nuxt module that allow developers to move styling logic into a structured theme configuration using a typed styling API, a VSCode extension for IntelliSense, and a Pinceau REPL for Vue 3.
<script> blocks lighter and <style> blocks smarter within your editor. It provides autocompletion and intelligence specifically for Pinceau-related syntax and features.Pinceau is a typed styling API designed to make <script> blocks lighter and <style> blocks smarter. It is built for modern design systems and provides:
$styled.a), scoped CSS (styled), and global CSS (css).<script> tags and into a structured theme configuration. It is incrementally adoptable and integrates with existing Vue Single File Components (SFCs).The variants key within the css() function allows you to create reusable component appearances (like size or color variations).
How to implement variants:
variants object into your defineProps() call.variants key to your css() object. Each variant name (e.g., size) contains sub-objects for each option (e.g., sm, md).Usage modes:
<MyComponent size="sm" />.<MyComponent :size="{ initial: 'sm', lg: 'lg' }" />.Example:
<script setup lang="ts">
import { computedStyle } from 'pinceau/runtime'
defineProps({
color: computedStyle<keyof PinceauTheme['color']>('red'),
...variants,
})
</script>
<style scoped lang="ts">
css({
'.my-button': {
display: 'inline-block',
},
'variants': {
size: {
sm: { span: { padding: '{space.3} {space.6}' } },
md: { span: { padding: '{space.6} {space.8}' } },
options: {
default: 'sm',
},
},
},
})
</style>Variants allow you to declare different component appearances that respond to media queries via props. You define them within the variants key at the root of the css() function.
When you define a variant, Pinceau automatically generates the corresponding Vue props. Every key in the variants object becomes a prop name. These props can be passed as simple values (like a string or boolean) or as responsive objects that specify values for different media queries using the initial key.
<script setup lang="ts">
// Spread the generated variants into defineProps
const props = defineProps({
...variants
})
</script>
<template>
<div class="root">
<slot />
</div>
</template>
<style lang="ts">
css({
variants: {
size: {
sm: { padding: '{space.3} {space.6}' },
md: { padding: '{space.6} {space.8}' },
options: { default: 'sm' }
},
},
})
</style>The colorSchemeMode option determines how Pinceau handles dark/light mode. You can choose between 'media' (using CSS media queries) or 'class' (using a CSS class like .dark on a root element).
@media (prefers-color-scheme: dark).:root.dark./* Example of 'class' mode output */
.my-button {
background-color: var(--color-gray-100);
}
:root.dark .my-button {
background-color: var(--color-gray-900);
}While you can define tokens as simple key/value pairs (e.g., myColor: 'red'), you can also use the explicit object syntax (e.g., myColor: { value: 'red' }). Using the value object is optional and has no impact on outputs if used alone, but it becomes useful when you need to:
$schema key for a specific token.// Explicit value syntax
myColor: { value: 'red' }
// Simple syntax (automatically normalized to the above)
myColor: 'red'Pinceau integrates Utils properties directly into the css() function. When you define a utility in your theme, it is treated as a first-class property with full TypeScript autocomplete support.
If a utility returns nested CSS, the compiler unwraps it using the key position as the root.
Example Theme Definition:
defineTheme({
utils: {
mx: value => ({ marginRight: value, marginLeft: value })
}
})Usage in css():
css({
'.my-button': {
// 'mx' will be suggested by autocomplete
mx: 2
}
})Responsive tokens allow you to define how a token's value changes at specific breakpoints or color schemes directly within the theme configuration, rather than handling responsiveness inside individual component styles.
A token is recognized as responsive when its value is an object containing an initial key (the default value used without any media queries) and other keys corresponding to your media queries or color schemes.
Supported keys for responsive tokens include:
media section of your theme.config.dark and light keys for color scheme switching.$color.blue.9).This pattern also applies to Variants and Computed Styles.
export default defineTheme({
primary: {
initial: '$color.blue.9',
dark: '$color.blue.0'
},
blue: {
0: '#C5CDE8',
1: '#B6C1E2',
2: '#99A8D7',
3: '#7B8FCB',
4: '#5E77C0',
5: '#4560B0',
6: '#354A88',
7: '#25345F',
8: '#161E37',
9: '#06080F',
},
})The extension monitors your code for token usage using both the string syntax '{your.token}' and the function syntax $dt('your.token').
If a token's origin cannot be found within your loaded Pinceau configurations, the extension will flag it as a warning in the VSCode Problems panel.
You can customize this behavior in your VSCode settings to either change the severity level of the warning or disable the check entirely.
// Supported syntaxes for detection:
'{your.token}'
$dt('your.token')To make component styles react to props, use Computed Styles. This involves two steps:
computedStyle: Import computedStyle from pinceau/runtime and use it within defineProps. You can provide a type (e.g., keyof PinceauTheme['color']) and a default value.css(): Instead of static values, pass an arrow function to the CSS property. This function receives the props object and returns a token string.Example:
<script setup lang="ts">
import { computedStyle } from 'pinceau/runtime'
defineProps({
color: computedStyle<keyof PinceauTheme['color']>('red'),
})
</script>
<style scoped lang="ts">
css({
'.my-button': {
'--button-primary': props => `{color.${props.color}.600}`,
'--button-secondary': props => `{color.${props.color}.500}`,
}
})
</style>The CSS prop automatically has the local tokens defined within a component injected into it. This allows parent components to easily override a component's internal design tokens by passing them through the css prop.
<template>
<MyButton :css="{ '--button-primary': '{color.red.200}' }" />
</template>