Skip to content

Commit

Permalink
feat(theme): add new option to disable variation generation
Browse files Browse the repository at this point in the history
  • Loading branch information
johnleider committed Jun 2, 2020
1 parent af13208 commit d4c311e
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 103 deletions.
4 changes: 4 additions & 0 deletions packages/docs/src/data/pages/customization/Theme.pug
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ h2 optionHeader5
code(lang="html" src="vuetify_csp")
code(lang="js" src="vuetify_csp")

h2 optionHeader6
| optionText7
code(lang="js" src="vuetify_theme_variations")

h2 provideHeading1
| provideText1
doc-api-items(:value=`[
Expand Down
2 changes: 2 additions & 0 deletions packages/docs/src/lang/en/customization/Theme.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"customPropertiesAlert": "Custom properties are not natively supported in Internet Explorer. Polyfills (with some limitations) are available: [https://github.com/nuxodin/ie11CustomProperties](https://github.com/nuxodin/ie11CustomProperties), [https://github.com/jhildenbiddle/css-vars-ponyfill](https://github.com/jhildenbiddle/css-vars-ponyfill).",
"optionHeader5": "### CSP Nonce",
"optionText6": "Pages with the `script-src` or `style-src` CSP rules enabled may require a **nonce** to be specified for embedded style tags.",
"optionHeader6": "### Variations",
"optionText7": "When Vuetify generates your *application's theme*, it creates **9 variants** for each color. For majority of users, these variants are rarely used. This is an **opt in** feature that will be __false by default__ in the next major version.",
"themeGeneratorHeader": "## Theme generator",
"themeGeneratorText1": "Discover and generate new color themes for your **Vuetify** applications using our [Theme Generator](https://theme-generator.vuetifyjs.com) tool.",
"variantsSubheader": "### Custom theme variants",
Expand Down
10 changes: 10 additions & 0 deletions packages/docs/src/snippets/js/vuetify_theme_variations.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// src/plugins/vuetify.js

import Vue from 'vue'
import Vuetify from 'vuetify/lib'

export default new Vuetify({
theme: {
options: { variations: false },
},
})
1 change: 1 addition & 0 deletions packages/vuetify/src/presets/default/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const preset: VuetifyPreset = {
customProperties: undefined,
minifyTheme: undefined,
themeCache: undefined,
variations: true,
},
themes: {
light: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`$vuetify.presets should merge user and default preset 1`] = `"{\\"breakpoint\\":{\\"scrollBarWidth\\":16,\\"thresholds\\":{\\"xs\\":200,\\"sm\\":960,\\"md\\":1280,\\"lg\\":1920}},\\"icons\\":{\\"iconfont\\":\\"md\\",\\"values\\":{\\"complete\\":\\"bar\\"}},\\"lang\\":{\\"current\\":\\"en\\",\\"locales\\":{\\"en\\":{\\"badge\\":\\"Foobar\\",\\"close\\":\\"Close\\",\\"dataIterator\\":{\\"noResultsText\\":\\"Fizzbuzz\\",\\"loadingText\\":\\"Loading items...\\"},\\"dataTable\\":{\\"itemsPerPageText\\":\\"Rows per page:\\",\\"ariaLabel\\":{\\"sortDescending\\":\\"Sorted descending.\\",\\"sortAscending\\":\\"Sorted ascending.\\",\\"sortNone\\":\\"Not sorted.\\",\\"activateNone\\":\\"Activate to remove sorting.\\",\\"activateDescending\\":\\"Activate to sort descending.\\",\\"activateAscending\\":\\"Activate to sort ascending.\\"},\\"sortBy\\":\\"Sort by\\"},\\"dataFooter\\":{\\"itemsPerPageText\\":\\"Items per page:\\",\\"itemsPerPageAll\\":\\"All\\",\\"nextPage\\":\\"Next page\\",\\"prevPage\\":\\"Previous page\\",\\"firstPage\\":\\"First page\\",\\"lastPage\\":\\"Last page\\",\\"pageText\\":\\"{0}-{1} of {2}\\"},\\"datePicker\\":{\\"itemsSelected\\":\\"{0} selected\\",\\"nextMonthAriaLabel\\":\\"Next month\\",\\"nextYearAriaLabel\\":\\"Next year\\",\\"prevMonthAriaLabel\\":\\"Previous month\\",\\"prevYearAriaLabel\\":\\"Previous year\\"},\\"noDataText\\":\\"No data available\\",\\"carousel\\":{\\"prev\\":\\"Previous visual\\",\\"next\\":\\"Next visual\\",\\"ariaLabel\\":{\\"delimiter\\":\\"Carousel slide {0} of {1}\\"}},\\"calendar\\":{\\"moreEvents\\":\\"{0} more\\"},\\"fileInput\\":{\\"counter\\":\\"{0} files\\",\\"counterSize\\":\\"{0} files ({1} in total)\\"},\\"timePicker\\":{\\"am\\":\\"AM\\",\\"pm\\":\\"PM\\"},\\"pagination\\":{\\"ariaLabel\\":{\\"wrapper\\":\\"Pagination Navigation\\",\\"next\\":\\"Next page\\",\\"previous\\":\\"Previous page\\",\\"page\\":\\"Goto Page {0}\\",\\"currentPage\\":\\"Current Page, Page {0}\\"}}}}},\\"rtl\\":true,\\"theme\\":{\\"dark\\":true,\\"default\\":\\"light\\",\\"disable\\":false,\\"options\\":{},\\"themes\\":{\\"light\\":{\\"primary\\":\\"blue\\",\\"secondary\\":{\\"darken4\\":\\"red\\"},\\"accent\\":\\"#82B1FF\\",\\"error\\":\\"#FF5252\\",\\"info\\":\\"#2196F3\\",\\"success\\":\\"#4CAF50\\",\\"warning\\":\\"#FB8C00\\"},\\"dark\\":{\\"primary\\":\\"#2196F3\\",\\"secondary\\":\\"#424242\\",\\"accent\\":\\"#FF4081\\",\\"error\\":\\"#FF5252\\",\\"info\\":\\"#2196F3\\",\\"success\\":\\"#4CAF50\\",\\"warning\\":\\"#FB8C00\\"}}}}"`;
exports[`$vuetify.presets should merge user and default preset 1`] = `"{\\"breakpoint\\":{\\"scrollBarWidth\\":16,\\"thresholds\\":{\\"xs\\":200,\\"sm\\":960,\\"md\\":1280,\\"lg\\":1920}},\\"icons\\":{\\"iconfont\\":\\"md\\",\\"values\\":{\\"complete\\":\\"bar\\"}},\\"lang\\":{\\"current\\":\\"en\\",\\"locales\\":{\\"en\\":{\\"badge\\":\\"Foobar\\",\\"close\\":\\"Close\\",\\"dataIterator\\":{\\"noResultsText\\":\\"Fizzbuzz\\",\\"loadingText\\":\\"Loading items...\\"},\\"dataTable\\":{\\"itemsPerPageText\\":\\"Rows per page:\\",\\"ariaLabel\\":{\\"sortDescending\\":\\"Sorted descending.\\",\\"sortAscending\\":\\"Sorted ascending.\\",\\"sortNone\\":\\"Not sorted.\\",\\"activateNone\\":\\"Activate to remove sorting.\\",\\"activateDescending\\":\\"Activate to sort descending.\\",\\"activateAscending\\":\\"Activate to sort ascending.\\"},\\"sortBy\\":\\"Sort by\\"},\\"dataFooter\\":{\\"itemsPerPageText\\":\\"Items per page:\\",\\"itemsPerPageAll\\":\\"All\\",\\"nextPage\\":\\"Next page\\",\\"prevPage\\":\\"Previous page\\",\\"firstPage\\":\\"First page\\",\\"lastPage\\":\\"Last page\\",\\"pageText\\":\\"{0}-{1} of {2}\\"},\\"datePicker\\":{\\"itemsSelected\\":\\"{0} selected\\",\\"nextMonthAriaLabel\\":\\"Next month\\",\\"nextYearAriaLabel\\":\\"Next year\\",\\"prevMonthAriaLabel\\":\\"Previous month\\",\\"prevYearAriaLabel\\":\\"Previous year\\"},\\"noDataText\\":\\"No data available\\",\\"carousel\\":{\\"prev\\":\\"Previous visual\\",\\"next\\":\\"Next visual\\",\\"ariaLabel\\":{\\"delimiter\\":\\"Carousel slide {0} of {1}\\"}},\\"calendar\\":{\\"moreEvents\\":\\"{0} more\\"},\\"fileInput\\":{\\"counter\\":\\"{0} files\\",\\"counterSize\\":\\"{0} files ({1} in total)\\"},\\"timePicker\\":{\\"am\\":\\"AM\\",\\"pm\\":\\"PM\\"},\\"pagination\\":{\\"ariaLabel\\":{\\"wrapper\\":\\"Pagination Navigation\\",\\"next\\":\\"Next page\\",\\"previous\\":\\"Previous page\\",\\"page\\":\\"Goto Page {0}\\",\\"currentPage\\":\\"Current Page, Page {0}\\"}}}}},\\"rtl\\":true,\\"theme\\":{\\"dark\\":true,\\"default\\":\\"light\\",\\"disable\\":false,\\"options\\":{\\"variations\\":true},\\"themes\\":{\\"light\\":{\\"primary\\":\\"blue\\",\\"secondary\\":{\\"darken4\\":\\"red\\"},\\"accent\\":\\"#82B1FF\\",\\"error\\":\\"#FF5252\\",\\"info\\":\\"#2196F3\\",\\"success\\":\\"#4CAF50\\",\\"warning\\":\\"#FB8C00\\"},\\"dark\\":{\\"primary\\":\\"#2196F3\\",\\"secondary\\":\\"#424242\\",\\"accent\\":\\"#FF4081\\",\\"error\\":\\"#FF5252\\",\\"info\\":\\"#2196F3\\",\\"success\\":\\"#4CAF50\\",\\"warning\\":\\"#FB8C00\\"}}}}"`;

exports[`$vuetify.presets should merge user and default preset 2`] = `undefined`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1696,6 +1696,66 @@ exports[`Theme.ts should minify theme 1`] = `
}foobar"
`;

exports[`Theme.ts should not generate variations 1`] = `
".v-application a { color: 1668818; }
.v-application .primary {
background-color: 1668818 !important;
border-color: 1668818 !important;
}
.v-application .primary--text {
color: 1668818 !important;
caret-color: 1668818 !important;
}
.v-application .secondary {
background-color: 4342338 !important;
border-color: 4342338 !important;
}
.v-application .secondary--text {
color: 4342338 !important;
caret-color: 4342338 !important;
}
.v-application .accent {
background-color: 8565247 !important;
border-color: 8565247 !important;
}
.v-application .accent--text {
color: 8565247 !important;
caret-color: 8565247 !important;
}
.v-application .error {
background-color: 16732754 !important;
border-color: 16732754 !important;
}
.v-application .error--text {
color: 16732754 !important;
caret-color: 16732754 !important;
}
.v-application .info {
background-color: 2201331 !important;
border-color: 2201331 !important;
}
.v-application .info--text {
color: 2201331 !important;
caret-color: 2201331 !important;
}
.v-application .success {
background-color: 5025616 !important;
border-color: 5025616 !important;
}
.v-application .success--text {
color: 5025616 !important;
caret-color: 5025616 !important;
}
.v-application .warning {
background-color: 16761095 !important;
border-color: 16761095 !important;
}
.v-application .warning--text {
color: 16761095 !important;
caret-color: 16761095 !important;
}"
`;

exports[`Theme.ts should reset themes 1`] = `
".v-application a { color: #1976d2; }
.v-application .primary {
Expand Down
156 changes: 67 additions & 89 deletions packages/vuetify/src/services/theme/__tests__/theme.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ import { Theme } from '../index'
// Preset
import { preset } from '../../../presets/default'

// Utilities
import { mergeDeep } from '../../../util/helpers'

// Types
import Vue from 'vue'
import {
VuetifyParsedTheme,
VuetifyThemeVariant,
ThemeOptions,
} from 'vuetify/types/services/theme'

const FillVariant = (variant: Partial<VuetifyThemeVariant> = {}) => {
Expand All @@ -25,49 +29,53 @@ const FillVariant = (variant: Partial<VuetifyThemeVariant> = {}) => {
}

describe('Theme.ts', () => {
let mock: any
function rootFactory () {
return mergeDeep(JSON.parse(JSON.stringify(preset)), {
theme: {
default: 'light',
themes: {
dark: FillVariant(),
light: FillVariant(),
},
},
})
}

let mockTheme: (theme?: Partial<ThemeOptions>) => Theme
let instance: Vue

beforeEach(() => {
const style = document.getElementById('vuetify-theme-stylesheet')
mockTheme = (theme?: Partial<ThemeOptions>) => {
const options = { theme: theme || {} }

if (style) {
style.remove()
}

mock = {
default: 'light',
themes: {
dark: FillVariant(),
light: FillVariant(),
},
return new Theme(mergeDeep(rootFactory(), options))
}

instance = new Vue()
})

afterEach(() => {
const style = document.getElementById('vuetify-theme-stylesheet')

style && style.remove()
})

it('should disable theme colors', () => {
const theme = new Theme({
...preset,
theme: { disable: true },
})
const theme = mockTheme({ disable: true })

theme.init(instance)

expect(theme.styleEl).toBeFalsy()
})

it('should generate theme and apply to document', () => {
const theme = new Theme({
...preset,
theme: {
themes: {
light: FillVariant({
primary: '#000001',
secondary: '#000002',
accent: '#000003',
}),
},
const theme = mockTheme({
themes: {
light: FillVariant({
primary: '#000001',
secondary: '#000002',
accent: '#000003',
}),
},
})

Expand All @@ -83,16 +91,13 @@ describe('Theme.ts', () => {
})

it('should apply a new theme', () => {
const theme = new Theme({
...preset,
theme: {
default: 'light',
themes: {
light: FillVariant(),
dark: FillVariant({
primary: '#FFFFFF',
}),
},
const theme = mockTheme({
default: 'light',
themes: {
light: FillVariant(),
dark: FillVariant({
primary: '#FFFFFF',
}),
},
})

Expand All @@ -107,7 +112,7 @@ describe('Theme.ts', () => {
})

it('should clear css', () => {
const theme = new Theme(preset)
const theme = mockTheme()
const spy = jest.spyOn(theme, 'clearCss')

theme.dark = true
Expand All @@ -131,14 +136,8 @@ describe('Theme.ts', () => {
}),
}

const theme = new Theme({
...preset,
theme: {
...mock,
options: {
themeCache,
},
},
const theme = mockTheme({
options: { themeCache },
})

expect(theme.generatedStyles).toMatchSnapshot()
Expand All @@ -154,14 +153,8 @@ describe('Theme.ts', () => {
it('should minify theme', () => {
const minifyTheme = jest.fn((css: string) => css + 'foobar')

const theme = new Theme({
...preset,
theme: {
...mock,
options: {
minifyTheme,
},
},
const theme = mockTheme({
options: { minifyTheme },
})

theme.init(instance)
Expand All @@ -175,27 +168,19 @@ describe('Theme.ts', () => {
})

it('should add nonce to stylesheet', () => {
const theme = new Theme({
...preset,
theme: {
...mock,
options: {
cspNonce: 'foobar',
},
},
const theme = mockTheme({
options: { cspNonce: 'foobar' },
})

theme.init(instance)

const style = document.getElementById('vuetify-theme-stylesheet')

expect(style!.getAttribute('nonce')).toBe('foobar')
})

it('should initialize the theme', () => {
const theme = new Theme({
...preset,
theme: { ...mock },
})
const theme = mockTheme()
const spy = jest.spyOn(theme, 'applyTheme')
const ssrContext = { head: '' }
theme.init(instance, ssrContext)
Expand All @@ -206,10 +191,7 @@ describe('Theme.ts', () => {
})

it('should set theme with vue-meta@1', () => {
const theme = new Theme({
...preset,
theme: mock,
})
const theme = mockTheme()
const anyInstance = instance as any

anyInstance.$meta = () => ({})
Expand All @@ -226,10 +208,7 @@ describe('Theme.ts', () => {
})

it('should set theme with vue-meta@2', () => {
const theme = new Theme({
...preset,
theme: mock,
})
const theme = mockTheme()
const anyInstance = instance as any

anyInstance.$meta = () => ({
Expand All @@ -250,10 +229,7 @@ describe('Theme.ts', () => {
})

it('should react to theme changes', async () => {
const theme = new Theme({
...preset,
theme: mock,
})
const theme = mockTheme()
const spy = jest.spyOn(theme, 'applyTheme')
theme.init(instance)

Expand All @@ -272,10 +248,7 @@ describe('Theme.ts', () => {
})

it('should reset themes', async () => {
const theme = new Theme({
...preset,
theme: mock,
})
const theme = mockTheme()
const spy = jest.spyOn(theme, 'applyTheme')
theme.init(instance)

Expand All @@ -286,10 +259,7 @@ describe('Theme.ts', () => {
})

it('should set theme', () => {
const theme = new Theme({
...preset,
theme: mock,
})
const theme = mockTheme()
const spy = jest.spyOn(theme, 'applyTheme')
theme.init(instance)

Expand All @@ -302,10 +272,7 @@ describe('Theme.ts', () => {
})

it('should use vue-meta@2.3 functionality', () => {
const theme = new Theme({
...preset,
theme: mock,
})
const theme = mockTheme()
const set = jest.fn()

const $meta = () => ({
Expand All @@ -318,4 +285,15 @@ describe('Theme.ts', () => {

expect(set).toHaveBeenCalled()
})

it('should not generate variations', () => {
const theme = mockTheme({ options: { variations: false } })

theme.init(instance)

const style = document.getElementById('vuetify-theme-stylesheet')
const html = style!.innerHTML

expect(html).toMatchSnapshot()
})
})
Loading

0 comments on commit d4c311e

Please sign in to comment.