wave-ui 1.51.0 → 1.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/wave-ui.cjs.js +1 -1
  2. package/dist/wave-ui.css +1 -1
  3. package/dist/wave-ui.es.js +255 -156
  4. package/dist/wave-ui.umd.js +1 -1
  5. package/package.json +3 -2
  6. package/src/wave-ui/components/transitions/w-transition-expand.vue +1 -13
  7. package/src/wave-ui/components/w-accordion.vue +47 -24
  8. package/src/wave-ui/components/w-card.vue +12 -5
  9. package/src/wave-ui/components/w-checkbox.vue +11 -6
  10. package/src/wave-ui/components/w-checkboxes.vue +9 -19
  11. package/src/wave-ui/components/w-dialog.vue +18 -9
  12. package/src/wave-ui/components/w-divider.vue +10 -3
  13. package/src/wave-ui/components/w-drawer.vue +46 -21
  14. package/src/wave-ui/components/w-form-element.vue +19 -13
  15. package/src/wave-ui/components/w-form.vue +16 -11
  16. package/src/wave-ui/components/w-icon.vue +19 -17
  17. package/src/wave-ui/components/w-input.vue +14 -37
  18. package/src/wave-ui/components/w-menu.vue +8 -0
  19. package/src/wave-ui/components/w-notification.vue +3 -1
  20. package/src/wave-ui/components/w-overlay.vue +35 -8
  21. package/src/wave-ui/components/w-radio.vue +11 -6
  22. package/src/wave-ui/components/w-radios.vue +6 -15
  23. package/src/wave-ui/components/w-select.vue +13 -28
  24. package/src/wave-ui/components/w-slider.vue +21 -10
  25. package/src/wave-ui/components/w-switch.vue +44 -16
  26. package/src/wave-ui/components/w-tabs/index.vue +11 -1
  27. package/src/wave-ui/components/w-textarea.vue +15 -17
  28. package/src/wave-ui/components/w-timeline.vue +1 -1
  29. package/src/wave-ui/components/w-toolbar.vue +46 -6
  30. package/src/wave-ui/components/w-tooltip.vue +6 -1
  31. package/src/wave-ui/mixins/detachable.js +18 -17
  32. package/src/wave-ui/mixins/form-elements.js +9 -0
@@ -1,12 +1,12 @@
1
1
  <template lang="pug">
2
2
  component.w-icon(
3
3
  :is="tag || 'i'"
4
- :class="classes"
5
4
  v-on="$listeners"
5
+ :class="classes"
6
6
  role="icon"
7
7
  aria-hidden="true"
8
- :style="styles")
9
- template(v-if="ligature") {{ ligature.icon }}
8
+ :style="readIcon() /* Always reacting to slot change when called from template. */ && styles")
9
+ template(v-if="hasLigature") {{ icon }}
10
10
  </template>
11
11
 
12
12
  <script>
@@ -41,15 +41,13 @@ export default {
41
41
  emits: [],
42
42
 
43
43
  data: () => ({
44
- icon: ''
44
+ icon: '',
45
+ fontName: ''
45
46
  }),
46
47
 
47
48
  computed: {
48
- ligature () {
49
- if (!config.iconsLigature) return false
50
-
51
- const [fontName, icon] = this.icon.split(' ')
52
- return fontName === config.iconsLigature && { fontName, icon }
49
+ hasLigature () {
50
+ return config.iconsLigature === this.fontName
53
51
  },
54
52
  forcedSize () {
55
53
  return this.size && (!isNaN(this.size) ? `${this.size}px` : this.size)
@@ -66,7 +64,8 @@ export default {
66
64
  },
67
65
  classes () {
68
66
  return {
69
- [this.icon]: true,
67
+ [this.fontName]: true,
68
+ [!this.hasLigature && this.icon]: !this.hasLigature && this.icon,
70
69
  [this.color]: this.color,
71
70
  [`${this.bgColor}--bg`]: this.bgColor,
72
71
  [`size--${this.presetSize}`]: this.presetSize && !this.forcedSize,
@@ -80,8 +79,7 @@ export default {
80
79
  'w-icon--rotate-90': this.rotate90a,
81
80
  'w-icon--rotate-135': this.rotate135a,
82
81
  'w-icon--flip-x': this.flipX,
83
- 'w-icon--flip-y': this.flipY,
84
- [this.ligature && this.ligature.fontName]: this.ligature
82
+ 'w-icon--flip-y': this.flipY
85
83
  }
86
84
  },
87
85
  styles () {
@@ -89,12 +87,15 @@ export default {
89
87
  }
90
88
  },
91
89
 
92
- created () {
93
- this.icon = this.$slots.default[0].text.trim() || ''
94
- },
90
+ methods: {
91
+ readIcon () {
92
+ const { default: slot } = this.$slots
93
+ const [fontName = '', icon = ''] = slot[0].text.trim().split(' ') || []
94
+ this.fontName = fontName
95
+ this.icon = icon
95
96
 
96
- beforeUpdate () {
97
- this.icon = this.$slots.default[0].text.trim()
97
+ return true // Always return true for styles to be applied (c.f. template styles).
98
+ }
98
99
  }
99
100
  }
100
101
  </script>
@@ -108,6 +109,7 @@ export default {
108
109
  justify-content: center;
109
110
  vertical-align: middle;
110
111
  user-select: none;
112
+ speak: never;
111
113
  line-height: 1;
112
114
  font-size: 1.2em;
113
115
  width: 1em;
@@ -13,15 +13,10 @@ component(
13
13
  //- Left label.
14
14
  template(v-if="labelPosition === 'left'")
15
15
  label.w-input__label.w-input__label--left.w-form-el-shakable(
16
- v-if="$slots.default"
16
+ v-if="$slots.default || label"
17
17
  :for="`w-input--${_uid}`"
18
- :class="validationClasses")
19
- slot
20
- label.w-input__label.w-input__label--left.w-form-el-shakable(
21
- v-else-if="label"
22
- :for="`w-input--${_uid}`"
23
- :class="validationClasses"
24
- v-html="label")
18
+ :class="labelClasses")
19
+ slot {{ label }}
25
20
 
26
21
  //- Input wrapper.
27
22
  .w-input__input-wrap(:class="inputWrapClasses")
@@ -81,15 +76,10 @@ component(
81
76
 
82
77
  template(v-if="labelPosition === 'inside' && showLabelInside")
83
78
  label.w-input__label.w-input__label--inside.w-form-el-shakable(
84
- v-if="$slots.default"
85
- :for="`w-input--${_uid}`"
86
- :class="validationClasses")
87
- slot
88
- label.w-input__label.w-input__label--inside.w-form-el-shakable(
89
- v-else-if="label"
79
+ v-if="$slots.default || label"
90
80
  :for="`w-input--${_uid}`"
91
- v-html="label"
92
- :class="validationClasses")
81
+ :class="labelClasses")
82
+ slot {{ label }}
93
83
  w-icon.w-input__icon.w-input__icon--inner-right(
94
84
  v-if="innerIconRight"
95
85
  tag="label"
@@ -117,15 +107,10 @@ component(
117
107
  //- Right label.
118
108
  template(v-if="labelPosition === 'right'")
119
109
  label.w-input__label.w-input__label--right.w-form-el-shakable(
120
- v-if="$slots.default"
121
- :for="`w-input--${_uid}`"
122
- :class="validationClasses")
123
- slot
124
- label.w-input__label.w-input__label--right.w-form-el-shakable(
125
- v-else-if="label"
110
+ v-if="$slots.default || label"
126
111
  :for="`w-input--${_uid}`"
127
- :class="validationClasses"
128
- v-html="label")
112
+ :class="labelClasses")
113
+ slot {{ label }}
129
114
  </template>
130
115
 
131
116
  <script>
@@ -146,12 +131,12 @@ export default {
146
131
  labelPosition: { type: String, default: 'inside' },
147
132
  innerIconLeft: { type: String },
148
133
  innerIconRight: { type: String },
149
- // When label is inside, allows to move the label above on focus or when filled.
150
- staticLabel: { type: Boolean },
134
+ staticLabel: { type: Boolean }, // When label is inside, fix the label above.
151
135
  placeholder: { type: String },
152
136
  color: { type: String, default: 'primary' },
153
- progressColor: { type: String },
154
137
  bgColor: { type: String },
138
+ labelColor: { type: String, default: 'primary' },
139
+ progressColor: { type: String },
155
140
  minlength: { type: [Number, String] },
156
141
  maxlength: { type: [Number, String] },
157
142
  step: { type: [Number, String] },
@@ -237,7 +222,7 @@ export default {
237
222
  },
238
223
 
239
224
  overallFilesProgress () {
240
- const progress = this.inputFiles.reduce((total, file) => total + file.progress, 0)
225
+ const progress = +this.inputFiles.reduce((total, file) => total + file.progress, 0)
241
226
  const total = progress / this.inputFiles.length
242
227
  this.$emit('update:overallProgress', this.inputFiles.length ? total : undefined)
243
228
 
@@ -269,15 +254,9 @@ export default {
269
254
  }
270
255
  },
271
256
 
272
- validationClasses () {
273
- return this.isFocused && {
274
- [this.valid === false ? 'error' : this.color]: this.color || this.valid === false
275
- }
276
- },
277
-
278
257
  inputWrapClasses () {
279
258
  return {
280
- [this.valid === false ? 'error' : this.color]: this.color || this.valid === false,
259
+ [this.valid === false ? this.validationColor : this.color]: this.color || this.valid === false,
281
260
  [`${this.bgColor}--bg`]: this.bgColor,
282
261
  'w-input__input-wrap--file': this.type === 'file',
283
262
  'w-input__input-wrap--round': this.round,
@@ -635,8 +614,6 @@ $inactive-color: #777;
635
614
  .w-input--filled.w-input--floating-label.w-input--inner-icon-left & {left: 0;}
636
615
  // Chrome & Safari - Must remain in a separated rule as Firefox discard the whole rule seeing -webkit-.
637
616
  .w-input--floating-label.w-input--inner-icon-left .w-input__input:-webkit-autofill & {left: 0;}
638
-
639
- .w-input--focused & {color: currentColor;}
640
617
  }
641
618
  }
642
619
  </style>
@@ -88,6 +88,14 @@ export default {
88
88
  // alignRight, noPosition, zIndex, activator.
89
89
  },
90
90
 
91
+ provide () {
92
+ return {
93
+ // If a detachable is used inside a w-menu without an appendTo, default to the menu element
94
+ // instead of the w-app.
95
+ detachableDefaultRoot: () => this.$refs.detachable?.$el || this.$refs.detachable || null
96
+ }
97
+ },
98
+
91
99
  emits: ['input', 'update:modelValue', 'open', 'close'],
92
100
 
93
101
  data: () => ({
@@ -1,7 +1,9 @@
1
1
  <template lang="pug">
2
2
  transition(:name="transitionName" appear)
3
3
  .w-notification(v-if="show" :class="classes" :style="styles")
4
- w-alert.white--bg(v-bind="alertProps" @input="$emit('update:modelValue', false);$emit('input', false)")
4
+ w-alert.white--bg(
5
+ v-bind="alertProps"
6
+ @input="$emit('update:modelValue', false);$emit('input', false)")
5
7
  slot
6
8
  </template>
7
9
 
@@ -1,8 +1,9 @@
1
1
  <template lang="pug">
2
- transition(name="fade" appear @after-leave="$emit('closed')")
2
+ transition(name="fade" appear @after-leave="onClose")
3
3
  .w-overlay(
4
- v-if="value"
5
- :style="(value && styles) || null"
4
+ v-if="showOverlay"
5
+ ref="overlay"
6
+ :style="styles || null"
6
7
  @keydown.escape.stop="onClick"
7
8
  @click="onClick"
8
9
  v-focus
@@ -24,10 +25,19 @@ export default {
24
25
  persistentNoAnimation: { type: Boolean }
25
26
  },
26
27
 
27
- emits: ['input', 'update:modelValue', 'click', 'close', 'closed'],
28
+ provide () {
29
+ return {
30
+ // If a detachable is used inside a w-overlay without an appendTo, default to the overlay element
31
+ // instead of the w-app.
32
+ detachableDefaultRoot: () => this.$refs.overlay || null
33
+ }
34
+ },
35
+
36
+ emits: ['input', 'update:modelValue', 'click', 'before-close', 'close'],
28
37
 
29
38
  data: () => ({
30
- persistentAnimate: false
39
+ persistentAnimate: false,
40
+ showOverlay: false
31
41
  }),
32
42
 
33
43
  computed: {
@@ -58,12 +68,29 @@ export default {
58
68
  setTimeout(() => (this.persistentAnimate = false), 150) // Must match CSS animation duration.
59
69
  }
60
70
  else if (!this.persistent) {
61
- this.$emit('update:modelValue', false)
62
- this.$emit('input', false)
63
- this.$emit('close')
71
+ this.showOverlay = false
72
+ this.$emit('before-close')
64
73
  }
65
74
 
66
75
  this.$emit('click', e)
76
+ },
77
+
78
+ // Wait until the end of the closing transition (v-show) to completely unmount (v-if).
79
+ // The onClose method is called twice from the transition: once for the v-show, and once for the v-if.
80
+ onClose () {
81
+ this.$emit('update:modelValue', false)
82
+ this.$emit('input', false)
83
+ this.$emit('close') // Only emit once.
84
+ }
85
+ },
86
+
87
+ created () {
88
+ this.showOverlay = this.value
89
+ },
90
+
91
+ watch: {
92
+ value (bool) {
93
+ if (this.showOverlay !== bool) this.showOverlay = bool
67
94
  }
68
95
  }
69
96
  }
@@ -20,16 +20,20 @@ component(
20
20
  :aria-checked="inputValue || 'false'"
21
21
  role="radio")
22
22
  template(v-if="hasLabel && labelOnLeft")
23
- label.w-radio__label.w-form-el-shakable.pr2(v-if="$slots.default" :for="`w-radio--${_uid}`")
24
- slot
25
- label.w-radio__label.w-form-el-shakable.pr2(v-else-if="label" :for="`w-radio--${_uid}`" v-html="label")
23
+ label.w-radio__label.w-form-el-shakable.pr2(
24
+ v-if="$slots.default || label"
25
+ :for="`w-radio--${_uid}`"
26
+ :class="labelClasses")
27
+ slot {{ label }}
26
28
  .w-radio__input(
27
29
  @click="$refs.input.focus();$refs.input.click()"
28
30
  :class="this.color")
29
31
  template(v-if="hasLabel && !labelOnLeft")
30
- label.w-radio__label.w-form-el-shakable.pl2(v-if="$slots.default" :for="`w-radio--${_uid}`")
31
- slot
32
- label.w-radio__label.w-form-el-shakable.pl2(v-else-if="label" :for="`w-radio--${_uid}`" v-html="label")
32
+ label.w-radio__label.w-form-el-shakable.pl2(
33
+ v-if="$slots.default || label"
34
+ :for="`w-radio--${_uid}`"
35
+ :class="labelClasses")
36
+ slot {{ label }}
33
37
  </template>
34
38
 
35
39
  <script>
@@ -48,6 +52,7 @@ export default {
48
52
  label: { type: String },
49
53
  labelOnLeft: { type: Boolean },
50
54
  color: { type: String, default: 'primary' },
55
+ labelColor: { type: String, default: 'primary' },
51
56
  noRipple: { type: Boolean }
52
57
  // Props from mixin: name, disabled, readonly, required, tabindex, validators.
53
58
  // Computed from mixin: inputName, isDisabled & isReadonly.
@@ -15,26 +15,16 @@ component(
15
15
  @focus="$emit('focus', $event)"
16
16
  :name="inputName"
17
17
  :value="item.value === value"
18
- :label="item.label"
19
- :label-on-left="labelOnLeft"
20
- :color="item.color"
18
+ v-bind="{ label: item.label, color: item.color, labelOnLeft, labelColor }"
21
19
  :disabled="isDisabled || null"
22
20
  :readonly="isReadonly || null"
23
21
  :class="{ mt1: !inline && i }")
24
22
  slot(
25
- v-if="$scopedSlots[`item.${i + 1}`]"
26
- :name="`item.${i + 1}`"
23
+ v-if="$slots[`item.${i + 1}`] || $slots.item"
24
+ :name="$slots[`item.${i + 1}`] ? `item.${i + 1}` : 'item'"
27
25
  :item="getOriginalItem(item)"
28
26
  :index="i + 1"
29
- :checked="item.value === value"
30
- v-html="item.label")
31
- slot(
32
- v-else-if="$scopedSlots.item"
33
- name="item"
34
- :item="getOriginalItem(item)"
35
- :index="i + 1"
36
- :checked="item.value === value"
37
- v-html="item.label")
27
+ :checked="item.value === value")
38
28
  </template>
39
29
 
40
30
  <script>
@@ -52,7 +42,8 @@ export default {
52
42
  itemValueKey: { type: String, default: 'value' },
53
43
  itemColorKey: { type: String, default: 'color' }, // Support a different color per item.
54
44
  inline: { type: Boolean },
55
- color: { type: String, default: 'primary' }
45
+ color: { type: String, default: 'primary' },
46
+ labelColor: { type: String, default: 'primary' }
56
47
  // Props from mixin: name, disabled, readonly, required, validators.
57
48
  // Computed from mixin: inputName, isDisabled & isReadonly.
58
49
  },
@@ -9,24 +9,19 @@ component(
9
9
  :class="classes")
10
10
  template(v-if="labelPosition === 'left'")
11
11
  label.w-select__label.w-select__label--left.w-form-el-shakable(
12
- v-if="$slots.default"
13
- :for="`w-select--${_uid}`")
14
- slot
15
- label.w-select__label.w-select__label--left.w-form-el-shakable(
16
- v-else-if="label"
12
+ v-if="$slots.default || label"
17
13
  :for="`w-select--${_uid}`"
18
- v-html="label")
14
+ :class="labelClasses")
15
+ slot {{ label }}
19
16
 
20
17
  w-menu(
21
18
  v-model="showMenu"
22
19
  :menu-class="`w-select__menu ${menuClass || ''}`"
23
20
  transition="slide-fade-down"
24
- :append-to="(menuProps || {}).appendTo !== undefined ? (menuProps || {}).appendTo : '.w-app'"
21
+ :append-to="(menuProps || {}).appendTo !== undefined ? (menuProps || {}).appendTo : undefined"
25
22
  align-left
26
23
  custom
27
24
  min-width="activator"
28
- @mousedown="isFocused = true, selectingItem = true"
29
- @mouseup="isFocused = true, selectingItem = false"
30
25
  v-bind="menuProps || {}")
31
26
  template(#activator="{ on }")
32
27
  //- Input wrapper.
@@ -69,15 +64,10 @@ component(
69
64
  :name="inputName + (multiple ? '[]' : '')")
70
65
  template(v-if="labelPosition === 'inside' && showLabelInside")
71
66
  label.w-select__label.w-select__label--inside.w-form-el-shakable(
72
- v-if="$slots.default"
73
- :for="`w-select--${_uid}`"
74
- :class="isFocused && { [valid === false ? 'error' : color]: color || valid === false }")
75
- slot
76
- label.w-select__label.w-select__label--inside.w-form-el-shakable(
77
- v-else-if="label"
67
+ v-if="$slots.default || label"
78
68
  :for="`w-select--${_uid}`"
79
- v-html="label"
80
- :class="isFocused && { [valid === false ? 'error' : color]: color || valid === false }")
69
+ :class="labelClasses")
70
+ slot {{ label }}
81
71
  w-icon.w-select__icon.w-select__icon--inner-right(
82
72
  v-if="innerIconRight"
83
73
  tag="label"
@@ -113,13 +103,10 @@ component(
113
103
 
114
104
  template(v-if="labelPosition === 'right'")
115
105
  label.w-select__label.w-select__label--right.w-form-el-shakable(
116
- v-if="$slots.default"
117
- :for="`w-select--${_uid}`")
118
- slot
119
- label.w-select__label.w-select__label--right.w-form-el-shakable(
120
- v-else-if="label"
106
+ v-if="$slots.default || label"
121
107
  :for="`w-select--${_uid}`"
122
- v-html="label")
108
+ :class="labelClasses")
109
+ slot {{ label }}
123
110
  </template>
124
111
 
125
112
  <script>
@@ -150,8 +137,9 @@ export default {
150
137
  itemClass: { type: String },
151
138
  menuClass: { type: String },
152
139
  color: { type: String, default: 'primary' }, // Applies to all the items.
153
- selectionColor: { type: String, default: 'primary' }, // Applies to the selected items only.
154
140
  bgColor: { type: String }, // Applies to all the items.
141
+ labelColor: { type: String, default: 'primary' },
142
+ selectionColor: { type: String, default: 'primary' }, // Applies to the selected items only.
155
143
  outline: { type: Boolean },
156
144
  round: { type: Boolean },
157
145
  shadow: { type: Boolean },
@@ -175,7 +163,6 @@ export default {
175
163
  showMenu: false,
176
164
  menuMinWidth: 0,
177
165
  isFocused: false,
178
- selectingItem: false,
179
166
  selectionWrapRef: undefined
180
167
  }),
181
168
 
@@ -213,7 +200,7 @@ export default {
213
200
  'w-select--disabled': this.isDisabled,
214
201
  'w-select--readonly': this.isReadonly,
215
202
  [`w-select--${this.hasValue ? 'filled' : 'empty'}`]: true,
216
- 'w-select--focused': (this.isFocused || this.selectingItem) && !this.isReadonly,
203
+ 'w-select--focused': (this.isFocused || this.showMenu) && !this.isReadonly,
217
204
  'w-select--dark': this.dark,
218
205
  'w-select--floating-label': this.hasLabel && this.labelPosition === 'inside' && !this.staticLabel,
219
206
  'w-select--no-padding': !this.outline && !this.bgColor && !this.shadow && !this.round,
@@ -579,8 +566,6 @@ export default {
579
566
  .w-select--filled.w-select--floating-label.w-select--inner-icon-left & {left: 0;}
580
567
  // Chrome & Safari - Must remain in a separated rule as Firefox discard the whole rule seeing -webkit-.
581
568
  .w-select--floating-label.w-select--inner-icon-left .w-select__select:-webkit-autofill & {left: 0;}
582
-
583
- .w-select--focused &, .w-select--open & {color: currentColor;}
584
569
  }
585
570
 
586
571
  // Menu.
@@ -5,15 +5,17 @@ component(
5
5
  v-bind="formRegister && { validators, inputValue: rangeValueScaled, disabled: isDisabled, readonly: isReadonly }"
6
6
  :valid.sync="valid"
7
7
  @reset="rangeValuePercent = 0;updateRangeValueScaled()"
8
- wrap
8
+ :wrap="formRegister || null"
9
9
  :class="wrapperClasses")
10
10
  label.w-slider__label.w-slider__label--left.w-form-el-shakable(
11
11
  v-if="$slots['label-left']"
12
- :for="`button--${_uid}`")
12
+ :for="`button--${_uid}`"
13
+ :class="labelClasses")
13
14
  slot(name="label-left")
14
15
  label.w-slider__label.w-slider__label--left.w-form-el-shakable(
15
16
  v-else-if="labelLeft"
16
17
  :for="`button--${_uid}`"
18
+ :class="labelClasses"
17
19
  v-html="labelLeft")
18
20
  .w-slider__track-wrap
19
21
  .w-slider__track(
@@ -39,6 +41,7 @@ component(
39
41
  :disabled="isDisabled || null"
40
42
  :readonly="isReadonly || null"
41
43
  :aria-readonly="isReadonly ? 'true' : 'false'"
44
+ :tabindex="isDisabled || isReadonly ? -1 : null"
42
45
  @keydown.left="onKeyDown($event, -1)"
43
46
  @keydown.right="onKeyDown($event, 1)"
44
47
  @focus="$emit('focus', $event)"
@@ -64,11 +67,13 @@ component(
64
67
  style="left: 100%") {{ this.maxVal }}
65
68
  label.w-slider__label.w-slider__label--right.w-form-el-shakable(
66
69
  v-if="$slots['label-right']"
67
- :for="`button--${_uid}`")
70
+ :for="`button--${_uid}`"
71
+ :class="labelClasses")
68
72
  slot(name="label-right")
69
73
  label.w-slider__label.w-slider__label--right.w-form-el-shakable(
70
74
  v-else-if="labelRight"
71
75
  :for="`button--${_uid}`"
76
+ :class="labelClasses"
72
77
  v-html="labelRight")
73
78
  </template>
74
79
 
@@ -83,6 +88,7 @@ export default {
83
88
  value: { type: Number, default: 0 },
84
89
  color: { type: String, default: 'primary' },
85
90
  bgColor: { type: String },
91
+ labelColor: { type: String, default: 'primary' },
86
92
  stepLabels: { type: [Boolean, Array] },
87
93
  thumbLabel: { type: [Boolean, String] }, // One of true, false, 'droplet'.
88
94
  thumbLabelClass: { type: String },
@@ -378,16 +384,17 @@ export default {
378
384
  &:before, &:after {
379
385
  content: '';
380
386
  position: absolute;
387
+ border-radius: inherit;
388
+ @include default-transition;
381
389
  }
390
+ // Colored border on thumb when hover and active - but with a transparency.
382
391
  &:before {
383
392
  left: 0;
384
393
  right: 0;
385
394
  top: 0;
386
395
  bottom: 0;
387
396
  opacity: 0.5;
388
- border-radius: inherit;
389
397
  border: 1px solid currentColor;
390
- @include default-transition;
391
398
  }
392
399
  &:hover:before, &:focus:before {opacity: 0.7;}
393
400
  &:active:before, .w-slider--dragging &:before {
@@ -398,13 +405,17 @@ export default {
398
405
  .w-slider--disabled &:before,
399
406
  .w-slider--readonly &:before {box-shadow: none;opacity: 0.4;}
400
407
 
401
- // For fat fingers.
408
+ // The outline when focused, but also a bigger reactive zone for fat fingers when not.
402
409
  &:after {
403
- left: -6px;
404
- right: -6px;
405
- top: -6px;
406
- bottom: -6px;
410
+ left: -2 * $base-increment;
411
+ right: -2 * $base-increment;
412
+ top: -2 * $base-increment;
413
+ bottom: -2 * $base-increment;
414
+ opacity: 0;
415
+ background-color: currentColor;
407
416
  }
417
+ &:focus:after {opacity: 0.15;}
418
+ .w-slider--dragging &:after, &:active:after {opacity: 0.1;transform: scale(1.2);}
408
419
  }
409
420
 
410
421
  // Thumb label.