@nyakari/meow
v0.0.6
Published
A Vite plugin that automatically generates CSS custom properties from shorthand syntax and manages theme variations
Maintainers
Readme
Meow
A Vite plugin that generates CSS custom properties from shorthand syntax and manages theme variations via [data-theme] attribute selectors.
npm install -D @nyakari/meowQuick Start
// vite.config.ts
import { defineConfig } from 'vite'
import { meow } from '@nyakari/meow'
export default defineConfig({
plugins: [meow()],
})/* src/styles/theme.css */
$theme default, light {
$bg: #ffffff;
$text: #000000;
$btn {
$bg: #0066cc;
$text: #ffffff;
$p: 8px 16px;
$rounded: 4px;
$weight: 500;
$size: 14px;
:hover {
$bg: #0052a3;
}
:active {
$bg: #004080;
transform: scale(0.97);
}
:disabled {
pointer-events: none;
$opacity: 0.5;
}
}
}
$theme dark {
$bg: #1a1a1a;
$text: #e0e0e0;
$btn {
$bg: #333333;
$text: #ffffff;
$p: 8px 16px;
$rounded: 4px;
$weight: 500;
$size: 14px;
:hover {
$bg: #444444;
}
}
}/* src/styles/components.css */
body {
@use base;
}
.button {
@use btn;
display: inline-flex;
align-items: center;
border: none;
cursor: pointer;
}<body>
<button class="button">Click me</button>
<div data-theme="dark">
<button class="button">Click me</button>
</div>
</body>Generated CSS
:root, [data-theme='light'] {
--bg: #ffffff;
--text: #000000;
--btn-bg: #0066cc;
--btn-text: #ffffff;
--btn-p: 8px 16px;
--btn-rounded: 4px;
--btn-weight: 500;
--btn-size: 14px;
--btn-hover-bg: #0052a3;
--btn-active-bg: #004080;
--btn-disabled-opacity: 0.5;
}
[data-theme='dark'] {
--bg: #1a1a1a;
--text: #e0e0e0;
--btn-bg: #333333;
--btn-text: #ffffff;
--btn-p: 8px 16px;
--btn-rounded: 4px;
--btn-weight: 500;
--btn-size: 14px;
--btn-hover-bg: #444444;
}
body {
background-color: var(--bg);
color: var(--text);
}
.button {
display: inline-flex;
align-items: center;
border: none;
cursor: pointer;
background-color: var(--btn-bg);
color: var(--btn-text);
padding: var(--btn-p);
border-radius: var(--btn-rounded);
font-weight: var(--btn-weight);
font-size: var(--btn-size);
}
.button:hover {
background-color: var(--btn-hover-bg);
}
.button:active {
transform: scale(0.97);
background-color: var(--btn-active-bg);
}
.button:disabled {
pointer-events: none;
opacity: var(--btn-disabled-opacity);
}Syntax
Theme Definition
$theme <name>[, <alias>, ...] { /* comma-separated aliases */
$<prop>: <value>; /* shorthand variable */
<prop>: <value>; /* plain CSS property (passes through) */
$<namespace> { /* grouped namespace */
$<prop>: <value>;
:<pseudo> { ... } /* pseudo-class block (:hover, :active, etc.) */
$<variant> { ... } /* sub-namespace variant */
}
}| Construct | Description |
|-----------|-------------|
| $theme default { } | Generates :root. All other names generate [data-theme="<name>"] |
| $theme default, light { } | Alias — same variables for :root and [data-theme='light'] |
| $theme inside @layer | Entirely supported — keeps your variables in a cascade layer |
| $<prop>: <value>; | Shorthand variable declaration (see shortcuts below) |
| <prop>: <value>; | Plain CSS property — passed through verbatim into the generated rule set |
| $<namespace> { } | Groups variables under a namespace prefix |
| :<pseudo> { } | Defines a pseudo-class block inside a namespace |
| @use <ns> | Injects all variables from a namespace + auto-generates pseudo-class rules |
@use Directive
/* In component CSS files: */
.element {
@use base; /* injects root-level variables (no prefix) */
@use btn; /* injects --btn-* and auto-generates :hover, :active, etc. */
@use btn.sm; /* injects nested variant --btn-sm-* */
@use btn.destructive; /* injects variant --btn-destructive-* */
}When @use btn is used on .element, Meow automatically generates:
.element:hover— from the namespace's:hoverblock.element:active— from:active.element:disabled— from:disabled
This means you do not need separate @use btn.hover rules — it happens automatically.
@use Inside Theme Definitions
Namespaces can compose from other namespaces:
$theme default {
$btn {
$bg: blue;
$p: 8px;
}
$icon {
@use btn; /* inherit all btn variables */
$p: 6px; /* override just padding */
}
}This generates --icon-bg, --icon-text, --icon-p etc., reusing btn's variables.
Property Shortcuts
| Shorthand | CSS Property | Shorthand | CSS Property |
|-----------|-------------|-----------|-------------|
| bg | background-color | text | color |
| m | margin | p | padding |
| mt/mb/ml/mr | margin-* | pt/pb/pl/pr | padding-* |
| mx/my | margin-inline/margin-block | px/py | padding-inline/padding-block |
| border | border | rounded | border-radius |
| w | width | h | height |
| flex | flex | gap | gap |
| shadow | box-shadow | opacity | opacity |
| weight | font-weight | size | font-size |
| leading | line-height | | |
Multi-line values work naturally:
$font: 400 16px 'Nunito',
sans-serif;Deeply Nested Namespaces
Namespaces can nest arbitrarily deep. Each level adds to the CSS variable prefix:
$card {
$nested {
$again { $bg: blue; }
}
}Generates --card-nested-again-bg: blue; — accessible via @use card.nested.again or auto-expanded.
Full Example
@layer base {
$theme default, light {
$btn {
$bg: #0066cc;
$text: #fff;
$p: 6px 12px;
$rounded: 14px;
$weight: 500;
$size: 14px;
corner-shape: squircle;
:hover {
$bg: #0052a3;
}
:active {
$bg: #004080;
transform: translateY(0.5px);
}
:disabled {
pointer-events: none;
$opacity: 0.5;
}
$sm { $p: 4px 8px; $rounded: 6px; $size: 13px; }
$lg { $p: 8px 12px; $size: 16px; $rounded: 20px; }
$base { $bg: gray; :hover { $bg: darkgray; } }
$destructive { $bg: red; :hover { $bg: darkred; } }
}
}
}.button { @use btn; }
.button--sm { @use btn.sm; }
.button--base { @use btn.base; }Generates :hover, :active, :disabled rules automatically for each variant.
Features
- Shorthand variables —
$bg,$p,$roundedetc. map to real CSS properties - Pseudo-class blocks —
:hover,:active,:disabledinside namespaces (colon-prefixed, no$) - Auto pseudo expansion —
@use btnon.Xauto-generates.X:hover,.X:active, etc. - Plain CSS passthrough — standard properties inside theme blocks pass through verbatim
@usecomposition — namespaces can inherit from other namespaces within theme definitions@use base— access root-level variables- Multi-line values — values spanning multiple lines are correctly parsed
- Deeply nested namespaces —
$a { $b { $c {} } }for any depth - Theme aliasing —
$theme default, light { }shares variables across selectors @layersupport —$themeblocks can be wrapped in@layerfor cascade control- Only processes Meow files — regular CSS passes through unchanged
License
MIT
