From 6d5b8fc9726dc3c56a27dd9a68df535f64ccb5ba Mon Sep 17 00:00:00 2001 From: J-Sek Date: Sat, 30 May 2026 04:54:52 +0200 Subject: [PATCH 1/5] feat(VSwitch): align with MD3 spec --- packages/vuetify/dev/vuetify.js | 8 ++- .../src/components/VSwitch/VSwitch.sass | 58 +++++++++++++++++++ .../src/components/VSwitch/VSwitch.tsx | 18 ++++-- .../src/components/VSwitch/_variables.scss | 29 ++++++++++ 4 files changed, 107 insertions(+), 6 deletions(-) diff --git a/packages/vuetify/dev/vuetify.js b/packages/vuetify/dev/vuetify.js index 38148f5541e..772370818cc 100644 --- a/packages/vuetify/dev/vuetify.js +++ b/packages/vuetify/dev/vuetify.js @@ -16,5 +16,11 @@ export default createVuetify({ defaults, icons, locale, - theme: { defaultTheme: 'light' }, + theme: { + defaultTheme: 'light', + themes: { + light: { colors: { primary: '#6750A4', 'on-primary': '#FFFFFF' } }, + dark: { colors: { primary: '#D0BCFF', 'on-primary': '#381E72' } }, + }, + }, }) diff --git a/packages/vuetify/src/components/VSwitch/VSwitch.sass b/packages/vuetify/src/components/VSwitch/VSwitch.sass index 3c81be92089..1445d636e5e 100644 --- a/packages/vuetify/src/components/VSwitch/VSwitch.sass +++ b/packages/vuetify/src/components/VSwitch/VSwitch.sass @@ -8,6 +8,14 @@ .v-label padding-inline-start: $switch-label-margin-inline-start + .v-switch--inset + --v-switch-inset-track-color: #{$switch-inset-track-background} + --v-switch-inset-outline-color: #{$switch-inset-outline} + + .v-theme--dark & + --v-switch-inset-track-color: #{$switch-inset-track-background-dark} + --v-switch-inset-outline-color: #{$switch-inset-outline-dark} + .v-switch__loader display: flex @@ -52,6 +60,12 @@ font-size: .75rem height: $switch-inset-track-height min-width: $switch-inset-track-width + opacity: $switch-inset-track-opacity + background-color: var(--v-switch-inset-track-color) + border: $switch-inset-border-width solid var(--v-switch-inset-outline-color) + + .v-switch--inset .v-selection-control--dirty & + border-color: transparent .v-switch__thumb align-items: center @@ -80,15 +94,59 @@ .v-switch--inset & height: $switch-inset-thumb-height width: $switch-inset-thumb-width + background-color: var(--v-switch-inset-outline-color) transform: scale(calc($switch-inset-thumb-off-height / $switch-inset-thumb-height)) &--filled transform: none + // icon reads as a cutout of the track behind it; the selected + color case + // is overridden by the text-color utility applied in the template + .v-icon + color: var(--v-switch-inset-track-color) + .v-switch--inset .v-selection-control--dirty & transform: none transition: .15s .05s transform settings.$decelerated-easing + .v-switch--inset .v-selection-control__wrapper:active & + transform: scale(calc($switch-inset-thumb-pressed-height / $switch-inset-thumb-height)) + + // Disabled (inset) — neutral surface tokens carry their own alpha, so the blanket + // control fade is reset to 1 (the label keeps it explicitly). + .v-switch--inset + .v-selection-control--disabled + opacity: 1 + + .v-label + opacity: var(--v-disabled-opacity) + + .v-switch__track + background-color: $switch-inset-disabled-track-unselected + border-color: $switch-inset-disabled-outline + + .v-switch__thumb + background-color: $switch-inset-disabled-handle + + .v-icon + color: $switch-inset-disabled-icon-unselected + + .v-selection-control--disabled.v-selection-control--dirty + .v-switch__track + background-color: $switch-inset-disabled-track + border-color: transparent + + .v-switch__thumb + background-color: $switch-inset-disabled-handle-selected + + .v-icon + color: $switch-inset-disabled-icon + + .v-selection-control--focus-visible .v-selection-control__wrapper + border-radius: $switch-inset-track-border-radius + outline: $switch-focus-outline-width solid $switch-focus-outline-color + outline-offset: $switch-focus-outline-offset + .v-switch $switch-thumb-transform: $switch-track-width * .5 - $switch-thumb-width * .5 + $switch-thumb-offset diff --git a/packages/vuetify/src/components/VSwitch/VSwitch.tsx b/packages/vuetify/src/components/VSwitch/VSwitch.tsx index 07432932784..b8312301ddd 100644 --- a/packages/vuetify/src/components/VSwitch/VSwitch.tsx +++ b/packages/vuetify/src/components/VSwitch/VSwitch.tsx @@ -179,23 +179,29 @@ export const VSwitch = genericComponent( )} ), - input: ({ inputNode, icon, backgroundColorClasses, backgroundColorStyles }) => ( + input: ({ inputNode, icon, backgroundColorClasses, backgroundColorStyles, textColorClasses, textColorStyles }) => ( <> { inputNode }
{ slots.thumb ? ( @@ -207,8 +213,10 @@ export const VSwitch = genericComponent( (icon && ( ))) : ( Date: Sat, 30 May 2026 05:12:30 +0200 Subject: [PATCH 2/5] fix: avoid theme styles leaking into the component --- .../src/components/VSwitch/VSwitch.sass | 16 +- .../src/components/VSwitch/_variables.scss | 17 +-- .../__snapshots__/theme.spec.ts.snap | 138 ++++++++++++++++++ packages/vuetify/src/composables/theme.ts | 4 + 4 files changed, 153 insertions(+), 22 deletions(-) diff --git a/packages/vuetify/src/components/VSwitch/VSwitch.sass b/packages/vuetify/src/components/VSwitch/VSwitch.sass index 1445d636e5e..55b2abd9a8d 100644 --- a/packages/vuetify/src/components/VSwitch/VSwitch.sass +++ b/packages/vuetify/src/components/VSwitch/VSwitch.sass @@ -8,14 +8,6 @@ .v-label padding-inline-start: $switch-label-margin-inline-start - .v-switch--inset - --v-switch-inset-track-color: #{$switch-inset-track-background} - --v-switch-inset-outline-color: #{$switch-inset-outline} - - .v-theme--dark & - --v-switch-inset-track-color: #{$switch-inset-track-background-dark} - --v-switch-inset-outline-color: #{$switch-inset-outline-dark} - .v-switch__loader display: flex @@ -61,8 +53,8 @@ height: $switch-inset-track-height min-width: $switch-inset-track-width opacity: $switch-inset-track-opacity - background-color: var(--v-switch-inset-track-color) - border: $switch-inset-border-width solid var(--v-switch-inset-outline-color) + background-color: $switch-inset-track-color + border: $switch-inset-border-width solid $switch-inset-outline-color .v-switch--inset .v-selection-control--dirty & border-color: transparent @@ -94,7 +86,7 @@ .v-switch--inset & height: $switch-inset-thumb-height width: $switch-inset-thumb-width - background-color: var(--v-switch-inset-outline-color) + background-color: $switch-inset-outline-color transform: scale(calc($switch-inset-thumb-off-height / $switch-inset-thumb-height)) &--filled @@ -103,7 +95,7 @@ // icon reads as a cutout of the track behind it; the selected + color case // is overridden by the text-color utility applied in the template .v-icon - color: var(--v-switch-inset-track-color) + color: $switch-inset-track-color .v-switch--inset .v-selection-control--dirty & transform: none diff --git a/packages/vuetify/src/components/VSwitch/_variables.scss b/packages/vuetify/src/components/VSwitch/_variables.scss index af82762a5f9..71eedae7e4c 100644 --- a/packages/vuetify/src/components/VSwitch/_variables.scss +++ b/packages/vuetify/src/components/VSwitch/_variables.scss @@ -17,13 +17,10 @@ $switch-inset-track-height: 32px !default; $switch-inset-track-width: 52px !default; $switch-inset-track-opacity: 1 !default; -// MD3 inset switch approximations. The spec uses surface-container-highest (track) -// and outline (border + unselected thumb); neither token exists yet and both are -// theme-dependent, so they are hardcoded per theme — temporary workaround until v5. -$switch-inset-track-background: #e6e0e8 !default; -$switch-inset-track-background-dark: #48454e !default; -$switch-inset-outline: #7a747e !default; -$switch-inset-outline-dark: #938f98 !default; +// MD3 inset switch: unselected track is surface-container-highest, the border and +// unselected thumb are outline. Both resolve per theme via the theme system. +$switch-inset-track-color: rgb(var(--v-theme-surface-container-highest)) !default; +$switch-inset-outline-color: rgb(var(--v-theme-outline)) !default; $switch-inset-border-width: 2px !default; // Focus ring. MD3 uses secondary; unavailable until v5, so it falls back to the @@ -34,14 +31,14 @@ $switch-focus-outline-offset: 2px !default; // Disabled (inset). MD3 derives the disabled state from on-surface / surface with // 12% (track/outline) and 38% (handle/icon) opacities; only the unselected track -// uses the surface-container-highest approximation (--v-switch-inset-track-color). +// uses surface-container-highest ($switch-inset-track-color). $switch-inset-disabled-track: rgba(var(--v-theme-on-surface), .12) !default; -$switch-inset-disabled-track-unselected: color-mix(in srgb, var(--v-switch-inset-track-color) 12%, transparent) !default; +$switch-inset-disabled-track-unselected: color-mix(in srgb, #{$switch-inset-track-color} 12%, transparent) !default; $switch-inset-disabled-outline: rgba(var(--v-theme-on-surface), .12) !default; $switch-inset-disabled-handle: rgba(var(--v-theme-on-surface), .38) !default; $switch-inset-disabled-handle-selected: rgb(var(--v-theme-surface)) !default; $switch-inset-disabled-icon: rgba(var(--v-theme-on-surface), .38) !default; -$switch-inset-disabled-icon-unselected: color-mix(in srgb, var(--v-switch-inset-track-color) 38%, transparent) !default; +$switch-inset-disabled-icon-unselected: color-mix(in srgb, #{$switch-inset-track-color} 38%, transparent) !default; $switch-label-margin-inline-start: 10px !default; $switch-loader-color: rgb(var(--v-theme-surface)) !default; diff --git a/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap b/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap index 89fdf6e8190..e38b7fb497a 100644 --- a/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap +++ b/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap @@ -19,7 +19,11 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; + --v-theme-surface-container-highest: 230,224,232; + --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; + --v-theme-outline: 122,116,126; + --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -40,6 +44,8 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; + --v-theme-on-surface-container-highest: 0,0,0; + --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -83,7 +89,11 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; + --v-theme-surface-container-highest: 230,224,232; + --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; + --v-theme-outline: 122,116,126; + --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -104,6 +114,8 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; + --v-theme-on-surface-container-highest: 0,0,0; + --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -147,7 +159,11 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 200,200,200; --v-theme-surface-variant-overlay-multiplier: 2; + --v-theme-surface-container-highest: 72,69,78; + --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 0,0,0; + --v-theme-outline: 147,143,152; + --v-theme-outline-overlay-multiplier: 2; --v-theme-primary: 33,150,243; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 39,124,193; @@ -168,6 +184,8 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 255,255,255; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 255,255,255; + --v-theme-on-surface-container-highest: 255,255,255; + --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -226,6 +244,16 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` background-color: rgb(var(--v-theme-surface-variant)); color: rgb(var(--v-theme-on-surface-variant)); } + .bg-surface-container-highest { + --v-theme-overlay-multiplier: var(--v-theme-surface-container-highest-overlay-multiplier); + background-color: rgb(var(--v-theme-surface-container-highest)); + color: rgb(var(--v-theme-on-surface-container-highest)); + } + .bg-outline { + --v-theme-overlay-multiplier: var(--v-theme-outline-overlay-multiplier); + background-color: rgb(var(--v-theme-outline)); + color: rgb(var(--v-theme-on-outline)); + } .bg-primary { --v-theme-overlay-multiplier: var(--v-theme-primary-overlay-multiplier); background-color: rgb(var(--v-theme-primary)); @@ -298,9 +326,21 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` .border-surface-variant { --v-border-color: var(--v-theme-surface-variant); } + .text-surface-container-highest { + color: rgb(var(--v-theme-surface-container-highest)); + } + .border-surface-container-highest { + --v-border-color: var(--v-theme-surface-container-highest); + } .on-surface-variant { color: rgb(var(--v-theme-on-surface-variant)); } + .text-outline { + color: rgb(var(--v-theme-outline)); + } + .border-outline { + --v-border-color: var(--v-theme-outline); + } .text-primary { color: rgb(var(--v-theme-primary)); } @@ -361,6 +401,12 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` .on-surface-light { color: rgb(var(--v-theme-on-surface-light)); } + .on-surface-container-highest { + color: rgb(var(--v-theme-on-surface-container-highest)); + } + .on-outline { + color: rgb(var(--v-theme-on-outline)); + } .on-primary { color: rgb(var(--v-theme-on-primary)); } @@ -406,7 +452,11 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; + --v-theme-surface-container-highest: 230,224,232; + --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; + --v-theme-outline: 122,116,126; + --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -427,6 +477,8 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; + --v-theme-on-surface-container-highest: 0,0,0; + --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -470,7 +522,11 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; + --v-theme-surface-container-highest: 230,224,232; + --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; + --v-theme-outline: 122,116,126; + --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -491,6 +547,8 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; + --v-theme-on-surface-container-highest: 0,0,0; + --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -534,7 +592,11 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 200,200,200; --v-theme-surface-variant-overlay-multiplier: 2; + --v-theme-surface-container-highest: 72,69,78; + --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 0,0,0; + --v-theme-outline: 147,143,152; + --v-theme-outline-overlay-multiplier: 2; --v-theme-primary: 33,150,243; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 39,124,193; @@ -555,6 +617,8 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 255,255,255; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 255,255,255; + --v-theme-on-surface-container-highest: 255,255,255; + --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -613,6 +677,16 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` background-color: rgb(var(--v-theme-surface-variant)); color: rgb(var(--v-theme-on-surface-variant)); } + :where(#my-app) .bg-surface-container-highest { + --v-theme-overlay-multiplier: var(--v-theme-surface-container-highest-overlay-multiplier); + background-color: rgb(var(--v-theme-surface-container-highest)); + color: rgb(var(--v-theme-on-surface-container-highest)); + } + :where(#my-app) .bg-outline { + --v-theme-overlay-multiplier: var(--v-theme-outline-overlay-multiplier); + background-color: rgb(var(--v-theme-outline)); + color: rgb(var(--v-theme-on-outline)); + } :where(#my-app) .bg-primary { --v-theme-overlay-multiplier: var(--v-theme-primary-overlay-multiplier); background-color: rgb(var(--v-theme-primary)); @@ -685,9 +759,21 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` :where(#my-app) .border-surface-variant { --v-border-color: var(--v-theme-surface-variant); } + :where(#my-app) .text-surface-container-highest { + color: rgb(var(--v-theme-surface-container-highest)); + } + :where(#my-app) .border-surface-container-highest { + --v-border-color: var(--v-theme-surface-container-highest); + } :where(#my-app) .on-surface-variant { color: rgb(var(--v-theme-on-surface-variant)); } + :where(#my-app) .text-outline { + color: rgb(var(--v-theme-outline)); + } + :where(#my-app) .border-outline { + --v-border-color: var(--v-theme-outline); + } :where(#my-app) .text-primary { color: rgb(var(--v-theme-primary)); } @@ -748,6 +834,12 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` :where(#my-app) .on-surface-light { color: rgb(var(--v-theme-on-surface-light)); } + :where(#my-app) .on-surface-container-highest { + color: rgb(var(--v-theme-on-surface-container-highest)); + } + :where(#my-app) .on-outline { + color: rgb(var(--v-theme-on-outline)); + } :where(#my-app) .on-primary { color: rgb(var(--v-theme-on-primary)); } @@ -798,7 +890,11 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; + --v-theme-surface-container-highest: 230,224,232; + --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; + --v-theme-outline: 122,116,126; + --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -819,6 +915,8 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; + --v-theme-on-surface-container-highest: 0,0,0; + --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -862,7 +960,11 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; + --v-theme-surface-container-highest: 230,224,232; + --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; + --v-theme-outline: 122,116,126; + --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -883,6 +985,8 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; + --v-theme-on-surface-container-highest: 0,0,0; + --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -926,7 +1030,11 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 200,200,200; --v-theme-surface-variant-overlay-multiplier: 2; + --v-theme-surface-container-highest: 72,69,78; + --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 0,0,0; + --v-theme-outline: 147,143,152; + --v-theme-outline-overlay-multiplier: 2; --v-theme-primary: 33,150,243; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 39,124,193; @@ -947,6 +1055,8 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-on-surface: 255,255,255; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 255,255,255; + --v-theme-on-surface-container-highest: 255,255,255; + --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -1005,6 +1115,16 @@ exports[`createTheme > should create style element 1`] = ` background-color: rgb(var(--v-theme-surface-variant)); color: rgb(var(--v-theme-on-surface-variant)); } + .bg-surface-container-highest { + --v-theme-overlay-multiplier: var(--v-theme-surface-container-highest-overlay-multiplier); + background-color: rgb(var(--v-theme-surface-container-highest)); + color: rgb(var(--v-theme-on-surface-container-highest)); + } + .bg-outline { + --v-theme-overlay-multiplier: var(--v-theme-outline-overlay-multiplier); + background-color: rgb(var(--v-theme-outline)); + color: rgb(var(--v-theme-on-outline)); + } .bg-primary { --v-theme-overlay-multiplier: var(--v-theme-primary-overlay-multiplier); background-color: rgb(var(--v-theme-primary)); @@ -1077,9 +1197,21 @@ exports[`createTheme > should create style element 1`] = ` .border-surface-variant { --v-border-color: var(--v-theme-surface-variant); } + .text-surface-container-highest { + color: rgb(var(--v-theme-surface-container-highest)); + } + .border-surface-container-highest { + --v-border-color: var(--v-theme-surface-container-highest); + } .on-surface-variant { color: rgb(var(--v-theme-on-surface-variant)); } + .text-outline { + color: rgb(var(--v-theme-outline)); + } + .border-outline { + --v-border-color: var(--v-theme-outline); + } .text-primary { color: rgb(var(--v-theme-primary)); } @@ -1140,6 +1272,12 @@ exports[`createTheme > should create style element 1`] = ` .on-surface-light { color: rgb(var(--v-theme-on-surface-light)); } + .on-surface-container-highest { + color: rgb(var(--v-theme-on-surface-container-highest)); + } + .on-outline { + color: rgb(var(--v-theme-on-outline)); + } .on-primary { color: rgb(var(--v-theme-on-primary)); } diff --git a/packages/vuetify/src/composables/theme.ts b/packages/vuetify/src/composables/theme.ts index 08b1da29c13..aa2ab56b425 100644 --- a/packages/vuetify/src/composables/theme.ts +++ b/packages/vuetify/src/composables/theme.ts @@ -151,7 +151,9 @@ function genDefaults () { 'surface-bright': '#FFFFFF', 'surface-light': '#EEEEEE', 'surface-variant': '#424242', + 'surface-container-highest': '#E6E0E8', 'on-surface-variant': '#EEEEEE', + outline: '#7A747E', primary: '#1867C0', 'primary-darken-1': '#1F5592', secondary: '#48A9A6', @@ -194,7 +196,9 @@ function genDefaults () { 'surface-bright': '#ccbfd6', 'surface-light': '#424242', 'surface-variant': '#c8c8c8', + 'surface-container-highest': '#48454E', 'on-surface-variant': '#000000', + outline: '#938F98', primary: '#2196F3', 'primary-darken-1': '#277CC1', secondary: '#54B6B2', From 182df98a9033e9b0ca3b16729b1b7abe6ca7d0de Mon Sep 17 00:00:00 2001 From: J-Sek Date: Sat, 30 May 2026 05:27:41 +0200 Subject: [PATCH 3/5] feat: add `thumb-color` prop --- .../src/components/VSwitch/VSwitch.tsx | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/vuetify/src/components/VSwitch/VSwitch.tsx b/packages/vuetify/src/components/VSwitch/VSwitch.tsx index b8312301ddd..e3a680bd37d 100644 --- a/packages/vuetify/src/components/VSwitch/VSwitch.tsx +++ b/packages/vuetify/src/components/VSwitch/VSwitch.tsx @@ -10,6 +10,7 @@ import { VProgressCircular } from '@/components/VProgressCircular' import { makeVSelectionControlProps, VSelectionControl } from '@/components/VSelectionControl/VSelectionControl' // Composables +import { useBackgroundColor } from '@/composables/color' import { useFocus } from '@/composables/focus' import { forwardRefs } from '@/composables/forwardRefs' import { LoaderSlot, useLoader } from '@/composables/loader' @@ -45,6 +46,7 @@ export type VSwitchSlots = export const makeVSwitchProps = propsFactory({ inset: Boolean, flat: Boolean, + thumbColor: String, loading: { type: [Boolean, String], default: false, @@ -78,6 +80,7 @@ export const VSwitch = genericComponent( const model = useProxiedModel(props, 'modelValue') const { loaderClasses } = useLoader(props) const { isFocused, focus, blur } = useFocus(props) + const { backgroundColorClasses: thumbColorClasses, backgroundColorStyles: thumbColorStyles } = useBackgroundColor(() => props.thumbColor) const control = ref() const inputRef = ref() const isForcedColorsModeActive = SUPPORTS_MATCH_MEDIA && window.matchMedia('(forced-colors: active)').matches @@ -179,17 +182,25 @@ export const VSwitch = genericComponent( )}
), - input: ({ inputNode, icon, backgroundColorClasses, backgroundColorStyles, textColorClasses, textColorStyles }) => ( + input: ({ inputNode, icon, model: isSelected, backgroundColorClasses, backgroundColorStyles, textColorClasses, textColorStyles }) => { + // thumbColor overrides the selected-state thumb (the default + // is the contrast/on-color, which can look poor — e.g. orange) + const useThumbColor = !isForcedColorsModeActive && !!props.thumbColor && isSelected.value + + return ( <> { inputNode }
( )}
- ), + ) + }, }} ) From 3c289c827253301901dbfde25ed6073790526022 Mon Sep 17 00:00:00 2001 From: J-Sek Date: Sat, 30 May 2026 16:02:07 +0200 Subject: [PATCH 4/5] extend `inset` as opt-in guard + refine focus/hover/disabled/no-color --- packages/vuetify/dev/vuetify.js | 8 +-- .../src/components/VSwitch/VSwitch.sass | 58 ++++++++++++------- .../src/components/VSwitch/VSwitch.tsx | 41 +++++++++---- .../src/components/VSwitch/_variables.scss | 10 +--- 4 files changed, 70 insertions(+), 47 deletions(-) diff --git a/packages/vuetify/dev/vuetify.js b/packages/vuetify/dev/vuetify.js index 772370818cc..38148f5541e 100644 --- a/packages/vuetify/dev/vuetify.js +++ b/packages/vuetify/dev/vuetify.js @@ -16,11 +16,5 @@ export default createVuetify({ defaults, icons, locale, - theme: { - defaultTheme: 'light', - themes: { - light: { colors: { primary: '#6750A4', 'on-primary': '#FFFFFF' } }, - dark: { colors: { primary: '#D0BCFF', 'on-primary': '#381E72' } }, - }, - }, + theme: { defaultTheme: 'light' }, }) diff --git a/packages/vuetify/src/components/VSwitch/VSwitch.sass b/packages/vuetify/src/components/VSwitch/VSwitch.sass index 55b2abd9a8d..9b5d7262841 100644 --- a/packages/vuetify/src/components/VSwitch/VSwitch.sass +++ b/packages/vuetify/src/components/VSwitch/VSwitch.sass @@ -52,12 +52,6 @@ font-size: .75rem height: $switch-inset-track-height min-width: $switch-inset-track-width - opacity: $switch-inset-track-opacity - background-color: $switch-inset-track-color - border: $switch-inset-border-width solid $switch-inset-outline-color - - .v-switch--inset .v-selection-control--dirty & - border-color: transparent .v-switch__thumb align-items: center @@ -86,27 +80,54 @@ .v-switch--inset & height: $switch-inset-thumb-height width: $switch-inset-thumb-width - background-color: $switch-inset-outline-color transform: scale(calc($switch-inset-thumb-off-height / $switch-inset-thumb-height)) &--filled transform: none - // icon reads as a cutout of the track behind it; the selected + color case - // is overridden by the text-color utility applied in the template - .v-icon - color: $switch-inset-track-color - .v-switch--inset .v-selection-control--dirty & transform: none transition: .15s .05s transform settings.$decelerated-easing - .v-switch--inset .v-selection-control__wrapper:active & + .v-switch--inset-material + .v-switch__track + opacity: $switch-inset-track-opacity + background-color: $switch-inset-track-color + border: $switch-inset-border-width solid $switch-inset-outline-color + + .v-switch__thumb + background-color: $switch-inset-outline-color + + .v-icon + color: $switch-inset-track-color + + .v-selection-control--dirty + .v-switch__track + border-color: transparent + background-color: $switch-inset-selected-track-color + + .v-switch__thumb + background-color: $switch-inset-selected-handle-color + + .v-icon + color: $switch-inset-selected-track-color + + .v-selection-control__input:active .v-switch__thumb transform: scale(calc($switch-inset-thumb-pressed-height / $switch-inset-thumb-height)) - // Disabled (inset) — neutral surface tokens carry their own alpha, so the blanket - // control fade is reset to 1 (the label keeps it explicitly). - .v-switch--inset + .v-selection-control__input:before + --v-hover-opacity: 0.08 + z-index: 1 + + // focus is the track outline, so drop the overlay's focus state layer + .v-selection-control--focus-visible + .v-selection-control__input:before + opacity: 0 + + .v-switch__track + outline: $switch-focus-outline-width solid $switch-focus-outline-color + outline-offset: $switch-focus-outline-offset + .v-selection-control--disabled opacity: 1 @@ -134,11 +155,6 @@ .v-icon color: $switch-inset-disabled-icon - .v-selection-control--focus-visible .v-selection-control__wrapper - border-radius: $switch-inset-track-border-radius - outline: $switch-focus-outline-width solid $switch-focus-outline-color - outline-offset: $switch-focus-outline-offset - .v-switch $switch-thumb-transform: $switch-track-width * .5 - $switch-thumb-width * .5 + $switch-thumb-offset diff --git a/packages/vuetify/src/components/VSwitch/VSwitch.tsx b/packages/vuetify/src/components/VSwitch/VSwitch.tsx index e3a680bd37d..b2fd98b60c8 100644 --- a/packages/vuetify/src/components/VSwitch/VSwitch.tsx +++ b/packages/vuetify/src/components/VSwitch/VSwitch.tsx @@ -21,7 +21,7 @@ import { ref, toRef, useId } from 'vue' import { filterInputAttrs, genericComponent, propsFactory, SUPPORTS_MATCH_MEDIA, useRender } from '@/util' // Types -import type { ComputedRef, Ref } from 'vue' +import type { ComputedRef, PropType, Ref } from 'vue' import type { VInputSlots } from '@/components/VInput/VInput' import type { VSelectionControlSlots } from '@/components/VSelectionControl/VSelectionControl' import type { IconValue } from '@/composables/icons' @@ -44,7 +44,10 @@ export type VSwitchSlots = } export const makeVSwitchProps = propsFactory({ - inset: Boolean, + inset: { + type: [Boolean, String] as PropType, + default: false, + }, flat: Boolean, thumbColor: String, loading: { @@ -80,7 +83,10 @@ export const VSwitch = genericComponent( const model = useProxiedModel(props, 'modelValue') const { loaderClasses } = useLoader(props) const { isFocused, focus, blur } = useFocus(props) - const { backgroundColorClasses: thumbColorClasses, backgroundColorStyles: thumbColorStyles } = useBackgroundColor(() => props.thumbColor) + const { + backgroundColorClasses: thumbColorClasses, + backgroundColorStyles: thumbColorStyles, + } = useBackgroundColor(() => props.thumbColor) const control = ref() const inputRef = ref() const isForcedColorsModeActive = SUPPORTS_MATCH_MEDIA && window.matchMedia('(forced-colors: active)').matches @@ -116,7 +122,8 @@ export const VSwitch = genericComponent( class={[ 'v-switch', { 'v-switch--flat': props.flat }, - { 'v-switch--inset': props.inset }, + { 'v-switch--inset': !!props.inset }, + { 'v-switch--inset-material': props.inset === 'material' }, { 'v-switch--indeterminate': indeterminate.value }, loaderClasses.value, props.class, @@ -182,9 +189,16 @@ export const VSwitch = genericComponent( )} ), - input: ({ inputNode, icon, model: isSelected, backgroundColorClasses, backgroundColorStyles, textColorClasses, textColorStyles }) => { - // thumbColor overrides the selected-state thumb (the default - // is the contrast/on-color, which can look poor — e.g. orange) + input: ({ + inputNode, + icon, + model: isSelected, + backgroundColorClasses, + backgroundColorStyles, + textColorClasses, + textColorStyles, + }) => { + const isMaterial = props.inset === 'material' const useThumbColor = !isForcedColorsModeActive && !!props.thumbColor && isSelected.value return ( @@ -196,14 +210,17 @@ export const VSwitch = genericComponent( { 'v-switch__thumb--filled': icon || props.loading }, isForcedColorsModeActive ? undefined : useThumbColor ? thumbColorClasses.value + : isMaterial ? backgroundColorClasses.value + : props.inset ? undefined : backgroundColorClasses.value, ]} style={ useThumbColor ? thumbColorStyles.value - : props.inset + : isMaterial ? (backgroundColorClasses.value.length || backgroundColorStyles.value.backgroundColor ? { backgroundColor: 'currentColor' } : undefined) + : props.inset ? undefined : backgroundColorStyles.value } > @@ -212,7 +229,7 @@ export const VSwitch = genericComponent( defaults={{ VIcon: { icon, - size: props.inset ? 16 : 'x-small', + size: isMaterial ? 16 : 'x-small', }, }} > @@ -224,10 +241,10 @@ export const VSwitch = genericComponent( (icon && ( ))) : ( Date: Sun, 31 May 2026 00:21:01 +0200 Subject: [PATCH 5/5] chore: avoid new theme colors + refactor variables --- .../src/components/VSwitch/VSwitch.sass | 37 +++-- .../src/components/VSwitch/VSwitch.tsx | 21 ++- .../src/components/VSwitch/_variables.scss | 25 ++-- .../__snapshots__/theme.spec.ts.snap | 138 ------------------ packages/vuetify/src/composables/theme.ts | 4 - 5 files changed, 39 insertions(+), 186 deletions(-) diff --git a/packages/vuetify/src/components/VSwitch/VSwitch.sass b/packages/vuetify/src/components/VSwitch/VSwitch.sass index 9b5d7262841..219af1772ec 100644 --- a/packages/vuetify/src/components/VSwitch/VSwitch.sass +++ b/packages/vuetify/src/components/VSwitch/VSwitch.sass @@ -80,7 +80,7 @@ .v-switch--inset & height: $switch-inset-thumb-height width: $switch-inset-thumb-width - transform: scale(calc($switch-inset-thumb-off-height / $switch-inset-thumb-height)) + transform: scale(var(--v-switch-inset-thumb-off-scale, #{$switch-inset-thumb-off-scale})) &--filled transform: none @@ -92,14 +92,12 @@ .v-switch--inset-material .v-switch__track opacity: $switch-inset-track-opacity - background-color: $switch-inset-track-color - border: $switch-inset-border-width solid $switch-inset-outline-color + background-color: $switch-inset-unselected-track-color + border: $switch-inset-border-width solid $switch-inset-unselected-thumb-color .v-switch__thumb - background-color: $switch-inset-outline-color - - .v-icon - color: $switch-inset-track-color + background-color: $switch-inset-unselected-thumb-color + color: $switch-inset-unselected-track-color .v-selection-control--dirty .v-switch__track @@ -107,13 +105,11 @@ background-color: $switch-inset-selected-track-color .v-switch__thumb - background-color: $switch-inset-selected-handle-color - - .v-icon - color: $switch-inset-selected-track-color + background-color: $switch-inset-selected-thumb-color + color: $switch-inset-selected-track-color .v-selection-control__input:active .v-switch__thumb - transform: scale(calc($switch-inset-thumb-pressed-height / $switch-inset-thumb-height)) + transform: scale(var(--v-switch-inset-thumb-pressed-scale, #{$switch-inset-thumb-pressed-scale})) .v-selection-control__input:before --v-hover-opacity: 0.08 @@ -135,25 +131,25 @@ opacity: var(--v-disabled-opacity) .v-switch__track - background-color: $switch-inset-disabled-track-unselected - border-color: $switch-inset-disabled-outline + background-color: $switch-inset-disabled-unselected-track-color + border-color: $switch-inset-disabled-unselected-border-color .v-switch__thumb - background-color: $switch-inset-disabled-handle + background-color: $switch-inset-disabled-unselected-thumb-color .v-icon - color: $switch-inset-disabled-icon-unselected + opacity: .8 .v-selection-control--disabled.v-selection-control--dirty .v-switch__track - background-color: $switch-inset-disabled-track + background-color: $switch-inset-disabled-selected-track-color border-color: transparent .v-switch__thumb - background-color: $switch-inset-disabled-handle-selected + background-color: $switch-inset-disabled-selected-thumb-color .v-icon - color: $switch-inset-disabled-icon + opacity: .4 .v-switch $switch-thumb-transform: $switch-track-width * .5 - $switch-thumb-width * .5 + $switch-thumb-offset @@ -168,6 +164,9 @@ border-radius: 50% transition: $switch-control-input-transition position: absolute + height: calc(var(--v-switch-thumb-height) * 1.666666667) + width: calc(var(--v-switch-thumb-height) * 1.666666667) + @include tools.ltr() transform: translateX(-$switch-thumb-transform) @include tools.rtl() diff --git a/packages/vuetify/src/components/VSwitch/VSwitch.tsx b/packages/vuetify/src/components/VSwitch/VSwitch.tsx index b2fd98b60c8..f0942361d48 100644 --- a/packages/vuetify/src/components/VSwitch/VSwitch.tsx +++ b/packages/vuetify/src/components/VSwitch/VSwitch.tsx @@ -115,6 +115,8 @@ export const VSwitch = genericComponent( const [rootAttrs, controlAttrs] = filterInputAttrs(attrs) const inputProps = VInput.filterProps(props) const controlProps = VSelectionControl.filterProps(props) + const isMaterial = ['material', 'square'].includes(String(props.inset)) + const hasThumbColor = !isForcedColorsModeActive && !!props.thumbColor return ( ( backgroundColorStyles, textColorClasses, textColorStyles, - }) => { - const isMaterial = props.inset === 'material' - const useThumbColor = !isForcedColorsModeActive && !!props.thumbColor && isSelected.value - - return ( + }) => ( <> { inputNode }
( 'v-switch__thumb', { 'v-switch__thumb--filled': icon || props.loading }, isForcedColorsModeActive ? undefined - : useThumbColor ? thumbColorClasses.value + : (hasThumbColor && isSelected.value) ? thumbColorClasses.value : isMaterial ? backgroundColorClasses.value : props.inset ? undefined : backgroundColorClasses.value, ]} - style={ - useThumbColor ? thumbColorStyles.value + style={[ + (hasThumbColor && isSelected.value) ? thumbColorStyles.value : isMaterial ? (backgroundColorClasses.value.length || backgroundColorStyles.value.backgroundColor ? { backgroundColor: 'currentColor' } : undefined) : props.inset ? undefined - : backgroundColorStyles.value - } + : backgroundColorStyles.value, + ]} > { slots.thumb ? ( ( )}
- ) - }, + ), }}
) diff --git a/packages/vuetify/src/components/VSwitch/_variables.scss b/packages/vuetify/src/components/VSwitch/_variables.scss index 670e1215534..4e35dde525c 100644 --- a/packages/vuetify/src/components/VSwitch/_variables.scss +++ b/packages/vuetify/src/components/VSwitch/_variables.scss @@ -10,31 +10,30 @@ $switch-inset-thumb-height: 24px !default; $switch-inset-thumb-width: 24px !default; $switch-inset-thumb-off-height: 16px !default; $switch-inset-thumb-off-width: 16px !default; -$switch-inset-thumb-pressed-height: 28px !default; -$switch-inset-thumb-pressed-width: 28px !default; +$switch-inset-thumb-off-scale: calc(#{$switch-inset-thumb-off-height} / #{$switch-inset-thumb-height}) !default; +$switch-inset-thumb-pressed-scale: calc(28px / #{$switch-inset-thumb-height}) !default; $switch-inset-track-border-radius: 9999px !default; $switch-inset-track-height: 32px !default; $switch-inset-track-width: 52px !default; $switch-inset-track-opacity: 1 !default; - -$switch-inset-track-color: rgb(var(--v-theme-surface-container-highest)) !default; -$switch-inset-outline-color: rgb(var(--v-theme-outline)) !default; $switch-inset-border-width: 2px !default; +$switch-inset-unselected-track-color: color-mix(in srgb, rgb(var(--v-theme-on-surface-variant)) 50%, #888) !default; +$switch-inset-unselected-thumb-color: color-mix(in srgb, rgb(var(--v-theme-surface-variant)) 50%, #888) !default; +$switch-inset-unselected-border-color: $switch-inset-unselected-thumb-color !default; + $switch-inset-selected-track-color: color-mix(in srgb, rgb(var(--v-theme-surface-variant)) 90%, white) !default; -$switch-inset-selected-handle-color: color-mix(in srgb, rgb(var(--v-theme-on-surface-variant)) 80%, white) !default; +$switch-inset-selected-thumb-color: color-mix(in srgb, rgb(var(--v-theme-on-surface-variant)) 80%, white) !default; $switch-focus-outline-color: rgb(var(--v-theme-primary)) !default; $switch-focus-outline-width: 2px !default; $switch-focus-outline-offset: 2px !default; -$switch-inset-disabled-track: rgba(var(--v-theme-on-surface), .12) !default; -$switch-inset-disabled-track-unselected: color-mix(in srgb, #{$switch-inset-track-color} 12%, transparent) !default; -$switch-inset-disabled-outline: rgba(var(--v-theme-on-surface), .12) !default; -$switch-inset-disabled-handle: rgba(var(--v-theme-on-surface), .38) !default; -$switch-inset-disabled-handle-selected: rgb(var(--v-theme-surface)) !default; -$switch-inset-disabled-icon: rgba(var(--v-theme-on-surface), .38) !default; -$switch-inset-disabled-icon-unselected: color-mix(in srgb, #{$switch-inset-track-color} 38%, transparent) !default; +$switch-inset-disabled-unselected-track-color: color-mix(in srgb, #{$switch-inset-unselected-track-color} 12%, transparent) !default; +$switch-inset-disabled-unselected-thumb-color: rgba(var(--v-theme-on-surface), .38) !default; +$switch-inset-disabled-unselected-border-color: rgba(var(--v-theme-on-surface), .12) !default; +$switch-inset-disabled-selected-track-color: rgba(var(--v-theme-on-surface), .12) !default; +$switch-inset-disabled-selected-thumb-color: rgb(var(--v-theme-surface)) !default; $switch-label-margin-inline-start: 10px !default; $switch-loader-color: rgb(var(--v-theme-surface)) !default; diff --git a/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap b/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap index e38b7fb497a..89fdf6e8190 100644 --- a/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap +++ b/packages/vuetify/src/composables/__tests__/__snapshots__/theme.spec.ts.snap @@ -19,11 +19,7 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; - --v-theme-surface-container-highest: 230,224,232; - --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; - --v-theme-outline: 122,116,126; - --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -44,8 +40,6 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; - --v-theme-on-surface-container-highest: 0,0,0; - --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -89,11 +83,7 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; - --v-theme-surface-container-highest: 230,224,232; - --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; - --v-theme-outline: 122,116,126; - --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -114,8 +104,6 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; - --v-theme-on-surface-container-highest: 0,0,0; - --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -159,11 +147,7 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 200,200,200; --v-theme-surface-variant-overlay-multiplier: 2; - --v-theme-surface-container-highest: 72,69,78; - --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 0,0,0; - --v-theme-outline: 147,143,152; - --v-theme-outline-overlay-multiplier: 2; --v-theme-primary: 33,150,243; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 39,124,193; @@ -184,8 +168,6 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 255,255,255; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 255,255,255; - --v-theme-on-surface-container-highest: 255,255,255; - --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -244,16 +226,6 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` background-color: rgb(var(--v-theme-surface-variant)); color: rgb(var(--v-theme-on-surface-variant)); } - .bg-surface-container-highest { - --v-theme-overlay-multiplier: var(--v-theme-surface-container-highest-overlay-multiplier); - background-color: rgb(var(--v-theme-surface-container-highest)); - color: rgb(var(--v-theme-on-surface-container-highest)); - } - .bg-outline { - --v-theme-overlay-multiplier: var(--v-theme-outline-overlay-multiplier); - background-color: rgb(var(--v-theme-outline)); - color: rgb(var(--v-theme-on-outline)); - } .bg-primary { --v-theme-overlay-multiplier: var(--v-theme-primary-overlay-multiplier); background-color: rgb(var(--v-theme-primary)); @@ -326,21 +298,9 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` .border-surface-variant { --v-border-color: var(--v-theme-surface-variant); } - .text-surface-container-highest { - color: rgb(var(--v-theme-surface-container-highest)); - } - .border-surface-container-highest { - --v-border-color: var(--v-theme-surface-container-highest); - } .on-surface-variant { color: rgb(var(--v-theme-on-surface-variant)); } - .text-outline { - color: rgb(var(--v-theme-outline)); - } - .border-outline { - --v-border-color: var(--v-theme-outline); - } .text-primary { color: rgb(var(--v-theme-primary)); } @@ -401,12 +361,6 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` .on-surface-light { color: rgb(var(--v-theme-on-surface-light)); } - .on-surface-container-highest { - color: rgb(var(--v-theme-on-surface-container-highest)); - } - .on-outline { - color: rgb(var(--v-theme-on-outline)); - } .on-primary { color: rgb(var(--v-theme-on-primary)); } @@ -452,11 +406,7 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; - --v-theme-surface-container-highest: 230,224,232; - --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; - --v-theme-outline: 122,116,126; - --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -477,8 +427,6 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; - --v-theme-on-surface-container-highest: 0,0,0; - --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -522,11 +470,7 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; - --v-theme-surface-container-highest: 230,224,232; - --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; - --v-theme-outline: 122,116,126; - --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -547,8 +491,6 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; - --v-theme-on-surface-container-highest: 0,0,0; - --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -592,11 +534,7 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 200,200,200; --v-theme-surface-variant-overlay-multiplier: 2; - --v-theme-surface-container-highest: 72,69,78; - --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 0,0,0; - --v-theme-outline: 147,143,152; - --v-theme-outline-overlay-multiplier: 2; --v-theme-primary: 33,150,243; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 39,124,193; @@ -617,8 +555,6 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` --v-theme-on-surface: 255,255,255; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 255,255,255; - --v-theme-on-surface-container-highest: 255,255,255; - --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -677,16 +613,6 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` background-color: rgb(var(--v-theme-surface-variant)); color: rgb(var(--v-theme-on-surface-variant)); } - :where(#my-app) .bg-surface-container-highest { - --v-theme-overlay-multiplier: var(--v-theme-surface-container-highest-overlay-multiplier); - background-color: rgb(var(--v-theme-surface-container-highest)); - color: rgb(var(--v-theme-on-surface-container-highest)); - } - :where(#my-app) .bg-outline { - --v-theme-overlay-multiplier: var(--v-theme-outline-overlay-multiplier); - background-color: rgb(var(--v-theme-outline)); - color: rgb(var(--v-theme-on-outline)); - } :where(#my-app) .bg-primary { --v-theme-overlay-multiplier: var(--v-theme-primary-overlay-multiplier); background-color: rgb(var(--v-theme-primary)); @@ -759,21 +685,9 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` :where(#my-app) .border-surface-variant { --v-border-color: var(--v-theme-surface-variant); } - :where(#my-app) .text-surface-container-highest { - color: rgb(var(--v-theme-surface-container-highest)); - } - :where(#my-app) .border-surface-container-highest { - --v-border-color: var(--v-theme-surface-container-highest); - } :where(#my-app) .on-surface-variant { color: rgb(var(--v-theme-on-surface-variant)); } - :where(#my-app) .text-outline { - color: rgb(var(--v-theme-outline)); - } - :where(#my-app) .border-outline { - --v-border-color: var(--v-theme-outline); - } :where(#my-app) .text-primary { color: rgb(var(--v-theme-primary)); } @@ -834,12 +748,6 @@ exports[`createTheme > should allow for themes to be scoped 1`] = ` :where(#my-app) .on-surface-light { color: rgb(var(--v-theme-on-surface-light)); } - :where(#my-app) .on-surface-container-highest { - color: rgb(var(--v-theme-on-surface-container-highest)); - } - :where(#my-app) .on-outline { - color: rgb(var(--v-theme-on-outline)); - } :where(#my-app) .on-primary { color: rgb(var(--v-theme-on-primary)); } @@ -890,11 +798,7 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; - --v-theme-surface-container-highest: 230,224,232; - --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; - --v-theme-outline: 122,116,126; - --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -915,8 +819,6 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; - --v-theme-on-surface-container-highest: 0,0,0; - --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -960,11 +862,7 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 66,66,66; --v-theme-surface-variant-overlay-multiplier: 2; - --v-theme-surface-container-highest: 230,224,232; - --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 238,238,238; - --v-theme-outline: 122,116,126; - --v-theme-outline-overlay-multiplier: 1; --v-theme-primary: 24,103,192; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 31,85,146; @@ -985,8 +883,6 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-on-surface: 0,0,0; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 0,0,0; - --v-theme-on-surface-container-highest: 0,0,0; - --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -1030,11 +926,7 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-surface-light-overlay-multiplier: 1; --v-theme-surface-variant: 200,200,200; --v-theme-surface-variant-overlay-multiplier: 2; - --v-theme-surface-container-highest: 72,69,78; - --v-theme-surface-container-highest-overlay-multiplier: 1; --v-theme-on-surface-variant: 0,0,0; - --v-theme-outline: 147,143,152; - --v-theme-outline-overlay-multiplier: 2; --v-theme-primary: 33,150,243; --v-theme-primary-overlay-multiplier: 2; --v-theme-primary-darken-1: 39,124,193; @@ -1055,8 +947,6 @@ exports[`createTheme > should create style element 1`] = ` --v-theme-on-surface: 255,255,255; --v-theme-on-surface-bright: 0,0,0; --v-theme-on-surface-light: 255,255,255; - --v-theme-on-surface-container-highest: 255,255,255; - --v-theme-on-outline: 255,255,255; --v-theme-on-primary: 255,255,255; --v-theme-on-primary-darken-1: 255,255,255; --v-theme-on-secondary: 255,255,255; @@ -1115,16 +1005,6 @@ exports[`createTheme > should create style element 1`] = ` background-color: rgb(var(--v-theme-surface-variant)); color: rgb(var(--v-theme-on-surface-variant)); } - .bg-surface-container-highest { - --v-theme-overlay-multiplier: var(--v-theme-surface-container-highest-overlay-multiplier); - background-color: rgb(var(--v-theme-surface-container-highest)); - color: rgb(var(--v-theme-on-surface-container-highest)); - } - .bg-outline { - --v-theme-overlay-multiplier: var(--v-theme-outline-overlay-multiplier); - background-color: rgb(var(--v-theme-outline)); - color: rgb(var(--v-theme-on-outline)); - } .bg-primary { --v-theme-overlay-multiplier: var(--v-theme-primary-overlay-multiplier); background-color: rgb(var(--v-theme-primary)); @@ -1197,21 +1077,9 @@ exports[`createTheme > should create style element 1`] = ` .border-surface-variant { --v-border-color: var(--v-theme-surface-variant); } - .text-surface-container-highest { - color: rgb(var(--v-theme-surface-container-highest)); - } - .border-surface-container-highest { - --v-border-color: var(--v-theme-surface-container-highest); - } .on-surface-variant { color: rgb(var(--v-theme-on-surface-variant)); } - .text-outline { - color: rgb(var(--v-theme-outline)); - } - .border-outline { - --v-border-color: var(--v-theme-outline); - } .text-primary { color: rgb(var(--v-theme-primary)); } @@ -1272,12 +1140,6 @@ exports[`createTheme > should create style element 1`] = ` .on-surface-light { color: rgb(var(--v-theme-on-surface-light)); } - .on-surface-container-highest { - color: rgb(var(--v-theme-on-surface-container-highest)); - } - .on-outline { - color: rgb(var(--v-theme-on-outline)); - } .on-primary { color: rgb(var(--v-theme-on-primary)); } diff --git a/packages/vuetify/src/composables/theme.ts b/packages/vuetify/src/composables/theme.ts index aa2ab56b425..08b1da29c13 100644 --- a/packages/vuetify/src/composables/theme.ts +++ b/packages/vuetify/src/composables/theme.ts @@ -151,9 +151,7 @@ function genDefaults () { 'surface-bright': '#FFFFFF', 'surface-light': '#EEEEEE', 'surface-variant': '#424242', - 'surface-container-highest': '#E6E0E8', 'on-surface-variant': '#EEEEEE', - outline: '#7A747E', primary: '#1867C0', 'primary-darken-1': '#1F5592', secondary: '#48A9A6', @@ -196,9 +194,7 @@ function genDefaults () { 'surface-bright': '#ccbfd6', 'surface-light': '#424242', 'surface-variant': '#c8c8c8', - 'surface-container-highest': '#48454E', 'on-surface-variant': '#000000', - outline: '#938F98', primary: '#2196F3', 'primary-darken-1': '#277CC1', secondary: '#54B6B2',