Skip to content

Conversation

@alessandrobellesia
Copy link
Member

@alessandrobellesia alessandrobellesia commented Dec 29, 2025

[0.1.24] - 2025-12-29

Added

  • CSS Relative Color Syntax support: New color generation system using native CSS hsl(from color h s calc(...)). Brand/accent colors use proportional scaling (l * 1.1), while surface/word colors use fixed steps (l + 12). This significantly reduces the number of CSS variables, improving Chrome DevTools inspector performance.
  • CSS @layer support: Optional cascade layers for better CSS specificity management.
  • Components without CSS custom properties: Option to generate components with hardcoded values instead of CSS variables for maximum performance.
  • New configuration options:
    • $use-color-mix: true - Enable/disable Relative Color Syntax mode (default: true)
    • $use-css-layers: false - Enable/disable CSS @layer cascade management (default: false)
    • $layer-order - Define layer priority order
    • $layer-prefix - Prefix for layer names (default: volver)
    • $use-custom-props-for-components: true - Enable/disable CSS variables in components (default: true)
  • New color functions: relative-color-value(), color-mix-shades-map(), color-mix-darken-map(), color-mix-lighten-map(), color-mix-alpha-map()

Changed

  • Migrated if() function calls to new Sass CSS-compatible syntax (if(sass($condition): $value; else: $fallback))
  • Color shades now use single --color-{name} variable with Relative Color Syntax instead of separate -hue, -saturation, -lightness variables
  • Updated box-shadow, glass effects, and component modifiers to use modern CSS color functions

Fixed

  • Reduced CSS output size and number of CSS custom properties for better browser DevTools performance

Summary by CodeRabbit

  • New Features

    • CSS Relative Color Syntax mode for programmatic shade generation and new color-mix utilities.
    • Optional CSS Layers system with configurable order and prefix; components, props and utilities can be layered.
    • New public color variables (e.g., danger, info).
  • Changes

    • Palette and shadow rendering moved to mix-based color computations; secondary button and card glass visuals adjusted.
    • Package metadata updated (engine and tooling versions).
  • Documentation

    • README and docs updated with Relative Color Syntax and CSS Layers guidance.
  • Chores

    • Dev dependency upgrades and export map adjustments.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 29, 2025

Walkthrough

Adds opt-in CSS Layers and CSS Relative Color Syntax; reorganizes and forwards SCSS mixins into modular mixin-modules; introduces color-mix/relative color utilities and conditional color maps; wraps most SCSS outputs in layer blocks; refactors theme application to spread-theme-component; updates auto-import typings and ESLint auto-import globals.

Changes

Cohort / File(s) Summary
Config & Tooling
package.json, postcss.config.cjs, .eslintrc-auto-import.json
Bump engines.node to ">=20.x", update packageManager and devDependencies; add cascade-layers: false flag in postcss preset features; remove resolveUnref: true global from ESLint auto-import globals.
Feature Flags & Core Config
src/_config.scss, src/_layers.scss
Add $use-color-mix, $use-css-layers, $layer-order, $layer-prefix; new src/_layers.scss to define layers when enabled.
Layering Base & Preflight
src/reset.scss, src/_preflight.scss, src/volver.scss, src/_layers.scss
Add @use 'context'/layers import and wrap reset/preflight/base with @include layer(...) or define-layers to centralize layer ordering.
Bulk Layer Wrapping
src/components/*.scss, src/props/*.scss, src/utilities/*.scss, src/settings/*, src/themes/**
Wrap many component, props, utilities, settings, and theme SCSS files inside @include layer(...) blocks (scoping outputs to configured layers).
Color System & Functions
src/tools/_functions.scss, src/settings/_colors.scss, src/themes/dark/settings/_colors.scss, src/settings/_effects.scss
Add CSS relative color and color-mix helper functions (shade/alpha generators); conditional color-map construction driven by $use-color-mix; replace several HSL shadows/backgrounds with color-mix(); add $color-danger and $color-info.
Mixin Reorganization
src/tools/_mixins.scss, src/tools/mixin-modules/*, src/tools/mixin-modules/_index.scss
Move and forward mixins into new mixin-modules submodules; add modules and mixins: layer, define-layers, wrap-with-where, spread-map-into-props, spread-map-into-utilities, spread-map-into-attrs, spread-map-into-bem, spread-theme-component, and related helpers; src/tools/_mixins.scss now forwards mixin-modules.
BEM / Attributes / Utilities Modules
src/tools/mixin-modules/_bem.scss, _attrs.scss, _props.scss, _utilities.scss, _helpers.scss, _layers.scss, _theme.scss
New mixin modules implementing BEM generation, attribute rendering, props/to-utilities spreading, layer helpers, theme spreading (including extract-light-values and spread-theme-component), and wrap-with-where.
Theme Refactor
src/themes/dark/components/*.scss, src/themes/dark/props/*, src/themes/dark/settings/*
Replace spread-map theming with spread-theme-component, re-nest dark theme rules inside theme layers, and conditional dark color maps keyed to $use-color-mix.
Component-specific tweaks
src/settings/components/*, src/components/*, docs/components/ColorPalette.vue
Adjust several modifiers to use color-mix() or --color-surface; ColorPalette refactor: single colorVar CSS var, unified reads/writes and safer RGB parsing; small text/color additions (e.g., headline color).
Build/Exports & Auto-imports
auto-imports.d.ts, package.json, .eslintrc-auto-import.json
Convert bracketed typeof import(...)['Name'] references to dot-notation typeof import(...).Name; remove Vue resolveUnref from public/ComponentCustomProperties typings and ESLint globals.
Utilities & Minor Fixes
src/tools/_breakpoints.scss, src/utilities/transforms.scss, src/export.scss
Make breakpoint helpers explicit with @if/@else; escape slashes in transform utility selectors; preserve escaped slashes in translation key generation (remove key normalization of \/ -> /).
Docs & Changelog
README.md, CHANGELOG.md, docs/contents/*, docs/App.vue
Document Relative Color Syntax Mode and CSS Layers; add CHANGELOG entry v0.1.24; update docs examples and docs/App.vue SCSS context map flags.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

🐰 In layers I hop, where colors entwine,
I mix and I blend with a carrot-shaped line,
New maps and mixins, a tidy, bright stew,
I hop through the PR — a small rabbit review! 🥕✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Implement CSS @layer cascade and color-mix features' accurately and concisely summarizes the main changes: introduction of CSS @layer support and CSS Relative Color Syntax (color-mix) features as primary objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/layers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Alessandro Bellesia added 2 commits December 29, 2025 18:08
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/settings/_effects.scss (1)

25-27: Invalid Sass function calls — missing module prefix.

The functions color-hue(), color-saturation(), and color-lightness() should use the color module prefix since you're using @use 'sass:color'. The current syntax will fail to compile in modern Sass.

🔎 Proposed fix
-$color-shadow-hue: color-hue(colors.$color-shadow);
-$color-shadow-saturation: color-saturation(colors.$color-shadow);
-$color-shadow-lightness: color-lightness(colors.$color-shadow);
+$color-shadow-hue: color.hue(colors.$color-shadow);
+$color-shadow-saturation: color.saturation(colors.$color-shadow);
+$color-shadow-lightness: color.lightness(colors.$color-shadow);
🧹 Nitpick comments (15)
auto-imports.d.ts (1)

91-96: Inconsistent syntax on line 96.

Line 96 (resolveUnref) still uses bracket notation ['resolveUnref'] while the surrounding declarations (lines 9-95, 97-304) were updated to dot notation (.Name). Since this is a generated file, consider regenerating to ensure consistency, or verify this was intentional.

🔎 Suggested fix for consistency
-  const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
+  const resolveUnref: typeof import('@vueuse/core').resolveUnref
docs/contents/get-started/configuration.md (1)

75-119: Excellent documentation for CSS Layers feature.

The documentation clearly explains the CSS @layer feature, configuration options, layer order, and browser support requirements. The code examples are helpful and the structure is easy to follow.

Optional enhancement: Document fallback behavior

Consider adding a brief note about what happens when $use-css-layers: true is used in older browsers. For example:

#### Browser Support

CSS `@layer` is supported in all modern browsers (Chrome 99+, Firefox 97+, Safari 15.4+, Edge 99+). 

**Note:** In browsers that don't support `@layer`, the styles will still work but the explicit cascade ordering will be ignored, falling back to standard CSS cascade rules. For older browsers, consider keeping `$use-css-layers: false` (the default).
README.md (1)

86-94: Consider updating this example for consistency with the new default.

This "Custom props" example still shows the legacy HSL variable approach (--color-brand-hue, --color-brand-saturation, --color-brand-lightness). Since $use-color-mix: true is now the default, users would typically just set --color-brand directly. Consider either updating this example to reflect the new approach or adding a note clarifying this is for legacy mode.

src/components/vv-skeleton.scss (1)

7-7: Remove unused variable $component-selector.

The variable is defined on line 7 but is never used within vv-skeleton.scss. Unlike other component files that reference this variable, it serves no purpose here and can be safely removed.

src/settings/components/_vv-badge.scss (1)

70-76: Updated to use color-mix() for semi-transparent white/black backgrounds.

The color-mix(in srgb, var(--color-white), transparent 20%) syntax is valid CSS Color Level 5 with strong modern browser support (Chrome 111+, Edge 111+, Firefox 113+, Safari 16.2+). Consider adding a plain-color fallback or @supports() feature query if the project targets older browsers, as support is ~92% globally but not universal in legacy environments.

src/tools/_breakpoints.scss (4)

20-24: LGTM! Improved code clarity.

The refactoring from implicit returns to explicit @if/@else blocks makes the null-handling and boundary conditions clearer. The logic remains functionally identical—returning the next breakpoint name when it exists, or null for the last breakpoint.


37-41: LGTM! Clearer zero-value handling.

The explicit conditional block makes it immediately clear that zero-valued breakpoints (typically for the smallest breakpoint like xs: 0) are treated as having no minimum and return null. Functionally equivalent to the previous implementation.


59-63: LGTM! Explicit max boundary calculation.

The refactoring makes the Safari rounding workaround (subtracting 0.02px from the next breakpoint's minimum) more explicit and easier to understand. The logic remains identical.


77-81: LGTM! Clear infix logic for responsive utilities.

The explicit conditional makes it clear when an empty string is returned (smallest breakpoint) versus a dash-prefixed name (all other breakpoints). This is important for generating responsive utility class names. Logic is preserved.

src/tools/mixin-modules/_helpers.scss (1)

12-14: Consider edge case handling for selector coercion.

The string interpolation #{$selector} for map/list types may not handle complex nested structures or special characters consistently. For selectors containing commas (e.g., multiple selectors as a list), the interpolation could produce unexpected results.

🔎 Consider adding validation or flattening logic
 @if meta.type-of($selector) == 'map' or meta.type-of($selector) == 'list' {
-	$selector: #{$selector};
+	// Convert list of selectors to comma-separated string
+	$selector: meta.inspect($selector);
+	$selector: string.slice($selector, 2, -2); // Remove parentheses if present
 }

Alternatively, document the expected input format for list/map types to clarify usage.

docs/contents/settings/colors.md (1)

108-109: Minor: Comment could be more specific.

The comment "Surface uses fixed steps (addition/subtraction)" is accurate but the example only shows subtraction. Consider adding an addition example for completeness, or update the comment to match the single example.

-  /* Surface uses fixed steps (addition/subtraction) */
+  /* Surface uses fixed steps (+12 for lighter, -12 for darker) */
   --color-surface-6: hsl(from var(--color-surface) h s calc(l - 12));
src/tools/mixin-modules/_utilities.scss (1)

33-37: Hardcoded backslash escaping may need configuration.

Line 36 hardcodes the backslash escape for breakpoint prefixes ($breakpoint + '\\:'), following Tailwind's convention. This works for CSS but assumes all consumers want this format.

Consider making the separator configurable if different naming conventions are needed:

 @mixin spread-map-into-utilities(
   $map: (),
   $class: '',
   $attribute: '',
   $prop: '',
   $name: '',
   $deep: true,
   $bps: (xxs: 0),
   $prefix: '',
-  $zero-specificity: false
+  $zero-specificity: false,
+  $bp-separator: '\\:'
 ) {
   @if (meta.type-of($map) == 'map' or meta.type-of($map) == 'list') and $attribute != '' {
     @each $breakpoint, $breakpoint-value in $bps {
       @if $breakpoint-value > 0 {
-        $prefix: $breakpoint + '\\:';
+        $prefix: $breakpoint + $bp-separator;
       }
src/tools/mixin-modules/_layers.scss (1)

25-41: Consider using Sass list interpolation for cleaner layer list generation.

The manual string concatenation works, but Sass provides built-in list handling that could simplify this.

🔎 Optional refactor using list.join()
+@use 'sass:list';
+
 @mixin define-layers($enabled: false, $order: (reset, props, utilities, components, themes), $prefix: 'volver') {
 	@if $enabled {
-		$layers: null;
-
-		@each $name in $order {
-			$layer-name: $prefix + '.' + $name;
-
-			@if $layers {
-				$layers: $layers + ', ' + $layer-name;
-			} @else {
-				$layers: $layer-name;
-			}
-		}
+		$layers: ();
+		@each $name in $order {
+			$layers: list.append($layers, #{$prefix}.#{$name}, comma);
+		}
 
 		/* stylelint-disable-next-line layer-name-pattern */
 		@layer #{$layers};
 	}
 }
src/tools/mixin-modules/_attrs.scss (2)

44-57: Consider consolidating vendor-prefixed pseudo-elements.

The $-pseudo-elements list includes both unprefixed (progress-bar) and vendor-prefixed (-webkit-progress-bar, -moz-progress-bar) variants. Since pseudo-element-placeholder already handles vendor prefixing for the unprefixed names, the explicit vendor-prefixed entries may cause redundant selector generation when used elsewhere.


80-88: Variable shadowing: $original is reassigned within the loop.

Reassigning the parameter $original at line 84 shadows the outer value. While functional due to Sass scoping, this reduces clarity. Consider using a distinct variable name like $nested-original.

🔎 Suggested improvement
 @if meta.type-of($value) == 'map' and ($deep or $key == 'pseudo') {
-	$original: map.get($original, $key);
+	$nested-original: map.get($original, $key);

-	@if not $original {
-		$original: ();
+	@if not $nested-original {
+		$nested-original: ();
 	}

Then use $nested-original in subsequent lines within this block.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1895f26 and 69f0bed.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (107)
  • .eslintrc-auto-import.json
  • CHANGELOG.md
  • README.md
  • auto-imports.d.ts
  • docs/App.vue
  • docs/components/ColorPalette.vue
  • docs/contents/get-started/configuration.md
  • docs/contents/settings/colors.md
  • package.json
  • postcss.config.cjs
  • src/_config.scss
  • src/_layers.scss
  • src/_preflight.scss
  • src/components/vv-accordion-group.scss
  • src/components/vv-accordion.scss
  • src/components/vv-alert-group.scss
  • src/components/vv-alert.scss
  • src/components/vv-avatar-group.scss
  • src/components/vv-avatar.scss
  • src/components/vv-badge.scss
  • src/components/vv-breadcrumb.scss
  • src/components/vv-button-group.scss
  • src/components/vv-button.scss
  • src/components/vv-card.scss
  • src/components/vv-checkbox-group.scss
  • src/components/vv-checkbox.scss
  • src/components/vv-dialog.scss
  • src/components/vv-dropdown-action.scss
  • src/components/vv-dropdown-optgroup.scss
  • src/components/vv-dropdown-option.scss
  • src/components/vv-dropdown.scss
  • src/components/vv-input-file.scss
  • src/components/vv-input-text.scss
  • src/components/vv-nav.scss
  • src/components/vv-progress.scss
  • src/components/vv-radio-group.scss
  • src/components/vv-radio.scss
  • src/components/vv-select.scss
  • src/components/vv-skeleton.scss
  • src/components/vv-tab.scss
  • src/components/vv-table.scss
  • src/components/vv-text.scss
  • src/components/vv-textarea.scss
  • src/components/vv-tooltip.scss
  • src/export.scss
  • src/props/background.scss
  • src/props/borders.scss
  • src/props/breakpoints.scss
  • src/props/colors.scss
  • src/props/effects.scss
  • src/props/filters.scss
  • src/props/input.scss
  • src/props/layout.scss
  • src/props/sizing.scss
  • src/props/spacing.scss
  • src/props/transitions.scss
  • src/props/typography.scss
  • src/reset.scss
  • src/settings/_colors.scss
  • src/settings/_effects.scss
  • src/settings/components/_vv-badge.scss
  • src/settings/components/_vv-button.scss
  • src/settings/components/_vv-card.scss
  • src/settings/components/_vv-nav.scss
  • src/settings/components/_vv-text.scss
  • src/themes/dark/components/_vv-alert.scss
  • src/themes/dark/components/_vv-avatar.scss
  • src/themes/dark/components/_vv-badge.scss
  • src/themes/dark/components/_vv-button.scss
  • src/themes/dark/components/_vv-dropdown-action.scss
  • src/themes/dark/components/_vv-dropdown-option.scss
  • src/themes/dark/components/_vv-nav.scss
  • src/themes/dark/components/_vv-select.scss
  • src/themes/dark/props/_background.scss
  • src/themes/dark/props/_colors.scss
  • src/themes/dark/props/_input.scss
  • src/themes/dark/settings/_colors.scss
  • src/themes/dark/settings/components/_vv-alert.scss
  • src/themes/dark/settings/components/_vv-avatar.scss
  • src/themes/dark/settings/components/_vv-button.scss
  • src/tools/_breakpoints.scss
  • src/tools/_functions.scss
  • src/tools/_mixins.scss
  • src/tools/mixin-modules/_attrs.scss
  • src/tools/mixin-modules/_bem.scss
  • src/tools/mixin-modules/_helpers.scss
  • src/tools/mixin-modules/_index.scss
  • src/tools/mixin-modules/_layers.scss
  • src/tools/mixin-modules/_props.scss
  • src/tools/mixin-modules/_theme.scss
  • src/tools/mixin-modules/_utilities.scss
  • src/utilities/backgrounds.scss
  • src/utilities/borders.scss
  • src/utilities/colors.scss
  • src/utilities/effects.scss
  • src/utilities/filters.scss
  • src/utilities/flexbox.scss
  • src/utilities/grid.scss
  • src/utilities/interactivity.scss
  • src/utilities/layout.scss
  • src/utilities/sizing.scss
  • src/utilities/spacing.scss
  • src/utilities/tables.scss
  • src/utilities/transforms.scss
  • src/utilities/transitions.scss
  • src/utilities/typography.scss
  • src/volver.scss
💤 Files with no reviewable changes (1)
  • src/themes/dark/settings/components/_vv-button.scss
🔇 Additional comments (116)
auto-imports.d.ts (2)

400-400: LGTM!

The refManualReset addition to ComponentCustomProperties is correctly placed alphabetically and uses consistent bracket notation with the rest of this section.


1-7: Generated file committed — ensure regeneration process is documented.

This file is auto-generated by unplugin-auto-import. Verify that:

  1. The generation config has been updated to include refManualReset
  2. CI/build process regenerates this file to prevent manual drift
src/components/vv-textarea.scss (1)

5-5: LGTM - CSS layer wrapper applied correctly.

The component is now properly scoped within the CSS layers system using the layer() mixin. The internal component logic remains unchanged, and the implementation aligns with the broader PR pattern.

Also applies to: 100-101

src/props/filters.scss (1)

3-9: LGTM - Props correctly scoped within CSS layer.

The property definitions are now properly wrapped within the props layer context while preserving the existing :where(:host, :root, .theme) selector structure.

CHANGELOG.md (1)

5-26: Comprehensive changelog entry.

The version 0.1.24 entry thoroughly documents the new CSS Relative Color Syntax support, CSS layers, configuration options, and migration notes. The comparison link is properly formatted.

Also applies to: 298-298

src/props/effects.scss (1)

3-8: LGTM - Effects props correctly layered.

The box-shadow and opacity properties are now properly scoped within the props layer, maintaining the existing property generation logic.

src/components/vv-dropdown-optgroup.scss (1)

4-4: LGTM - Component properly wrapped in CSS layer.

The dropdown optgroup component is now correctly scoped within the components layer, consistent with the broader CSS layers implementation across the codebase.

Also applies to: 15-16

postcss.config.cjs (1)

18-18: Browser support is determined by consuming projects, not this library.

This is a CSS utility library with no explicit browserslist configuration. Browser support for @layer syntax is not a concern for the library itself—consuming projects will apply their own PostCSS transformations based on their own browser targets. The setting 'cascade-layers': false preserves @layer rules for downstream build tools to handle according to their own requirements.

Likely an incorrect or invalid review comment.

src/settings/components/_vv-button.scss (1)

92-92: This change is an intentional part of the v0.1.24 color system refactor to semantic colors.

The --color-surface variable is properly defined in src/settings/_colors.scss using the new Relative Color Syntax system. In the light theme, it evaluates to white (matching the previous var(--color-white)), ensuring backward-compatible visual appearance. In the dark theme, --color-surface intentionally uses a very dark background, which is the correct semantic choice for secondary buttons in that theme. This is documented in the CHANGELOG as part of the migration from literal color names to semantic color variables for improved theming flexibility.

src/settings/_effects.scss (1)

6-22: LGTM! Clean migration to color-mix() for shadow transparency.

The box-shadow definitions now use modern CSS color-mix() with the --color-shadow variable, aligning with the PR's goal to reduce CSS custom properties and leverage native CSS color functions.

README.md (1)

111-139: Good documentation for the new Relative Color Syntax feature.

The examples clearly illustrate the difference between proportional scaling for brand colors and fixed steps for surface/word colors.

src/themes/dark/settings/components/_vv-alert.scss (1)

60-109: LGTM! Consistent header text contrast for notification modifiers.

Adding color: var(--color-white) to all notification header variants ensures readable text on colored backgrounds in dark theme. The pattern is consistently applied across danger, brand, success, accent, warning, and info modifiers.

src/tools/_mixins.scss (1)

1-6: LGTM! Clean refactoring to a façade pattern.

Re-exporting all mixins via @forward 'mixin-modules' maintains backward compatibility while consolidating implementations in the new module structure. Consumers can continue using @use '@volverjs/style/scss/mixins' without changes.

package.json (1)

112-139: LGTM! Props export mappings properly added.

The new export entries follow the established pattern and expand the public API to allow consumers to import individual props modules (typography, transitions, spacing, etc.) both as CSS and SCSS.

src/components/vv-dropdown-action.scss (1)

4-16: LGTM! Proper CSS layer scoping applied.

The component styles are correctly wrapped with the layer() mixin, enabling optional cascade layer support when $use-css-layers is true.

src/components/vv-skeleton.scss (1)

4-17: LGTM! CSS layer scoping applied correctly.

The layer wrapper follows the same pattern as other components.

src/settings/components/_vv-text.scss (1)

6-13: LGTM! Explicit color for headline modifier.

Adding color: var(--color-word) ensures headlines use the semantic text color variable, improving theme consistency and making the text color explicit rather than relying on inheritance.

src/components/vv-alert-group.scss (1)

4-16: LGTM! CSS layer wrapper correctly applied.

The component styles are now scoped under the components layer when $use-css-layers is enabled. The internal logic remains unchanged, and the layer block is properly opened and closed.

src/components/vv-input-text.scss (1)

5-101: LGTM! Layer wrapper correctly encompasses complex component logic.

The entire vv-input-text component, including its state management logic for disabled and readonly states, is now properly scoped within the components layer. All existing functionality is preserved.

src/components/vv-radio-group.scss (1)

4-16: LGTM! Consistent layer implementation.

The vv-radio-group component follows the same layer-scoping pattern as other components, correctly wrapping styles under the components layer.

src/components/vv-tab.scss (1)

4-16: LGTM! Layer wrapper correctly applied.

The vv-tab component styles are properly scoped within the components layer, maintaining consistency with other components in this PR.

src/components/vv-accordion.scss (1)

4-16: LGTM! Layer wrapper correctly applied.

The vv-accordion component is properly wrapped within the components layer, following the consistent pattern applied across all components in this PR.

src/components/vv-alert.scss (1)

4-16: LGTM! Consistent layer implementation.

The vv-alert component correctly follows the layer-scoping pattern, wrapping all styles under the components layer when $use-css-layers is enabled.

src/utilities/typography.scss (1)

4-268: LGTM! Typography utilities correctly scoped under utilities layer.

All typography utilities are now properly wrapped within the utilities layer (note: correctly using 'utilities' rather than 'components'), which aligns with the CSS layer architecture for separating utility classes from component styles. The extensive typography utility definitions remain unchanged and intact.

src/themes/dark/settings/components/_vv-avatar.scss (1)

24-26: New surface modifier follows color system conventions.

The surface modifier is correctly added to the ring modifiers group, using var(--color-word-2) which aligns with the new surface/word color palette introduced in this PR. The variable is properly defined through the color map generation system.

src/components/vv-checkbox-group.scss (1)

4-4: LGTM: Consistent layer integration.

The component correctly adopts the CSS layer pattern matching other components in this PR.

Also applies to: 15-16

src/utilities/layout.scss (1)

5-5: LGTM: Utilities correctly scoped to their layer.

All layout utilities are now properly wrapped in the utilities layer, maintaining the appropriate separation from component and prop layers.

Also applies to: 208-209

src/components/vv-accordion-group.scss (1)

4-4: LGTM: Layer integration applied consistently.

Also applies to: 15-16

src/components/vv-avatar.scss (1)

4-4: LGTM: Layer integration applied consistently.

Also applies to: 15-16

src/props/background.scss (1)

3-8: LGTM: Props correctly scoped to their layer.

The background and gradient property mappings are now properly wrapped in the props layer, with correct indentation maintained for the nested :where(:host, :root, .theme) selector.

src/volver.scss (1)

1-2: LGTM: Layer order definition correctly positioned.

The explicit layers import is properly placed at the top of the entry file with a clear comment explaining the requirement. CSS layer order must be established before any layered styles are defined, making this positioning critical for the cascade layer system to function correctly.

src/components/vv-input-file.scss (1)

5-5: LGTM: Layer integration applied consistently.

The component, including its disabled/readonly state handling logic, is now properly scoped within the components layer.

Also applies to: 100-101

src/components/vv-button.scss (1)

4-4: CSS layer integration applied correctly.

The component is properly scoped within the components layer using the configuration-driven approach. The layer mixin is defined in src/tools/mixin-modules/_layers.scss, and both configuration variables ($use-css-layers and $layer-prefix) are defined in src/_config.scss and exported via the imported context file. All dependencies are available in scope.

src/themes/dark/props/_background.scss (1)

7-18: LGTM!

The CSS layer wrapper is correctly applied around the dark theme background rules. The themes layer name is semantically appropriate, and the inner logic remains unchanged.

src/utilities/flexbox.scss (1)

5-5: LGTM!

The layer wrapper correctly scopes all flexbox utilities under the utilities layer. The existing utility definitions remain functionally unchanged.

Also applies to: 138-139

src/utilities/effects.scss (1)

3-3: LGTM!

The layer wrapper correctly scopes all effect utilities (box-shadow, opacity, blend modes) under the utilities layer, consistent with other utility files.

Also applies to: 35-36

src/utilities/backgrounds.scss (1)

3-3: LGTM!

Background utilities are correctly wrapped in the utilities layer, following the consistent pattern established across all utility files.

Also applies to: 69-70

src/components/vv-button-group.scss (1)

4-4: LGTM!

The button group component is correctly wrapped in the components layer. All the complex modifier logic (block, compact, vertical) remains intact within the layer scope.

Also applies to: 114-115

src/components/vv-nav.scss (1)

4-4: LGTM!

The nav component is correctly wrapped in the components layer, following the established pattern for component files.

Also applies to: 15-16

src/components/vv-text.scss (1)

4-4: LGTM!

The text component is correctly wrapped in the components layer, consistent with all other component files in this PR.

Also applies to: 15-16

src/components/vv-progress.scss (1)

4-4: LGTM! Component layer wrapping applied correctly.

The vv-progress component is now properly scoped under the components layer, consistent with the broader CSS layers architecture introduced in this PR.

Also applies to: 15-16

src/utilities/grid.scss (1)

4-4: LGTM! Layer wrapping applied correctly.

The grid utilities are now properly scoped under the utilities layer, following the same pattern as other utility files.

Also applies to: 86-87

src/utilities/tables.scss (1)

3-3: LGTM! Layer wrapping applied correctly.

The table utilities are now properly scoped under the utilities layer, consistent with other utility modules.

Also applies to: 19-20

src/components/vv-table.scss (1)

4-4: LGTM! Component layer wrapping applied correctly.

The vv-table component is now properly scoped under the components layer.

Also applies to: 15-16

src/components/vv-dropdown-option.scss (1)

4-4: LGTM! Component layer wrapping applied correctly.

The vv-dropdown-option component is now properly scoped under the components layer.

Also applies to: 15-16

src/components/vv-breadcrumb.scss (1)

4-4: LGTM! Component layer wrapping applied correctly.

The vv-breadcrumb component is now properly scoped under the components layer.

Also applies to: 15-16

src/_preflight.scss (1)

12-12: LGTM! Preflight layer wrapping applied correctly.

The preflight styles are now properly scoped under the preflight layer. This is an appropriate layer designation for base reset/normalization styles, allowing them to be positioned early in the cascade order.

Also applies to: 452-452

src/utilities/spacing.scss (1)

5-5: Layer wrapping applied correctly.

The spacing utilities are now properly scoped under the utilities layer. The layer() mixin is correctly defined in src/tools/mixin-modules/_layers.scss, and both required configuration variables ($use-css-layers and $layer-prefix) are defined in src/_config.scss. The wrapping is clean with proper opening at line 5 and closing at line 121, and the internal logic remains unchanged.

src/components/vv-checkbox.scss (1)

4-32: LGTM! Clean layer integration.

The component is correctly wrapped in the CSS layer scope. The internal logic remains unchanged, and the opening/closing braces are properly balanced.

src/components/vv-select.scss (1)

5-101: LGTM! Consistent layer integration.

The component follows the same layer-wrapping pattern as other components in this PR. Structure is sound and internal logic is preserved.

src/components/vv-dialog.scss (1)

4-16: LGTM! Proper layer scoping applied.

The layer wrapper is correctly implemented with balanced braces and unchanged internal logic.

docs/App.vue (1)

20-22: LGTM! Good test configuration.

Enabling $use-css-layers: true and $use-custom-props-for-components: false in the documentation app provides an excellent test bed for the new CSS layer and performance optimization features.

src/utilities/interactivity.scss (1)

4-29: LGTM! Utilities properly layered.

The utilities are correctly scoped under the utilities layer. Structure is sound and utility logic is preserved.

src/utilities/sizing.scss (1)

4-89: LGTM! Consistent utility layer integration.

The sizing utilities follow the same layer pattern as other utility files. All opening/closing braces are balanced, and the internal logic remains intact.

src/components/vv-dropdown.scss (1)

4-16: LGTM! Layer wrapping applied correctly.

The dropdown component is properly scoped within the CSS layer with balanced braces and preserved internal logic.

src/components/vv-avatar-group.scss (1)

4-16: LGTM! Consistent layer implementation.

The avatar group component follows the same mechanical pattern as all other components in this PR. Structure is correct and internal logic is unchanged.

src/themes/dark/props/_input.scss (1)

7-18: LGTM! CSS layer integration is correct.

The layer wrapper appropriately scopes dark input theme styles under the themes layer, maintaining all existing selectors and media query logic while enabling cascade layer management.

src/themes/dark/props/_colors.scss (1)

7-18: LGTM! Consistent layer integration for dark theme colors.

The layer wrapper correctly scopes dark color theme styles under the themes layer, consistent with the pattern used across other theme files.

src/props/colors.scss (1)

3-7: LGTM! Proper layer scoping for color properties.

The layer wrapper correctly places color property definitions in the props layer, which appropriately precedes the themes layer in the cascade order.

src/utilities/transitions.scss (1)

5-51: LGTM! Utilities correctly scoped to highest specificity layer.

The layer wrapper places transition utilities in the utilities layer, which appropriately comes last in the cascade order, allowing utilities to override component and theme styles as expected.

src/components/vv-badge.scss (1)

4-16: LGTM! Component correctly scoped to components layer.

The layer wrapper appropriately places the badge component in the components layer, maintaining proper cascade order between base props and theme overrides.

src/props/layout.scss (1)

3-8: LGTM! Layout properties correctly scoped to props layer.

The layer wrapper maintains consistency with other property files by placing layout properties in the props layer, ensuring proper cascade order.

src/_layers.scss (1)

1-4: No action needed—CSS layer initialization is already correctly positioned.

The file is already imported first in the main entry point (volver.scss) before any files that use @include layer(...). The dependency order is correct, and the layer order will be established before any styles are emitted to layers.

src/settings/components/_vv-nav.scss (1)

125-125: Confirm that the project's target browser matrix supports color-mix() (Chrome 111+, Firefox 113+, Safari 16.2+), or add a fallback for older browser versions if required.

The color-mix() function is well-established in modern browsers (supported since late 2022–early 2023). Ensure your browser support policy explicitly includes these versions; if not, provide a fallback.

src/props/input.scss (1)

3-7: LGTM! Clean layer integration.

The input props are now properly scoped within the CSS props layer. The wrapping is consistent with the broader CSS Layers architecture introduced in this PR, and the inner logic remains unchanged.

src/utilities/colors.scss (1)

3-40: LGTM! Utilities properly layered.

All color utilities (background, text, decoration, border) are now consistently scoped within the utilities layer, aligning with the CSS Layers architecture. The utility generation logic remains intact.

src/utilities/borders.scss (1)

4-93: LGTM! Border utilities correctly layered.

The border utilities (radius, width, style) and their directional variants are now properly scoped within the utilities layer. The complex nested loops for generating directional utilities remain functionally unchanged.

src/props/borders.scss (1)

3-8: LGTM! Border props layered correctly.

Border-related CSS custom properties are now scoped within the props layer, consistent with other prop files in this PR. The property generation logic is preserved.

src/props/spacing.scss (1)

4-29: LGTM! Spacing props with responsive logic properly layered.

The spacing props, including both static and dynamic responsive variants, are now scoped within the props layer. The complex breakpoint-driven dynamic spacing logic and conditional handling remain functionally intact.

src/utilities/filters.scss (1)

3-36: LGTM! Filter utilities layered consistently.

Filter utilities (blur, brightness, saturate, backdrop-blur) are now properly scoped within the utilities layer, maintaining consistency with the other utility files in this PR.

src/reset.scss (2)

1-3: LGTM! Reset layer properly configured.

The addition of the context module import enables access to the layer() mixin, and the reset styles are now correctly scoped within the reset layer. This aligns with CSS Layers best practices for managing cascade order.


4-101: LGTM! Reset styles preserved.

All reset rules remain functionally unchanged while now being scoped within the CSS layer. The complex :where selectors and attribute-based rules are properly maintained.

src/components/vv-card.scss (1)

4-16: LGTM! Clean layer encapsulation.

The component styles are correctly wrapped in the CSS layer context using the components layer, aligning with the PR's architecture for optional cascade layer management.

src/props/breakpoints.scss (1)

4-18: LGTM! Breakpoint properties correctly layered.

The breakpoint properties are properly encapsulated in the props layer, maintaining the existing logic while enabling optional layer-based specificity control.

src/props/sizing.scss (1)

3-8: LGTM! Sizing properties correctly layered.

The width and height properties are properly wrapped in the props layer, consistent with the broader layering strategy.

src/components/vv-radio.scss (1)

4-24: LGTM! Radio component correctly layered.

The vv-radio component styles are properly encapsulated in the components layer without modifying the internal BEM structure or disabled state handling.

src/tools/mixin-modules/_index.scss (1)

1-25: Excellent centralized mixin index.

This index module provides a clean, single-import interface for all mixin utilities, improving developer experience and maintainability. The documentation comments clearly indicate what each forwarded module provides.

src/props/typography.scss (1)

4-41: LGTM! Typography properties correctly layered.

The typography properties, including static and responsive font-size mappings, are properly encapsulated in the props layer. The breakpoint handling and dynamic font-size logic remain intact.

src/themes/dark/components/_vv-avatar.scss (2)

7-13: LGTM! Updated to use spread-theme-component.

The mixin correctly migrates to the new spread-theme-component helper, consolidating theme component logic and aligning with the PR's refactored theme system.


16-26: LGTM! Dark theme correctly layered.

The dark theme logic is properly wrapped in the themes layer while maintaining both automatic (prefers-color-scheme) and explicit (.theme--dark) dark mode paths.

src/settings/components/_vv-card.scss (1)

48-56: Modern color-mix implementation for glass effects.

The glass modifier correctly uses CSS color-mix() with appropriate transparency levels (40% for main background, 70% for header/footer), creating the intended glass aesthetic. This syntax is widely supported in modern browsers (Chrome/Edge 111+, Firefox 113+, Safari 16.2+) and marked as baseline/widely available per MDN. If targeting older browsers, consider providing a fallback background color via a @supports feature query.

src/tools/mixin-modules/_helpers.scss (1)

16-18: LGTM!

The conditional :where() wrapper correctly implements zero-specificity when enabled. The string.unquote ensures the selector string is properly formatted for CSS output.

src/utilities/transforms.scss (1)

3-3: LGTM - Layer wrapper correctly applied.

The utilities are properly wrapped in the CSS layer using the new configuration flags. This enables cascade management when $use-css-layers is enabled.

Also applies to: 127-127

src/props/transitions.scss (1)

51-169: LGTM - Keyframes definitions preserved.

The @keyframes definitions are correctly moved inside the layer wrapper while maintaining their functionality. The formatting changes improve readability without altering behavior.

src/_config.scss (2)

12-14: Verify layer order priority matches intended cascade.

The $layer-order defines cascade priority where later layers have higher specificity. The current order (reset, preflight, props, components, themes, utilities) means:

  • Utilities have highest priority (can override everything)
  • Themes can override components/props/preflight/reset
  • Components can override props/preflight/reset

Verify this matches the intended design system behavior, particularly:

  • Should themes really override component defaults?
  • Is utilities having the highest priority intentional (following Tailwind's model)?

Consider documenting this cascade order with examples in the configuration comments to help users understand the implications when $use-css-layers: true.


4-7: LGTM - Well-documented color system toggle.

The $use-color-mix flag is clearly documented with the distinction between modern Relative Color Syntax and legacy HSL channel separation. Defaulting to true is appropriate given browser support in Chrome 125+, Edge 125+, Firefox 128+, and Safari 18+. Ensure minimum browser requirements are documented at the project level (e.g., in README or contributing guide).

src/themes/dark/components/_vv-dropdown-action.scss (2)

7-13: LGTM - Theme component refactored correctly.

The mixin now uses spread-theme-component with explicit base and theme maps, which provides better control over theme application and supports the new custom properties flag.


16-26: LGTM - Proper layer scoping for themes.

The theme rules are correctly wrapped in the CSS layer, maintaining both the automatic dark mode detection via prefers-color-scheme and explicit .theme--dark class application.

src/tools/mixin-modules/_utilities.scss (2)

44-54: LGTM - Recursive nested map handling.

The recursive call for nested maps correctly passes through all necessary parameters and maintains the naming hierarchy with the $name parameter. This enables deep map traversal for complex utility definitions.


75-75: The str-replace function is properly imported and available. It is defined in src/tools/_functions.scss (line 520) and imported via @use '../functions' as * at line 3 of the utilities file. No action required.

src/themes/dark/components/_vv-alert.scss (1)

7-13: LGTM - Consistent theme component pattern.

The file follows the same refactoring pattern as other theme components (e.g., _vv-dropdown-action.scss), using spread-theme-component and proper layer scoping. This consistency ensures predictable behavior across all themed components.

Also applies to: 16-26

docs/contents/settings/colors.md (1)

97-114: The color algorithm values are mathematically correct but documentation could clarify the scale differences.

The documentation examples are accurate:

  • Brand-lighten-6: calc(l * 1.6) is correct (6 steps × 10% scale = 1.6 multiplier)
  • Surface-6: calc(l - 12) is correct (6 steps × 2% scale = 12)

However, the general description stating "Fixed steps for surface/word colors: calc(l + 12)" is imprecise. The implementation uses two different scales:

  • color-mix-lighten-map uses 12% per step (for lighten variants)
  • color-mix-darken-map uses 2% per step (for darken variants)

The documentation example demonstrates the 2% scale (step 6: 6 × 2 = 12), while the general description references the 12% scale. Clarify which function and scale applies to each color type to avoid confusion.

src/components/vv-tooltip.scss (1)

4-31: LGTM - Layer wrapper and consolidated selector look correct.

The component is properly wrapped with the layer() mixin for CSS cascade layer support. The consolidated selector on line 25 correctly handles all hover/focus-visible interaction states (both pseudo-classes and utility classes) in a single rule.

src/themes/dark/components/_vv-select.scss (1)

6-26: LGTM - Consistent dark theme pattern with layer wrapping.

The spread-theme-component mixin usage with explicit parameters and the layer(themes, ...) wrapper follow the established pattern across dark theme components. The dual-path approach (media query for system preference + explicit .theme--dark class) provides good flexibility for theme switching.

src/themes/dark/components/_vv-badge.scss (1)

6-26: LGTM - Follows established dark theme component pattern.

Structure is consistent with other dark theme components (_vv-select.scss, _vv-button.scss, etc.) using spread-theme-component and layer wrapping.

src/tools/mixin-modules/_layers.scss (1)

9-18: LGTM - Clean and functional layer wrapper mixin.

The conditional layer wrapping based on $enabled flag is well-implemented. The @content passthrough when disabled ensures no output overhead.

src/themes/dark/components/_vv-button.scss (1)

6-26: LGTM - Consistent with the dark theme component pattern.

Follows the same structure as other dark theme components with spread-theme-component and layer wrapping.

src/themes/dark/components/_vv-nav.scss (1)

6-26: LGTM - Follows established dark theme component pattern.

The implementation correctly uses $vv-nav and $dark-vv-nav maps with the standardized layer wrapping.

Note: The AI summary references _vv-alert.scss content, but this file is _vv-nav.scss. The code itself is correct.

src/themes/dark/components/_vv-dropdown-option.scss (1)

6-26: LGTM - Consistent dark theme component implementation.

Follows the standardized pattern with spread-theme-component and layer wrapping.

src/tools/mixin-modules/_props.scss (1)

15-41: LGTM - Solid recursive map-to-CSS-props transformation.

The mixin correctly handles:

  • Nested map recursion with proper key concatenation
  • Skip logic for internal keys (prefixed with _, --, or [)
  • Escaped slash normalization via str-replace

The meta.inspect() usage for key comparisons ensures consistent string handling regardless of the original key type. The str-replace function is properly imported and available from the functions module.

src/tools/mixin-modules/_attrs.scss (2)

12-42: LGTM - Vendor prefix handling for pseudo-elements.

The mixin correctly emits both -webkit- and -moz- variants for form control pseudo-elements that require vendor prefixes.


134-174: Logic for attribute generation is well-structured.

The conditional handling for CSS custom properties vs direct values, bracketed keys, and content properties is comprehensive. The use of meta.inspect for string operations is appropriate.

src/themes/dark/settings/_colors.scss (2)

14-33: Conditional surface palette for color-mix mode is well-implemented.

The dual-branch approach using CSS Relative Color Syntax (hsl(from var(...) h s 10%)) when color-mix is enabled, with fallback to legacy HSL variable pattern, provides good backward compatibility.


36-55: Dark theme color inversion logic is correct.

The dark theme appropriately uses color-mix-darken-map for word colors (darkening bright text) and color-mix-lighten-map for surface colors (lightening dark backgrounds), which is the inverse of the light theme behavior.

src/settings/_colors.scss (2)

58-103: Comprehensive color map with dual-mode support.

The color map construction cleanly separates the color-mix-enabled path (using color-base-map, color-mix-*-map functions) from the legacy path (using hsla-map, color-*-map functions). The structure is consistent and maintainable.


89-93: Minor inconsistency: legacy surface map uses color-darken-map with $fixed: true.

In the color-mix branch (line 69), surface uses color-mix-darken-map which produces darkened shades. In the legacy branch (line 91), it also uses color-darken-map. However, the word colors use opposite operations in each branch (lighten in color-mix, but line 89 shows color-lighten-map). This appears intentional for the light theme, just confirming the logic is correct.

src/tools/_functions.scss (3)

133-152: Verify proportional mode calculation for relative-color-value.

In proportional mode (lines 147-150), the calculation $multiplier: 1 + $scale-factor means a 10% scale produces multiplier 1.1. For darkening (negative change), a -10% would produce multiplier 0.9. However, line 179 passes $scale * $i * -1 for darken, so color-mix-shades-map uses negative values for darkening.

The issue: when $lightness-change is negative (e.g., -10%), line 147 calculates $scale-factor: -0.1, then $multiplier: 0.9, which correctly darkens. The logic appears sound.


244-261: Alpha map percentage calculation may produce unexpected results at boundaries.

At line 254, $percentage: 100% - ($scale * $i * 100%) with default $scale: 0.1 and $steps: 9:

  • Step 1: 100% - (0.1 * 1 * 100%) = 90% transparent → 10% opaque
  • Step 9: 100% - (0.1 * 9 * 100%) = 10% transparent → 90% opaque

This is correct for generating increasing opacity steps. The color-mix(in srgb, var(...), transparent #{$percentage}) syntax is valid.


117-121: LGTM - Simple and effective base map function.

Clean implementation that returns the color under its CSS variable name.

docs/components/ColorPalette.vue (2)

72-75: Good simplification to single CSS variable.

Consolidating from separate hue/saturation/lightness variables to a single --color-{name} variable aligns with the new CSS Relative Color Syntax approach and reduces complexity.


256-259: Simplified color setter writes hex directly to CSS variable.

Setting the hex value directly to colorVar works because modern browsers accept hex colors as CSS variable values, and the Relative Color Syntax can work with them.

src/tools/mixin-modules/_theme.scss (3)

18-45: Well-designed recursive function for extracting light reset values.

The extract-light-values function correctly traverses the theme map and extracts corresponding values from the base map, enabling automatic light-mode reset generation. The null-safe handling and empty map check are good practices.


57-146: Comprehensive theme component mixin with dual-mode support.

The spread-theme-component mixin cleanly handles both CSS custom properties mode and direct attributes mode. The automatic light reset generation from base-map is a thoughtful feature for theme toggling scenarios.


283-354: State spreading handles multiple selector variants comprehensively.

The mixin generates BEM modifier style (.block--state), class style (.block.state), and appropriate pseudo-class/attribute selectors for each state. The focus-visible selector at line 323 includes proper exclusions for disabled and inactive elements.

src/tools/mixin-modules/_bem.scss (2)

41-170: Well-structured main BEM mixin with customization flags.

The spread-map-into-bem mixin provides a clean orchestration layer with individual $custom-* flags allowing selective generation. The :where(:host, :root, .theme) wrapper for CSS custom properties at line 66 is appropriate for low-specificity theming.


496-574: Comprehensive state selector helper function.

The -add-state-selectors function handles various state types appropriately:

  • checked-within with :has(input:checked)
  • open/close with attribute selectors
  • dirty with :not(:has(*:placeholder-shown))
  • disabled/readonly/multiple with attribute selectors
  • pressed/selected with ARIA attributes

The alias support ensures consistent behavior across alternative selectors.

"unplugin-auto-import": "^20.3.0",
"unplugin-vue-components": "^30.0.0",
"vite": "^7.1.11",
"vite": "^7.3.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Vite 7 breaking changes migration guide

💡 Result:

Summary migration checklist for Vite 7 — key breaking changes and actions

  1. Upgrade Node in dev/CI to >= 20.19 (or 22.12+) — Vite 7 is ESM-only and drops Node 18. Update Docker/CI runners. [2]

  2. ESM-only distribution — Vite core is shipped as pure ESM; ensure any CJS consumers use supported Node require(esm) shims or migrate to ESM. [2]

  3. Default build.target changed to "baseline-widely-available" (new baseline browser versions bumped) — verify your app against the new target and pin build.target if you need broader legacy support. [1][2]

  4. Removed/deprecated APIs/features to address before upgrading:

    • Legacy Sass API support removed. Migrate to supported Sass usage. [2]
    • splitVendorChunkPlugin removed — adjust chunking strategy if you relied on it. [2]
    • Other outdated config options / deprecated internals — run tests and review migration docs/changelog for project-specific items. [1][2]
  5. Environment API and new hooks:

    • New buildApp hook and other Environment API changes for framework integrations — plugin/framework authors should adapt. [1][2]
  6. Rolldown integration (new Rust-based bundler):

    • Rolldown/rolldown-vite is introduced as an alternative (path toward future default). Test with rolldown-vite if you rely on bundler internals or want to migrate early. Watch for minor Rolldown-specific edge cases documented in the migration notes. [1]
  7. Testing/tooling:

    • Upgrade Vitest to a compatible version (Vitest 3.2+ recommended). Update any test configs that interact with Vite internals. [2]
  8. Practical upgrade steps

    • Update package.json to vite@^7, update devDependencies (vitest, plugins). [2]
    • Update Node versions in local/dev/CI to 20.19+ or 22.12+. [2]
    • Run full test suite and dev server; fix plugin or config breakages reported. [1][3]
    • If you need to preserve legacy behavior, pin build.target or keep using a Vite 6 branch until you’re ready to migrate. [1]

References

  • Vite migration page / Migration from v7 (breaking notes & Rolldown notes). [1]
  • Vite 7 release announcement (requirements, removed features, summary). [2]
  • Vite breaking changes index (list of planned/past breaking changes). [3]

If you want, I can produce a tailored step-by-step upgrade plan for your repo—tell me your current Vite version, Node version, and any plugins you use.


🏁 Script executed:

# First, let's examine the package.json to see the current plugin versions
cat package.json | grep -A 20 -B 5 "vite"

Repository: volverjs/style

Length of output: 2782


🏁 Script executed:

# Check if there's a vite config file
fd -t f "vite\.config\." -o "vitest\.config\."

Repository: volverjs/style

Length of output: 209


🏁 Script executed:

# Find vite config files with correct syntax
fd "vite\.config" -t f

Repository: volverjs/style

Length of output: 72


🏁 Script executed:

# Check for vitest config and vitest dependency
grep -i "vitest" package.json

Repository: volverjs/style

Length of output: 40


🌐 Web query:

vite-plugin-css-export Vite 7 compatibility

💡 Result:

Short answer: Use vite-plugin-css-export v3.0.3 or later — v3.0.3+ is listed as compatible with Vite 7. [1][2]

Details: the plugin README and package pages show the compatibility table (3.x supports Vite 5–7; specifically >=3.0.3 adds Vite 7 support). If you need a specific install command: npm i -D vite-plugin-css-export@^3.0.3. [1][2]

Sources:
[1] GitHub README (vite-plugin-css-export).
[2] Package metadata / compatibility table (npm/socket view).


🌐 Web query:

vite-plugin-handlebars Vite 7 support

💡 Result:

Short answer: Most popular vite-plugin-handlebars packages are not officially updated for Vite 7; you’ll need to either use a maintained fork (e.g. @yoichiro / @vituum variants) or patch the plugin to the Vite 7 plugin API. See sources below for status and Vite 7 breaking changes.

  • Vite 7 release notes (Node and ESM changes / plugin hook adjustments) — upgrade may require plugin changes. [1]
  • The original vite-plugin-handlebars npm page states it was written for Vite 2 and hasn’t been updated for newer majors. [2]
  • The GitHub repo for @yoichiro/vite-plugin-handlebars (active repo/fork) and @vituum package are available as alternatives you can try; check those repos for recent activity and compatibility. [3][4]

Recommendation: try one of the maintained forks (install and run with Vite 7); if you hit errors, update the plugin to use Vite 7’s ESM-only distribution and any changed transformIndexHtml / plugin-hook signatures (see Vite 7 docs). If you want, tell me which package/version you’re using and I’ll check compatibility or suggest exact code changes.

Sources:
[1] Vite 7 announcement.
[2] vite-plugin-handlebars — npm.
[3] yoichiro/vite-plugin-handlebars — GitHub.
[4] @vituum/vite-plugin-handlebars — npm / Vituum docs.


🌐 Web query:

vite-ssg Vite 7 compatibility

💡 Result:

Short answer: Possibly — but you should verify before upgrading.

  • Vite 7 was released June 24, 2025 (Node 20.19+/22.12+ and ESM-only distribution). [1]
  • The official vite-ssg README (antfu-collective/vite-ssg) does not explicitly list Vite 7 in its top-level compatibility note; it documents ESM-only from v27.0.0 and general Vite support but you should check the repo's issues/PRs for Vite‑7-specific fixes. [2]

Actionable steps:

  1. Check your installed vite-ssg version (use v27+ for ESM). [2]
  2. Search the vite-ssg GitHub issues/PRs for “vite 7” or open an issue if you hit breakage. [2]
  3. Confirm your Node version meets Vite 7’s requirements (Node 20.19+ or 22.12+). [1]

Sources:

  1. Vite 7 announcement (June 24, 2025). [1]
  2. vite-ssg README (antfu-collective/vite-ssg). [2]

🏁 Script executed:

cat -n vite.config.ts

Repository: volverjs/style

Length of output: 3445


🌐 Web query:

vite-ssg v28 Vite 7 support compatibility

💡 Result:

Short answer: vite-ssg v28 (v27+ is ESM-only) is expected to work with Vite 7, but you must run on the Node versions Vite 7 requires (Node.js >= 20.19 or 22.12) and confirm any downstream plugin/adapter you use also supports Vite 7. Sources: vite-ssg README (ESM-only from v27) and the Vite 7 announcement (Node / ESM requirements). [1][2]

Sources
[1] antfu-collective/vite-ssg — README (notes ESM-only from v27.0.0).
[2] Vite — "Vite 7.0 is out!" (Vite 7 release notes: ESM-only distribution and Node.js 20.19+/22.12+ requirement).


Update Node.js requirement and vite-plugin-handlebars for Vite 7 compatibility.

Vite 7 requires Node ≥ 20.19 or 22.12+, but package.json specifies ">= 12.x" — update the engines.node field to at least ">= 20.19". Additionally, vite-plugin-handlebars v2.0.0 is not officially compatible with Vite 7; replace it with a maintained fork such as @yoichiro/vite-plugin-handlebars or @vituum/vite-plugin-handlebars. The other plugins (vite-plugin-css-export v3.0.3, vite-ssg v28.2.2, @vitejs/plugin-vue v6.0.3) support Vite 7. After these changes, test the build and consider pinning build.target if legacy browser support is required (Vite 7 changed the default baseline).

🤖 Prompt for AI Agents
In package.json around line 82, update the Node engine requirement and replace
the incompatible handlebars plugin: change the "engines.node" value to at least
">= 20.19" (Vite 7 requires Node ≥ 20.19 or 22.12+), remove
"vite-plugin-handlebars" v2.0.0 and add a maintained fork such as
"@yoichiro/vite-plugin-handlebars" or "@vituum/vite-plugin-handlebars" in
dependencies, run npm/yarn install to update lockfile, then run the build and
tests to verify compatibility and optionally pin Vite build.target if you need
legacy browser support.

src/export.scss Outdated
Comment on lines 544 to 546

// Keep the escaped slash for CSS property names
$name: str-replace($name, '\\/', '\\/');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove the redundant no-op str-replace operation.

The str-replace($name, '\\/', '\\/') operation replaces the escaped slash with itself, which is a no-op. If the intent is to preserve escaped slashes in translation keys (as indicated by the comment), simply remove the str-replace line entirely.

🔎 Proposed fix
 @each $key, $value in $translate {
   $name: meta.inspect($key);
-
-  // Keep the escaped slash for CSS property names
-  $name: str-replace($name, '\\/', '\\/');

   #{'translate__' + $name}: $value;
 }

Alternatively, if you need to keep the comment for documentation purposes:

 @each $key, $value in $translate {
+  // Keep the escaped slash for CSS property names
   $name: meta.inspect($key);
-
-  // Keep the escaped slash for CSS property names
-  $name: str-replace($name, '\\/', '\\/');

   #{'translate__' + $name}: $value;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Keep the escaped slash for CSS property names
$name: str-replace($name, '\\/', '\\/');
@each $key, $value in $translate {
$name: meta.inspect($key);
#{'translate__' + $name}: $value;
}
🤖 Prompt for AI Agents
In src/export.scss around lines 544 to 546, the str-replace call
str-replace($name, '\\/', '\\/') is a redundant no-op (it replaces an escaped
slash with itself); remove that line and keep the existing comment so escaped
slashes are preserved without performing an unnecessary replacement.

Comment on lines +56 to +85
$default: null;
$class-name: $class;
$key: meta.inspect($key);
$var: $prop;

// fix class name
@if $class-name != $key and $prop != $key {
@if $class-name != '' {
$class-name: $class-name + '-';
}

$class-name: $class-name + $key;
}

// fix variable name
@if $var != '' and $var != $key {
$var: $var + '-' + $key;
}

$var: str-replace($var, '\\/', '-');

// check if value is not a map (spacing-dynamic)
@if meta.type-of($value) != 'map' {
$default: $value;
}

// check if map is a list
@if meta.type-of($map) == 'list' and (not $default or $default == '') {
$default: $key;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Complex default value logic - verify edge cases.

The default value determination (lines 78-85) has multiple conditions:

  1. Use $value if not a map
  2. Use $key if $map is a list and no default
  3. Unquote if string

This logic might not handle all edge cases correctly, particularly:

  • What happens if $value is null or 0? Line 98 checks @if $default which would fail for falsy values.
  • List detection at line 83 happens after the map check, but lists were already handled recursively.
🔎 Strengthen default value handling
 // check if value is not a map (spacing-dynamic)
 @if meta.type-of($value) != 'map' {
   $default: $value;
 }

 // check if map is a list
-@if meta.type-of($map) == 'list' and (not $default or $default == '') {
+@if meta.type-of($map) == 'list' and $default == null {
   $default: $key;
 }

 @if meta.type-of($default) == 'string' {
   $default: string.unquote($default);
 }

 %#{$prefix}#{$class-name} {
   @include media-breakpoint-up($breakpoint, $bps) {
     @if meta.type-of($attribute) != 'list' {
       $attribute: ($attribute);
     }

     @each $attr in $attribute {
-      @if $default {
+      @if $default != null {
         @if $var != '' {
           #{$attr}: var(--#{$var}, $default);
         } @else {
           #{$attr}: $default;
         }

This ensures falsy but valid values (like 0) are handled correctly.

Committable suggestion skipped: line range outside the PR's diff.

@alessandrobellesia alessandrobellesia changed the title Feature/layers Implement CSS @layer cascade and color-mix features Dec 29, 2025
@sonarqubecloud
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
package.json (2)

28-30: Node version constraint is too loose for Vite 7.

Vite 7 requires Node.js ≥ 20.19 or ≥ 22.12, but ">= 20.x" permits Node 20.0–20.18 which will fail. Tighten the constraint.

🔎 Proposed fix
  "engines": {
-    "node": ">= 20.x"
+    "node": ">= 20.19"
  },

82-84: vite-plugin-handlebars v2.0.0 is not officially compatible with Vite 7.

With vite@^7.3.0, the unchanged vite-plugin-handlebars@^2.0.0 may cause build failures or runtime issues. Consider replacing it with a maintained fork such as @yoichiro/vite-plugin-handlebars or @vituum/vite-plugin-handlebars.

#!/bin/bash
# Check if vite-plugin-handlebars is actually used in the vite config
cat vite.config.ts | grep -i "handlebars"
🧹 Nitpick comments (1)
src/props/transitions.scss (1)

39-42: Consider removing redundant CSS variable definitions.

The $transition-property map (lines 39-42) and $transition-timing-function map (lines 51-54) are already spread outside the media query at lines 21-24 and 15-18 respectively. Since these values don't need to change based on motion preference, spreading them again inside the media query generates duplicate CSS output unnecessarily.

The --transition-property-* and --ease-* variables can be defined once outside the media query, reducing CSS output size. Only the duration, animation, and composite transition values need to be overridden inside prefers-reduced-motion: no-preference.

🔎 Proposed optimization

Remove the redundant spreads from inside the media query:

 		@media (prefers-reduced-motion: no-preference) {
-			// transition-property
-			@include spread-map-into-props(
-				$transition-property,
-				$prefix: transition-property
-			);
-
 			// duration
 			@include spread-map-into-props(
 				$transition-duration-delay,
 				$prefix: duration
 			);
 
-			// ease
-			@include spread-map-into-props(
-				$transition-timing-function,
-				$prefix: ease
-			);
-
 			// animation
 			@include spread-map-into-props($animation, animation);

Also applies to: 51-54

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9043ffe and 201f052.

📒 Files selected for processing (8)
  • .eslintrc-auto-import.json
  • auto-imports.d.ts
  • docs/components/ColorPalette.vue
  • package.json
  • src/export.scss
  • src/props/transitions.scss
  • src/tools/mixin-modules/_bem.scss
  • src/utilities/transforms.scss
💤 Files with no reviewable changes (2)
  • .eslintrc-auto-import.json
  • src/export.scss
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/tools/mixin-modules/_bem.scss
🧰 Additional context used
🧬 Code graph analysis (1)
auto-imports.d.ts (1)
scripts/generateDesignTokens.js (1)
  • icssExports (15-17)
🔇 Additional comments (13)
package.json (3)

31-31: LGTM!

The pnpm version bump to 10.26.2 is a routine maintenance update.


50-93: DevDependency updates look reasonable.

The version bumps align with the Vite 7 migration. Key observations:

  • @vitejs/plugin-vue@^6.0.3 and vite-plugin-css-export@^3.0.3 support Vite 7
  • sass-embedded@^1.97.1 uses the modern Sass API (legacy API was removed in Vite 7)
  • vite-ssg@^28.2.2 is ESM-compatible

Ensure build and dev server are tested after these upgrades.


112-139: New props exports are well-structured and properly referenced.

The export entries follow a consistent pattern and provide granular access to individual prop modules alongside the bundled ./props entry. All 14 referenced SCSS source files exist in src/props/, confirming the exports are correctly configured. This aligns with the PR's goal of modularizing props.

src/props/transitions.scss (2)

6-34: Excellent fix for the critical accessibility issue!

This change directly addresses the critical issue flagged in previous reviews where transition variables were undefined for users with prefers-reduced-motion enabled. The default values ensure that:

  • All --duration-* variables are set to 0s (no animation)
  • All --transition-* variables are set to none (no transitions)
  • All --animation-* variables are set to none (no animations)

Components that reference these variables (e.g., var(--transition-all)) will now always receive valid values, preventing broken transition properties for reduced-motion users.


60-76: Transition building logic looks correct.

The logic correctly constructs composite transition values by combining property names with duration and easing variables. The string manipulation properly handles comma-separated properties and removes the trailing delimiter.

The hardcoded defaults (--duration-300 and --ease-in-out) are reasonable choices for the composite transitions.

src/utilities/transforms.scss (4)

3-3: LGTM! CSS layer wrapper added correctly.

The layer wrapper correctly implements the new CSS @layer support introduced in this PR, using the utilities layer name with conditional activation via $use-css-layers.


65-65: Excellent! Previous escaping issue resolved.

All translate selectors now consistently use $escaped-size, including the negative translate -x and -y variants at lines 109 and 120 that were flagged in the previous review. This will correctly generate escaped class names like .-translate-x-1\/2 instead of invalid .-translate-x-1/2.

Also applies to: 76-76, 87-87, 98-98, 109-109, 120-120


127-127: LGTM! Layer wrapper properly closed.

The closing brace correctly closes the CSS layer wrapper block opened at line 3, ensuring all transform utilities are properly scoped within the utilities layer.


58-59: The str-replace function is properly defined and available through the import chain. The custom Sass function is defined in src/tools/_functions.scss and exported through src/tools/_index.scss, which is forwarded by src/_context.scss. This makes it accessible in transforms.scss via the @use '../context' as *; import statement. The implementation at lines 58-59 is correct.

docs/components/ColorPalette.vue (4)

72-75: Clean refactor to single CSS variable.

The consolidation from separate HSL variables to a single colorVar bound to --color-${props.name} aligns well with the PR's CSS Relative Color Syntax objectives and simplifies the reactive state management.


100-160: Robust color parsing implementation.

The enhanced getComputedStyleRgb now comprehensively handles multiple color formats with proper error handling:

  • rgb/rgba parsing via regex
  • color() format (sRGB) parsing
  • Canvas-based fallback with OffscreenCanvas support
  • Null checks for canvas context (addresses previous review concern)
  • Try-catch wrapper with safe defaults

The implementation properly guards against all failure modes identified in the previous review.


162-162: Updated watcher dependencies align with refactor.

The watchThrottled dependencies correctly reflect the new single-variable color model, watching colorVar instead of the previous separate HSL components.


279-280: The implementation is correct. CSS Relative Color Syntax accepts any color format (including hex) as the source color, so assigning hex directly to colorVar works as intended. This is the documented default approach in the library and requires no changes.

const refWithControl: typeof import('@vueuse/core').refWithControl
const resolveComponent: typeof import('vue').resolveComponent
const resolveRef: typeof import('@vueuse/core').resolveRef
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent type declaration syntax.

Line 95 uses bracket notation ['resolveUnref'] while all other global declarations (lines 9-94, 96-303) have been migrated to dot notation. This inconsistency likely indicates incomplete refactoring in the auto-generation configuration.

🔎 Proposed fix
-  const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
+  const resolveUnref: typeof import('@vueuse/core').resolveUnref
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
const resolveUnref: typeof import('@vueuse/core').resolveUnref
🤖 Prompt for AI Agents
In auto-imports.d.ts around line 95, the global declaration uses bracket
notation "typeof import('@vueuse/core')['resolveUnref']" which is inconsistent
with the rest of the file; change it to dot notation "typeof
import('@vueuse/core').resolveUnref" to match lines 9–94 and 96–303, ensuring
the auto-generated declaration uses the same syntax and saving the file so the
refactor is complete.

@alessandrobellesia alessandrobellesia merged commit 39ccb5c into develop Dec 29, 2025
11 checks passed
@alessandrobellesia alessandrobellesia deleted the feature/layers branch December 29, 2025 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants