diff --git a/.stylelintrc.json b/.stylelintrc.json
new file mode 100644
index 0000000000..9fb2c5fe19
--- /dev/null
+++ b/.stylelintrc.json
@@ -0,0 +1,30 @@
+{
+ "extends": [
+ "stylelint-config-standard",
+ "stylelint-config-rational-order"
+ ],
+ "plugins": [
+ "stylelint-order",
+ "stylelint-scss"
+ ],
+ "rules": {
+ "indentation": "tab",
+ "order/order": [
+ "dollar-variables",
+ "custom-properties",
+ "declarations",
+ "at-variables",
+ "rules",
+ "at-rules"
+ ],
+ "at-rule-no-unknown": null,
+ "scss/at-rule-no-unknown": true,
+ "selector-pseudo-element-no-unknown": [
+ true,
+ {
+ "ignorePseudoElements": ["v-deep"]
+ }
+ ],
+ "string-quotes": "single"
+ }
+}
diff --git a/package.json b/package.json
index 02ce474533..5f54f64291 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,9 @@
"build": "vue-cli-service build",
"test": "vue-cli-service test:unit",
"lint": "vue-cli-service lint",
+ "lint:styles": "stylelint \"**/*.{vue,scss}\"",
"fix": "prettier --write \"src/**/*.{js,vue,ts}\"",
+ "fix:styles": "stylelint --fix \"**/*.{vue,scss}\"",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
},
@@ -69,6 +71,11 @@
"sass": "^1.23.7",
"sass-loader": "^8.0.0",
"storybook-addon-themes": "^5.3.0",
+ "stylelint": "^13.1.0",
+ "stylelint-config-rational-order": "^0.1.2",
+ "stylelint-config-standard": "^20.0.0",
+ "stylelint-order": "^4.0.0",
+ "stylelint-scss": "^3.14.2",
"typescript": "^3.7.4",
"vue-cli-plugin-storybook": "^1.1.0",
"vue-loader": "^15.8.3",
@@ -81,9 +88,18 @@
"pre-commit": "lint-staged"
},
"lint-staged": {
- "*.{js,vue,ts}": [
+ "*.{js,ts}": [
"vue-cli-service lint",
"git add"
+ ],
+ "*.{scss}": [
+ "stylelint --fix",
+ "git add"
+ ],
+ "*.vue": [
+ "vue-cli-service lint",
+ "stylelint --fix",
+ "git add"
]
}
}
diff --git a/src/components/v-avatar/v-avatar.vue b/src/components/v-avatar/v-avatar.vue
index 3be0c198c1..38fa358337 100644
--- a/src/components/v-avatar/v-avatar.vue
+++ b/src/components/v-avatar/v-avatar.vue
@@ -33,18 +33,18 @@ export default createComponent({
--v-avatar-color: var(--teal);
--v-avatar-size: 48px;
- background-color: var(--v-avatar-color);
- display: flex;
- justify-content: center;
- align-items: center;
position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
width: var(--v-avatar-size);
height: var(--v-avatar-size);
- border-radius: 50%;
overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
color: var(--white);
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ background-color: var(--v-avatar-color);
+ border-radius: 50%;
&.tile {
border-radius: 0;
diff --git a/src/components/v-button/v-button.vue b/src/components/v-button/v-button.vue
index 47b6eb652e..17941ebe00 100644
--- a/src/components/v-button/v-button.vue
+++ b/src/components/v-button/v-button.vue
@@ -69,28 +69,32 @@ export default createComponent({
--v-button-hover-background-color: var(--button-primary-background-color-hover);
--v-button-font-size: 16px;
- color: var(--v-button-color);
- background-color: var(--v-button-background-color);
- border-radius: var(--border-radius);
- font-weight: var(--weight-bold);
- cursor: pointer;
- border: var(--input-border-width) solid var(--v-button-background-color);
-
- font-size: var(--v-button-font-size);
- padding: 0 19px;
- min-width: 78px;
+ position: relative;
width: var(--v-button-width);
+ min-width: 78px;
height: var(--v-button-height);
-
+ padding: 0 19px;
+ color: var(--v-button-color);
+ font-weight: var(--weight-bold);
+ font-size: var(--v-button-font-size);
+ background-color: var(--v-button-background-color);
+ border: var(--input-border-width) solid var(--v-button-background-color);
+ border-radius: var(--border-radius);
+ cursor: pointer;
transition: var(--fast) var(--transition);
transition-property: background-color border;
- position: relative;
-
&:focus {
outline: 0;
}
+ &:disabled {
+ color: var(--button-primary-text-color-disabled);
+ background-color: var(--button-primary-background-color-disabled);
+ border: var(--input-border-width) solid var(--button-primary-background-color-disabled);
+ cursor: not-allowed;
+ }
+
&:not(.loading):not(:disabled):hover {
color: var(--v-button-hover-color);
background-color: var(--v-button-hover-background-color);
@@ -110,52 +114,49 @@ export default createComponent({
background-color: transparent;
}
- &:disabled {
- background-color: var(--button-primary-background-color-disabled);
- border: var(--input-border-width) solid var(--button-primary-background-color-disabled);
- color: var(--button-primary-text-color-disabled);
- cursor: not-allowed;
- }
-
&.x-small {
--v-button-height: 28px;
--v-button-font-size: 12px;
- padding: 0 12px;
+
min-width: 48px;
+ padding: 0 12px;
}
&.small {
--v-button-height: 36px;
--v-button-font-size: 14px;
- padding: 0 16px;
+
min-width: 64px;
+ padding: 0 16px;
}
&.large {
--v-button-height: 52px;
- padding: 0 23px;
+
min-width: 92px;
+ padding: 0 23px;
}
&.x-large {
--v-button-height: 58px;
--v-button-font-size: 18px;
- padding: 0 32px;
+
min-width: 120px;
+ padding: 0 32px;
}
&.icon {
+ width: var(--v-button-height);
min-width: 0;
padding: 0;
- width: var(--v-button-height);
}
.content,
.spinner {
+ max-width: 100%;
+ overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
- overflow: hidden;
- max-width: 100%;
}
.content {
diff --git a/src/components/v-checkbox/v-checkbox.vue b/src/components/v-checkbox/v-checkbox.vue
index a0779a3640..0e1422547b 100644
--- a/src/components/v-checkbox/v-checkbox.vue
+++ b/src/components/v-checkbox/v-checkbox.vue
@@ -89,22 +89,22 @@ export default createComponent({
.v-checkbox {
--v-checkbox-color: var(--input-background-color-active);
- font-size: 0;
- appearance: none;
- background-color: transparent;
- border-radius: 0;
- border: none;
display: flex;
align-items: center;
+ font-size: 0;
text-align: left;
+ background-color: transparent;
+ border: none;
+ border-radius: 0;
+ appearance: none;
.label:not(:empty) {
- font-size: var(--input-font-size);
margin-left: 8px;
- vertical-align: middle;
+ overflow: hidden;
+ font-size: var(--input-font-size);
white-space: nowrap;
text-overflow: ellipsis;
- overflow: hidden;
+ vertical-align: middle;
}
& .v-icon {
diff --git a/src/components/v-chip/v-chip.vue b/src/components/v-chip/v-chip.vue
index e53c32bb8a..d3706dcecf 100644
--- a/src/components/v-chip/v-chip.vue
+++ b/src/components/v-chip/v-chip.vue
@@ -92,14 +92,13 @@ export default createComponent({
--v-chip-hover-background-color: var(--chip-primary-background-color-hover);
display: inline-flex;
+ align-items: center;
height: 32px;
padding: 0 12px;
- align-items: center;
-
color: var(--v-chip-color);
+ font-weight: var(--weight-normal);
background-color: var(--v-chip-background-color);
border-radius: 16px;
- font-weight: var(--weight-normal);
&:hover {
color: var(--v-chip-hover-color);
@@ -121,26 +120,26 @@ export default createComponent({
}
&.x-small {
- font-size: 12px;
height: 20px;
+ font-size: 12px;
border-radius: 10px;
}
&.small {
- font-size: 14px;
height: 24px;
+ font-size: 14px;
border-radius: 12px;
}
&.large {
- font-size: 16px;
height: 44px;
+ font-size: 16px;
border-radius: 22px;
}
&.x-large {
- font-size: 18px;
height: 48px;
+ font-size: 18px;
border-radius: 24px;
}
@@ -150,16 +149,15 @@ export default createComponent({
.close-outline {
position: relative;
+ right: -4px;
display: inline-flex;
- justify-content: center;
align-items: center;
-
+ justify-content: center;
+ width: 14px;
+ height: 14px;
+ margin-left: 4px;
background-color: var(--chip-primary-close-color);
border-radius: 10px;
- height: 14px;
- width: 14px;
- right: -4px;
- margin-left: 4px;
.close {
--v-icon-color: var(--v-chip-background-color);
diff --git a/src/components/v-icon/v-icon.vue b/src/components/v-icon/v-icon.vue
index 66d79a0b76..bd476a59dd 100644
--- a/src/components/v-icon/v-icon.vue
+++ b/src/components/v-icon/v-icon.vue
@@ -76,29 +76,31 @@ export default createComponent({
--v-icon-color: currentColor;
--v-icon-size: 24px;
- color: var(--v-icon-color);
position: relative;
display: inline-block;
- font-size: 0;
width: var(--v-icon-size);
height: var(--v-icon-size);
+ color: var(--v-icon-color);
+ font-size: 0;
vertical-align: middle;
i {
- font-size: var(--v-icon-size);
- font-family: 'Material Icons';
- font-weight: normal;
- font-style: normal;
display: inline-block;
+ font-weight: normal;
+ font-size: var(--v-icon-size);
+ /* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */
+ font-family: 'Material Icons';
+ font-style: normal;
line-height: 1;
- text-transform: none;
letter-spacing: normal;
- word-wrap: normal;
white-space: nowrap;
- font-feature-settings: 'liga';
+ text-transform: none;
vertical-align: middle;
+ word-wrap: normal;
+ font-feature-settings: 'liga';
&.outline {
+ /* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */
font-family: 'Material Icons Outline';
}
}
@@ -119,7 +121,8 @@ export default createComponent({
&.sup {
--v-icon-size: 8px;
- vertical-align: 0px;
+
+ vertical-align: 0;
i {
vertical-align: 5px;
@@ -148,8 +151,8 @@ export default createComponent({
}
&.right {
- margin-left: 8px;
margin-right: -4px;
+ margin-left: 8px;
}
}
diff --git a/src/components/v-input/v-input.vue b/src/components/v-input/v-input.vue
index fe2ff96c4e..a7371e5450 100644
--- a/src/components/v-input/v-input.vue
+++ b/src/components/v-input/v-input.vue
@@ -87,13 +87,13 @@ export default createComponent({
}
.input {
- height: 100%;
display: flex;
align-items: center;
- border: var(--input-border-width) solid var(--input-border-color);
- background-color: var(--input-background-color);
- border-radius: var(--border-radius);
+ height: 100%;
padding: var(--input-padding);
+ background-color: var(--input-background-color);
+ border: var(--input-border-width) solid var(--input-border-color);
+ border-radius: var(--border-radius);
transition: border-color var(--fast) var(--transition);
.prepend {
@@ -116,20 +116,20 @@ export default createComponent({
width: 100%;
}
+ input {
+ flex-grow: 1;
+ height: 100%;
+ background-color: transparent;
+ border: none;
+ appearance: none;
+ }
+
&.monospace {
input {
font-family: var(--family-monospace);
}
}
- input {
- appearance: none;
- flex-grow: 1;
- height: 100%;
- border: none;
- background-color: transparent;
- }
-
.prefix,
.suffix {
color: var(--input-border-color-focus);
diff --git a/src/components/v-overlay/v-overlay.vue b/src/components/v-overlay/v-overlay.vue
index 5fcd22ac15..245adf2246 100644
--- a/src/components/v-overlay/v-overlay.vue
+++ b/src/components/v-overlay/v-overlay.vue
@@ -41,13 +41,13 @@ export default createComponent({
position: fixed;
top: 0;
left: 0;
+ z-index: var(--v-overlay-z-index);
+ display: flex;
+ align-items: center;
+ justify-content: center;
width: 100%;
height: 100%;
pointer-events: none;
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: var(--v-overlay-z-index);
&.has-click {
cursor: pointer;
diff --git a/src/components/v-progress/linear/v-progress-linear.vue b/src/components/v-progress/linear/v-progress-linear.vue
index 144ed3ac19..544fe9d49b 100644
--- a/src/components/v-progress/linear/v-progress-linear.vue
+++ b/src/components/v-progress/linear/v-progress-linear.vue
@@ -65,19 +65,19 @@ export default createComponent({
--v-progress-linear-color: var(--progress-background-color-accent);
--v-progress-linear-background-color: var(--progress-background-color);
- background-color: var(--v-progress-linear-background-color);
- height: var(--v-progress-linear-height);
position: relative;
- width: 100%;
display: flex;
- justify-content: center;
align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: var(--v-progress-linear-height);
overflow: hidden;
+ background-color: var(--v-progress-linear-background-color);
.inner {
+ position: absolute;
top: 0;
left: 0;
- position: absolute;
height: 100%;
background-color: var(--v-progress-linear-color);
}
@@ -87,7 +87,7 @@ export default createComponent({
}
&.bottom {
- bottom: 0px;
+ bottom: 0;
}
&.fixed {
@@ -95,11 +95,11 @@ export default createComponent({
}
&.indeterminate .inner {
+ position: relative;
width: 100% !important;
transform-origin: left;
- will-change: transform;
animation: indeterminate 2s infinite;
- position: relative;
+ will-change: transform;
}
&.rounded,
@@ -108,7 +108,7 @@ export default createComponent({
}
&.top {
- top: 0px;
+ top: 0;
}
}
@@ -117,10 +117,12 @@ export default createComponent({
transform: scaleX(0);
animation-timing-function: cubic-bezier(0.1, 0.6, 0.9, 0.5);
}
+
50% {
transform: scaleX(1) translateX(25%);
animation-timing-function: cubic-bezier(0.4, 0.1, 0.2, 0.9);
}
+
100% {
transform: scaleX(1) translateX(100%);
animation-timing-function: cubic-bezier(0.1, 0.6, 0.9, 0.5);
diff --git a/src/components/v-sheet/v-sheet.vue b/src/components/v-sheet/v-sheet.vue
index ddf03cfb70..15cfb7814c 100644
--- a/src/components/v-sheet/v-sheet.vue
+++ b/src/components/v-sheet/v-sheet.vue
@@ -13,26 +13,22 @@ export default createComponent({});
diff --git a/src/components/v-slider/v-slider.vue b/src/components/v-slider/v-slider.vue
index 937a844f49..f1fd90b40c 100644
--- a/src/components/v-slider/v-slider.vue
+++ b/src/components/v-slider/v-slider.vue
@@ -101,96 +101,98 @@ export default createComponent({
}
.slider {
- flex-grow: 1;
position: relative;
top: -3px;
+ flex-grow: 1;
input {
- -webkit-appearance: none;
- appearance: none;
width: 100%;
height: 2px;
-
- /*
- * The vendor specific styling for the tracks needs to be separate into individual
- * statements. In browsers, if one of the statements is unknown, the whole selector is
- * invalidated. We're using these 'local' mixins to facilitate that.
- */
-
- @mixin v-slider-track {
- height: 2px;
- background: var(--v-slider-color);
- box-shadow: none;
- border: none;
- border-radius: 2px;
- }
+ -webkit-appearance: none;
+ appearance: none;
&::-webkit-slider-runnable-track {
- @include v-slider-track;
+ height: 2px;
+ background: var(--v-slider-color);
+ border: none;
+ border-radius: 2px;
+ box-shadow: none;
}
&::-moz-range-track {
- @include v-slider-track;
- }
-
- @mixin v-slider-thumb {
- -webkit-appearance: none;
- appearance: none;
- box-shadow: none;
+ height: 2px;
+ background: var(--v-slider-color);
border: none;
- height: 14px;
- width: 14px;
- border-radius: 50%;
- background: var(--v-slider-thumb-color);
- margin-top: -6px;
- cursor: ew-resize;
- box-shadow: 0 0 0 4px var(--input-background-color);
- z-index: 3;
- position: relative;
+ border-radius: 2px;
+ box-shadow: none;
}
&::-webkit-slider-thumb {
- @include v-slider-thumb;
+ position: relative;
+ z-index: 3;
+ width: 14px;
+ height: 14px;
+ margin-top: -6px;
+ background: var(--v-slider-thumb-color);
+ border: none;
+ border-radius: 50%;
+ box-shadow: none;
+ box-shadow: 0 0 0 4px var(--input-background-color);
+ cursor: ew-resize;
+ -webkit-appearance: none;
+ appearance: none;
}
&::-moz-range-thumb {
- @include v-slider-thumb;
+ position: relative;
+ z-index: 3;
+ width: 14px;
+ height: 14px;
+ margin-top: -6px;
+ background: var(--v-slider-thumb-color);
+ border: none;
+ border-radius: 50%;
+ box-shadow: none;
+ box-shadow: 0 0 0 4px var(--input-background-color);
+ cursor: ew-resize;
+ -webkit-appearance: none;
+ appearance: none;
}
}
.fill {
position: absolute;
- left: 0;
- right: 0;
top: 50%;
- transform: translateY(2px) scaleX(calc(var(--_v-slider-percentage) / 100));
- transform-origin: left;
+ right: 0;
+ left: 0;
+ z-index: 2;
height: 2px;
background-color: var(--v-slider-fill-color);
+ transform: translateY(2px) scaleX(calc(var(--_v-slider-percentage) / 100));
+ transform-origin: left;
pointer-events: none;
- z-index: 2;
}
.ticks {
- opacity: 0;
position: absolute;
top: 11px;
left: 0;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
width: 100%;
height: 4px;
- pointer-events: none;
- display: flex;
- justify-content: space-between;
- align-items: center;
padding: 0 7px;
+ opacity: 0;
transition: opacity var(--fast) var(--transition);
+ pointer-events: none;
.tick {
display: inline-block;
width: 4px;
height: 4px;
- border-radius: 50%;
background-color: var(--v-slider-fill-color);
+ border-radius: 50%;
}
}
@@ -203,29 +205,29 @@ export default createComponent({
}
.thumb-label {
- opacity: 0;
position: absolute;
- width: max-content;
- left: calc(var(--_v-slider-percentage) * 1%);
- transform: translateX(-50%);
top: 10px;
+ left: calc(var(--_v-slider-percentage) * 1%);
+ width: max-content;
+ padding: 4px 8px;
color: var(--input-text-color);
+ font-size: var(--input-font-size);
background-color: var(--input-background-color-alt);
border-radius: var(--border-radius);
- font-size: var(--input-font-size);
- padding: 4px 8px;
+ transform: translateX(-50%);
+ opacity: 0;
transition: opacity var(--fast) var(--transition);
- &:before {
- content: '';
+ &::before {
position: absolute;
top: -4px;
left: calc(50%);
width: 10px;
height: 10px;
+ background-color: var(--input-background-color-alt);
border-radius: var(--border-radius);
transform: translateX(-50%) rotate(45deg);
- background-color: var(--input-background-color-alt);
+ content: '';
}
}
diff --git a/src/components/v-spinner/v-spinner.vue b/src/components/v-spinner/v-spinner.vue
index ea72e0e981..30d0fe36c2 100644
--- a/src/components/v-spinner/v-spinner.vue
+++ b/src/components/v-spinner/v-spinner.vue
@@ -20,20 +20,17 @@ export default createComponent({
.v-spinner {
--v-spinner-color: var(--loading-background-color-accent);
--v-spinner-background-color: var(--loading-background-color);
-
--v-spinner-speed: 1s;
--v-spinner-size: 28px;
--v-spinner-line-size: 3px;
+ position: relative;
width: var(--v-spinner-size);
height: var(--v-spinner-size);
- position: relative;
-
- border-radius: 100%;
+ background-color: transparent;
border: var(--v-spinner-line-size) solid var(--v-spinner-background-color);
border-top: var(--v-spinner-line-size) solid var(--v-spinner-color);
- background-color: transparent;
-
+ border-radius: 100%;
animation: rotate var(--v-spinner-speed) infinite linear;
&.x-small {
diff --git a/src/components/v-switch/v-switch.vue b/src/components/v-switch/v-switch.vue
index f8f2a7ee37..ccb68c214b 100644
--- a/src/components/v-switch/v-switch.vue
+++ b/src/components/v-switch/v-switch.vue
@@ -75,67 +75,60 @@ export default createComponent({
.v-switch {
--v-switch-color: var(--input-background-color-active);
- font-size: 0;
- appearance: none;
- background-color: transparent;
- border-radius: 0;
- border: none;
display: flex;
align-items: center;
+ font-size: 0;
+ background-color: transparent;
+ border: none;
+ border-radius: 0;
+ appearance: none;
.switch {
- display: inline-block;
- height: 24px;
- width: 44px;
- border-radius: 12px;
- border: var(--input-border-width) solid var(--input-border-color);
position: relative;
+ display: inline-block;
+ width: 44px;
+ height: 24px;
+ vertical-align: middle;
+ border: var(--input-border-width) solid var(--input-border-color);
+ border-radius: 12px;
transition: var(--fast) var(--transition);
transition-property: background-color border;
- vertical-align: middle;
-
- &:not(:disabled)hover {
- border-color: var(--input-border-color-hover);
- }
&:focus {
outline: 0;
}
&::after {
- content: '';
- width: 16px;
- height: 16px;
position: absolute;
top: 2px;
left: 2px;
display: block;
+ width: 16px;
+ height: 16px;
background-color: var(--input-border-color);
border-radius: 8px;
transition: transform var(--fast) var(--transition);
+ content: '';
+ }
+
+ &:hover {
+ border-color: var(--input-border-color-hover);
}
}
- &[aria-pressed='true'] {
- &:not(:disabled) {
- .switch {
- background-color: var(--v-switch-color);
- border-color: var(--v-switch-color);
+ &[aria-pressed='true'] .switch {
+ background-color: var(--v-switch-color);
+ border-color: var(--v-switch-color);
- &::after {
- background-color: var(--input-text-color-active);
- }
- }
- }
-
- .switch::after {
+ &::after {
+ background-color: var(--input-text-color-active);
transform: translateX(20px);
}
}
.label:not(:empty) {
- font-size: var(--input-font-size);
margin-left: 8px;
+ font-size: var(--input-font-size);
vertical-align: middle;
}
@@ -144,6 +137,15 @@ export default createComponent({
.switch {
background-color: var(--input-background-color-disabled);
+ border-color: var(--input-border-color);
+
+ &::after {
+ background-color: var(--input-border-color);
+ }
+
+ &:hover {
+ border-color: var(--input-border-color);
+ }
}
.label {
diff --git a/src/components/v-table/_table-header.vue b/src/components/v-table/_table-header.vue
index d63975f61f..c3f2c0407a 100644
--- a/src/components/v-table/_table-header.vue
+++ b/src/components/v-table/_table-header.vue
@@ -222,21 +222,21 @@ export default createComponent({