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
@@ -22,17 +22,25 @@ component(
22
22
  :aria-checked="isOn || 'false'"
23
23
  role="switch")
24
24
  template(v-if="hasLabel && labelOnLeft")
25
- label.w-switch__label.w-form-el-shakable(v-if="$slots.default" :for="`w-switch--${_uid}`")
26
- slot
27
- label.w-switch__label.w-form-el-shakable(v-else-if="label" :for="`w-switch--${_uid}`" v-html="label")
25
+ label.w-switch__label.w-switch__label--left.w-form-el-shakable(
26
+ v-if="$slots.default || label"
27
+ :for="`w-switch--${_uid}`"
28
+ :class="labelClasses")
29
+ slot {{ label }}
28
30
  .w-switch__input(
29
31
  @click="$refs.input.focus();$refs.input.click()"
30
32
  v-on="$listeners"
31
33
  :class="inputClasses")
34
+ .w-switch__track(v-if="$slots.track")
35
+ slot(name="track")
36
+ .w-switch__thumb(v-if="$slots.thumb")
37
+ slot(name="thumb")
32
38
  template(v-if="hasLabel && !labelOnLeft")
33
- label.w-switch__label.w-form-el-shakable(v-if="$slots.default" :for="`w-switch--${_uid}`")
34
- slot
35
- label.w-switch__label.w-form-el-shakable(v-else-if="label" :for="`w-switch--${_uid}`" v-html="label")
39
+ label.w-switch__label.w-switch__label--right.w-form-el-shakable(
40
+ v-if="$slots.default || label"
41
+ :for="`w-switch--${_uid}`"
42
+ :class="labelClasses")
43
+ slot {{ label }}
36
44
  </template>
37
45
 
38
46
  <script>
@@ -47,6 +55,7 @@ export default {
47
55
  label: { type: String, default: '' },
48
56
  labelOnLeft: { type: Boolean },
49
57
  color: { type: String, default: 'primary' },
58
+ labelColor: { type: String, default: 'primary' },
50
59
  thin: { type: Boolean },
51
60
  noRipple: { type: Boolean }
52
61
  // Props from mixin: name, disabled, readonly, required, tabindex, validators.
@@ -77,6 +86,8 @@ export default {
77
86
  'w-switch--disabled': this.isDisabled,
78
87
  'w-switch--readonly': this.isReadonly,
79
88
  'w-switch--ripple': this.ripple.start,
89
+ 'w-switch--custom-thumb': this.$slots.thumb,
90
+ 'w-switch--custom-track': this.$slots.track,
80
91
  'w-switch--rippled': this.ripple.end
81
92
  }
82
93
  },
@@ -186,8 +197,18 @@ $disabled-color: #ddd;
186
197
  }
187
198
  }
188
199
 
189
- // Thumb.
190
- &__input:after {
200
+ // Track slot, if any.
201
+ &__track {
202
+ position: absolute;
203
+ left: 100%;
204
+ padding: 0 4px;
205
+ transform: translateX(-100%);
206
+ @include default-transition;
207
+ }
208
+ .w-switch--on &__track {left: 0;transform: translateX(0);}
209
+
210
+ // Thumb: show either the thumb slot if any, or :after otherwise.
211
+ &__thumb, &__input:after {
191
212
  content: '';
192
213
  position: absolute;
193
214
  left: 0;
@@ -196,22 +217,28 @@ $disabled-color: #ddd;
196
217
  height: $small-form-el-size;
197
218
  background-color: #fff;
198
219
  border-radius: 100%;
220
+ text-align: center;
199
221
  @include default-transition;
200
222
 
201
223
  .w-switch[class^="bdrs"] &, .w-switch[class*=" bdrs"] & {border-radius: inherit;}
202
224
 
203
- :checked ~ & {transform: translateX(100%);}
225
+ .w-switch--on & {left: 100%;transform: translateX(-100%);}
204
226
 
205
227
  .w-switch--thin & {
206
228
  top: - round(0.15 * $small-form-el-size);
207
229
  transform: scale(1.1);
208
230
  box-shadow: $box-shadow;
209
231
  }
210
- .w-switch--thin :checked ~ & {
211
- transform: translateX(100%) scale(1.1);
232
+ .w-switch--thin.w-switch--on & {
233
+ transform: translateX(-100%) scale(1.1);
212
234
  background-color: currentColor;
213
235
  }
214
236
  }
237
+ &--custom-thumb &__input:after {display: none;}
238
+ &__thumb > * {
239
+ width: inherit;
240
+ height: inherit;
241
+ }
215
242
 
216
243
  // The focus outline & ripple on switch activation.
217
244
  &__input:before {
@@ -223,11 +250,12 @@ $disabled-color: #ddd;
223
250
  height: $small-form-el-size;
224
251
  background-color: currentColor;
225
252
  border-radius: 100%;
226
- transform: translateX(100%) scale(0);
227
253
  opacity: 0;
228
254
  pointer-events: none;
229
255
  transition: 0.25s ease-in-out;
230
256
 
257
+ :checked ~ & {transform: translateX(-100%) scale(0);left: 100%;}
258
+
231
259
  .w-switch[class^="bdrs"] &, .w-switch[class*=" bdrs"] & {border-radius: inherit;}
232
260
  .w-switch--thin & {top: - round(0.15 * $small-form-el-size);}
233
261
  }
@@ -242,14 +270,14 @@ $disabled-color: #ddd;
242
270
  opacity: 0.2;
243
271
  }
244
272
  :focus:checked ~ &__input:before {
245
- transform: translateX(100%) scale(1.8);
273
+ transform: translateX(-100%) scale(1.8);
246
274
  }
247
275
 
248
276
  // After ripple reset to default state, then remove the class via js and the
249
277
  // `:focus ~ &__input:before` will re-transition to normal focused outline.
250
278
  &--rippled &__input:before {
251
279
  transition: none;
252
- transform: translateX(100%) scale(0);
280
+ transform: translateX(-100%) scale(0);
253
281
  opacity: 0;
254
282
  }
255
283
 
@@ -264,7 +292,7 @@ $disabled-color: #ddd;
264
292
  }
265
293
 
266
294
  @keyframes w-switch-ripple {
267
- 0% {opacity: 0.8;transform: translateX(100%) scale(1);background-color: currentColor;} // Start with visible ripple.
268
- 100% {opacity: 0;transform: translateX(100%) scale(2.8);} // Propagate ripple to max radius and fade out.
295
+ 0% {opacity: 0.8;transform: translateX(-100%) scale(1);background-color: currentColor;} // Start with visible ripple.
296
+ 100% {opacity: 0;transform: translateX(-100%) scale(2.8);} // Propagate ripple to max radius and fade out.
269
297
  }
270
298
  </style>
@@ -65,6 +65,7 @@ export default {
65
65
  titleClass: { type: String },
66
66
  activeClass: { type: String, default: 'primary' },
67
67
  noSlider: { type: Boolean },
68
+ pillSlider: { type: Boolean },
68
69
  sliderColor: { type: String, default: 'primary' },
69
70
  contentClass: { type: String },
70
71
  transition: { type: [String, Boolean], default: '' },
@@ -122,6 +123,7 @@ export default {
122
123
  return {
123
124
  'w-tabs--card': this.card,
124
125
  'w-tabs--no-slider': this.noSlider,
126
+ 'w-tabs--pill-slider': this.pillSlider,
125
127
  'w-tabs--fill-bar': this.fillBar,
126
128
  'w-tabs--init': this.init
127
129
  }
@@ -252,11 +254,11 @@ export default {
252
254
  &__bar {
253
255
  position: relative;
254
256
  display: flex;
255
- // align-items: center;
256
257
  overflow-x: auto;
257
258
 
258
259
  &--center {justify-content: center;}
259
260
  &--right {justify-content: flex-end;}
261
+ .w-tabs--pill-slider & {padding-left: $base-increment;}
260
262
 
261
263
  .w-tabs--card &:after {
262
264
  content: '';
@@ -310,6 +312,7 @@ export default {
310
312
  &:active:before {opacity: 0.08;}
311
313
  &--disabled:before {display: none;}
312
314
  }
315
+ &--pill-slider &__bar-item:before {display: none;}
313
316
 
314
317
  // Bar Extra.
315
318
  // ------------------------------------------------------
@@ -330,6 +333,13 @@ export default {
330
333
  background-color: currentColor;
331
334
  transition: $transition-duration ease-in-out;
332
335
  }
336
+ &--pill-slider &__slider {
337
+ opacity: 0.1;
338
+ bottom: 15%;
339
+ height: 70%;
340
+ border-radius: 99em;
341
+ }
342
+
333
343
  &--init &__slider {transition: none;}
334
344
 
335
345
  // Content.
@@ -9,9 +9,11 @@ component(
9
9
  :class="classes")
10
10
  //- Left label.
11
11
  template(v-if="labelPosition === 'left'")
12
- label.w-textarea__label.w-textarea__label--left.w-form-el-shakable(v-if="$slots.default" :for="`w-textarea--${_uid}`")
13
- slot
14
- label.w-textarea__label.w-textarea__label--left.w-form-el-shakable(v-else-if="label" :for="`w-textarea--${_uid}`" v-html="label")
12
+ label.w-textarea__label.w-textarea__label--left.w-form-el-shakable(
13
+ v-if="$slots.default || label"
14
+ :for="`w-textarea--${_uid}`"
15
+ :class="labelClasses")
16
+ slot {{ label }}
15
17
 
16
18
  //- Input wrapper.
17
19
  .w-textarea__textarea-wrap(:class="inputWrapClasses")
@@ -39,15 +41,10 @@ component(
39
41
  :tabindex="tabindex || null")
40
42
  template(v-if="labelPosition === 'inside' && showLabelInside")
41
43
  label.w-textarea__label.w-textarea__label--inside.w-form-el-shakable(
42
- v-if="$slots.default"
43
- :for="`w-textarea--${_uid}`"
44
- :class="isFocused && { [valid === false ? 'error' : this.color]: this.color || valid === false }")
45
- slot
46
- label.w-textarea__label.w-textarea__label--inside.w-form-el-shakable(
47
- v-else-if="label"
44
+ v-if="$slots.default || label"
48
45
  :for="`w-textarea--${_uid}`"
49
- v-html="label"
50
- :class="isFocused && { [valid === false ? 'error' : color]: color || valid === false }")
46
+ :class="labelClasses")
47
+ slot {{ label }}
51
48
  w-icon.w-textarea__icon.w-textarea__icon--inner-right(
52
49
  v-if="innerIconRight"
53
50
  tag="label"
@@ -56,9 +53,11 @@ component(
56
53
 
57
54
  //- Right label.
58
55
  template(v-if="labelPosition === 'right'")
59
- label.w-textarea__label.w-textarea__label--right.w-form-el-shakable(v-if="$slots.default" :for="`w-textarea--${_uid}`")
60
- slot
61
- label.w-textarea__label.w-textarea__label--right.w-form-el-shakable(v-else-if="label" :for="`w-textarea--${_uid}`" v-html="label")
56
+ label.w-textarea__label.w-textarea__label--right.w-form-el-shakable(
57
+ v-if="$slots.default || label"
58
+ :for="`w-textarea--${_uid}`"
59
+ :class="labelClasses")
60
+ slot {{ label }}
62
61
  </template>
63
62
 
64
63
  <script>
@@ -83,6 +82,7 @@ export default {
83
82
  placeholder: { type: String },
84
83
  color: { type: String, default: 'primary' },
85
84
  bgColor: { type: String },
85
+ labelColor: { type: String, default: 'primary' },
86
86
  dark: { type: Boolean },
87
87
  outline: { type: Boolean },
88
88
  shadow: { type: Boolean },
@@ -142,7 +142,7 @@ export default {
142
142
  },
143
143
  inputWrapClasses () {
144
144
  return {
145
- [this.valid === false ? 'error' : this.color]: this.color || this.valid === false,
145
+ [this.valid === false ? this.validationColor : this.color]: this.color || this.valid === false,
146
146
  [`${this.bgColor}--bg`]: this.bgColor,
147
147
  'w-textarea__textarea-wrap--tile': this.tile,
148
148
  // Box adds a padding on input. If there is a bgColor or shadow, a padding is needed.
@@ -387,8 +387,6 @@ $inactive-color: #777;
387
387
  .w-textarea--filled.w-textarea--floating-label.w-textarea--inner-icon-left & {left: 0;}
388
388
  // Chrome & Safari - Must remain in a separated rule as Firefox discard the whole rule seeing -webkit-.
389
389
  .w-textarea--floating-label.w-textarea--inner-icon-left .w-textarea__textarea:-webkit-autofill & {left: 0;}
390
-
391
- .w-textarea--focused & {color: currentColor;}
392
390
  }
393
391
  }
394
392
  </style>
@@ -1,7 +1,7 @@
1
1
  <template lang="pug">
2
2
  ul.w-timeline
3
3
  li.w-timeline-item(v-for="(item, i) in items" :key="i")
4
- .w-timeline-item__bullet(
4
+ component.w-timeline-item__bullet(
5
5
  :is="item[itemIconKey] || icon ? 'w-icon' : 'div'"
6
6
  :class="{ [item[itemColorKey] || color]: item[itemColorKey] || color }")
7
7
  | {{ item[itemIconKey] || icon }}
@@ -13,6 +13,10 @@ export default {
13
13
  absolute: { type: Boolean },
14
14
  fixed: { type: Boolean },
15
15
  bottom: { type: Boolean },
16
+ vertical: { type: Boolean },
17
+ left: { type: Boolean },
18
+ right: { type: Boolean },
19
+ width: { type: [Number, String], default: null },
16
20
  height: { type: [Number, String], default: null },
17
21
  noBorder: { type: Boolean },
18
22
  shadow: { type: Boolean }
@@ -21,25 +25,35 @@ export default {
21
25
  emits: [],
22
26
 
23
27
  computed: {
24
- // Return the width or height value if defined, or false otherwise.
28
+ // Return the height value if defined, or false otherwise.
25
29
  toolbarHeight () {
26
30
  const h = this.height
27
31
  // If a number is passed without units, append `px`.
28
32
  return h && parseInt(h) == h ? h + 'px' : h
29
33
  },
34
+ // Return the width value if defined, or false otherwise.
35
+ toolbarWidth () {
36
+ const w = this.width
37
+ // If a number is passed without units, append `px`.
38
+ return w && parseInt(w) == w ? w + 'px' : w
39
+ },
30
40
  classes () {
31
41
  return {
32
42
  [this.color]: !!this.color,
33
43
  [`${this.bgColor}--bg`]: !!this.bgColor,
34
44
  'w-toolbar--absolute': !!this.absolute,
35
45
  'w-toolbar--fixed': !!this.fixed,
36
- [`w-toolbar--${this.bottom ? 'bottom' : 'top'}`]: true,
46
+ [`w-toolbar--${this.bottom ? 'bottom' : 'top'}`]: !this.vertical,
47
+ [`w-toolbar--vertical w-toolbar--${this.right ? 'right' : 'left'}`]: this.vertical,
37
48
  'w-toolbar--no-border': this.noBorder,
38
49
  'w-toolbar--shadow': !!this.shadow
39
50
  }
40
51
  },
41
52
  styles () {
42
- return this.height ? `height: ${this.toolbarHeight}` : false
53
+ return {
54
+ height: this.height && !this.vertical ? this.toolbarHeight : null,
55
+ width: this.width && this.vertical ? this.toolbarWidth : null
56
+ }
43
57
  }
44
58
  }
45
59
  }
@@ -58,16 +72,34 @@ export default {
58
72
  &--absolute, &--fixed {top: 0;left: 0;right: 0;}
59
73
  &--absolute {position: absolute;}
60
74
  &--fixed {position: fixed;}
75
+ &--absolute.w-toolbar--vertical, &--fixed.w-toolbar--vertical {top: 0;bottom: 0;}
76
+ &--absolute.w-toolbar--left, &--fixed.w-toolbar--left {left: 0;right: auto;}
77
+ &--absolute.w-toolbar--right, &--fixed.w-toolbar--right {left: auto;right: 0;}
78
+
79
+ // Horizontal.
61
80
  &--top {border-bottom: $border;}
62
81
  &--bottom {
63
82
  bottom: 0;
64
83
  top: auto;
65
84
  border-top: $border;
66
85
  }
67
- &--no-border, &--shadow {
68
- border-top-width: 0;
69
- border-bottom-width: 0;
86
+
87
+ // Vertical.
88
+ &--vertical {
89
+ padding: (2 * $base-increment);
90
+ flex-direction: column;
91
+ flex-grow: 0;
92
+ flex-shrink: 0;
93
+ }
94
+
95
+ &--left {border-right: $border;}
96
+ &--right {
97
+ right: 0;
98
+ left: auto;
99
+ border-left: $border;
70
100
  }
101
+
102
+ &--no-border, &--shadow {border-width: 0;}
71
103
  &--shadow {box-shadow: $box-shadow;}
72
104
 
73
105
  .w-app > & {z-index: 200;}
@@ -81,5 +113,13 @@ export default {
81
113
  border-bottom-left-radius: inherit;
82
114
  border-bottom-right-radius: inherit;
83
115
  }
116
+ .w-card__content &--left {
117
+ border-top-left-radius: inherit;
118
+ border-bottom-left-radius: inherit;
119
+ }
120
+ .w-card__content &--right {
121
+ border-top-right-radius: inherit;
122
+ border-bottom-right-radius: inherit;
123
+ }
84
124
  }
85
125
  </style>
@@ -2,7 +2,12 @@
2
2
  .w-tooltip-wrap
3
3
  slot(name="activator" :on="activatorEventHandlers")
4
4
  transition(:name="transitionName" appear)
5
- .w-tooltip(v-if="detachableVisible" ref="detachable" :class="classes" :style="styles")
5
+ .w-tooltip(
6
+ v-if="detachableVisible"
7
+ ref="detachable"
8
+ :key="_uid"
9
+ :class="classes"
10
+ :style="styles")
6
11
  slot
7
12
  </template>
8
13
 
@@ -9,7 +9,6 @@ import { consoleWarn } from '../utils/console'
9
9
  export default {
10
10
  props: {
11
11
  // Position.
12
- detachTo: { type: [String, Boolean, Object], deprecated: true },
13
12
  appendTo: { type: [String, Boolean, Object] },
14
13
  fixed: { type: Boolean },
15
14
  top: { type: Boolean },
@@ -26,6 +25,10 @@ export default {
26
25
  activator: { type: [String, Object, HTMLElement] } // The activator can be a DOM string selector, a ref or a DOM node.
27
26
  },
28
27
 
28
+ inject: {
29
+ detachableDefaultRoot: { default: null }
30
+ },
31
+
29
32
  data: () => ({
30
33
  // The event listeners handlers have to be removed the exact same way they have been attached.
31
34
  // Since the handler functions have variables that change after hot-reload, keep them exactly
@@ -39,14 +42,15 @@ export default {
39
42
  // DOM element to attach tooltip/menu to.
40
43
  // ! \ This computed uses the DOM - NO SSR (only trigger from beforeMount and later).
41
44
  appendToTarget () {
42
- const defaultTarget = '.w-app'
45
+ let defaultTarget = '.w-app'
43
46
 
44
- // Convert deprecated prop to renamed one.
45
- if (this.detachTo && !this.appendTo) {
46
- consoleWarn(`The ${this.$options.name} prop \`detach-to\` is deprecated. You can replace it with \`append-to\`.`, this)
47
+ // If used inside a w-dialog, w-drawer, or w-menu without an appendTo, default to that open
48
+ // element instead of the w-app.
49
+ if (typeof this.detachableDefaultRoot === 'function') {
50
+ defaultTarget = this.detachableDefaultRoot() || defaultTarget
47
51
  }
48
52
 
49
- let target = this.appendTo || this.detachTo || defaultTarget
53
+ let target = this.appendTo || defaultTarget
50
54
  if (target === true) target = defaultTarget
51
55
  else if (this.appendTo === 'activator') target = this.$el.previousElementSibling
52
56
  else if (target && !['object', 'string'].includes(typeof target)) target = defaultTarget
@@ -145,7 +149,7 @@ export default {
145
149
  // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
146
150
  getActivatorCoordinates () {
147
151
  // Get the activator coordinates relative to window.
148
- const { top, left, width, height } = (this.activatorEl).getBoundingClientRect()
152
+ const { top, left, width, height } = this.activatorEl.getBoundingClientRect()
149
153
  let coords = { top, left, width, height }
150
154
 
151
155
  // If absolute position, adjust top & left.
@@ -167,6 +171,11 @@ export default {
167
171
  // Get the activator coordinates.
168
172
  let { top, left, width, height } = this.getActivatorCoordinates()
169
173
 
174
+ // Prevent error in case the detachable component unmounted hook is fired but the activator
175
+ // is still in the DOM until the end of a transition and the user toggles it.
176
+ // Unmounted is called straight away from beforeLeave: https://github.com/vuejs/core/issues/994
177
+ if (!this.detachableEl) return
178
+
170
179
  // 1. First display the menu but hide it (So we can get its dimension).
171
180
  // --------------------------------------------------
172
181
  this.detachableEl.style.visibility = 'hidden'
@@ -273,7 +282,6 @@ export default {
273
282
  this.detachableEl = this.$refs.detachable?.$el || this.$refs.detachable
274
283
 
275
284
  // Move the tooltip/menu elsewhere in the DOM.
276
- // wrapper.parentNode.insertBefore(this.detachableEl, wrapper)
277
285
  if (this.detachableEl) this.appendToTarget.appendChild(this.detachableEl)
278
286
  resolve()
279
287
  })
@@ -327,7 +335,7 @@ export default {
327
335
  // so check it on nextTick.
328
336
  else {
329
337
  this.$nextTick(() => {
330
- this.activator && this.bindActivatorEvents()
338
+ if (this.activator) this.bindActivatorEvents()
331
339
  if (this.value) this.toggle({ type: 'click', target: this.activatorEl })
332
340
  })
333
341
  }
@@ -341,10 +349,7 @@ export default {
341
349
  if (this.value && this.activator) this.toggle({ type: 'click', target: this.activatorEl })
342
350
  },
343
351
 
344
- // Must be on destroy and not before destroy, so that when used in a dialog, we wait for the end
345
- // of the animation before removing the activator element.
346
- // https://github.com/antoniandre/wave-ui/issues/82
347
- destroy () {
352
+ beforeDestroy () {
348
353
  this.close()
349
354
 
350
355
  this.removeFromDOM()
@@ -365,10 +370,6 @@ export default {
365
370
  value (bool) {
366
371
  if (!!bool !== this.detachableVisible) this.toggle({ type: 'click', target: this.activatorEl })
367
372
  },
368
- detachTo () {
369
- this.removeFromDOM()
370
- this.insertInDOM()
371
- },
372
373
  appendTo () {
373
374
  this.removeFromDOM()
374
375
  this.insertInDOM()
@@ -29,6 +29,15 @@ export default {
29
29
  },
30
30
  isReadonly () {
31
31
  return this.readonly || this.formProps.readonly
32
+ },
33
+ validationColor () {
34
+ return this.formProps.validationColor
35
+ },
36
+ labelClasses () {
37
+ return {
38
+ [this.labelColor]: this.labelColor && this.valid !== false,
39
+ [this.validationColor]: this.valid === false
40
+ }
32
41
  }
33
42
  },
34
43