wave-ui 2.24.0 → 2.28.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-ui",
3
- "version": "2.24.0",
3
+ "version": "2.28.0",
4
4
  "description": "An emerging UI framework for Vue.js & Vue 3 with only the bright side. :sunny:",
5
5
  "author": "Antoni Andre <antoniandre.web@gmail.com>",
6
6
  "main": "./dist/wave-ui.umd.js",
@@ -43,28 +43,29 @@
43
43
  "*.vue"
44
44
  ],
45
45
  "devDependencies": {
46
- "@babel/core": "^7.14.8",
47
- "@babel/eslint-parser": "^7.14.7",
48
- "@babel/plugin-proposal-class-properties": "^7.14.5",
46
+ "@babel/core": "^7.16.0",
47
+ "@babel/eslint-parser": "^7.16.3",
48
+ "@babel/plugin-proposal-class-properties": "^7.16.0",
49
49
  "@mdi/font": "^5.9.55",
50
- "@vitejs/plugin-vue": "^1.2.2",
50
+ "@vitejs/plugin-vue": "^1.9.4",
51
51
  "@vue/compiler-sfc": "3.1.5",
52
- "autoprefixer": "^10.2.5",
53
- "axios": "^0.21.1",
54
- "eslint": "^7.28.0",
52
+ "autoprefixer": "^10.4.0",
53
+ "axios": "^0.21.4",
54
+ "eslint": "^7.32.0",
55
55
  "font-awesome": "^4.7.0",
56
- "gsap": "^3.6.1",
56
+ "gsap": "^3.8.0",
57
57
  "ionicons": "^4.6.3",
58
58
  "material-design-icons": "^3.0.1",
59
59
  "rollup-plugin-delete": "^2.0.0",
60
- "sass": "^1.34.0",
61
- "simple-syntax-highlighter": "^2.0.6",
62
- "splitpanes": "^3.0.4",
63
- "vite": "^2.3.3",
60
+ "sass": "^1.43.4",
61
+ "simple-syntax-highlighter": "^2.2.0",
62
+ "splitpanes": "^3.0.6",
63
+ "vite": "^2.6.14",
64
64
  "vite-plugin-pug": "^0.3.0",
65
- "vue": "^3.2.13",
65
+ "vue": "^3.2.26",
66
66
  "vue-cal": "^4.2.0",
67
- "vue-router": "^4.0.8",
68
- "vueperslides": "^3.3.0"
67
+ "vue-router": "^4.0.12",
68
+ "vueperslides": "^3.3.2",
69
+ "vuex": "^4.0.2"
69
70
  }
70
71
  }
@@ -5,9 +5,10 @@ export { default as WApp } from './w-app.vue'
5
5
  export { default as WBadge } from './w-badge.vue'
6
6
  export { default as WBreadcrumbs } from './w-breadcrumbs.vue'
7
7
  export { default as WButton } from './w-button.vue'
8
+ export { default as WCard } from './w-card.vue'
8
9
  export { default as WCheckbox } from './w-checkbox.vue'
9
10
  export { default as WCheckboxes } from './w-checkboxes.vue'
10
- export { default as WCard } from './w-card.vue'
11
+ export { default as WConfirm } from './w-confirm.vue'
11
12
  export { default as WDatePicker } from './w-date-picker.vue'
12
13
  export { default as WDialog } from './w-dialog.vue'
13
14
  export { default as WDivider } from './w-divider.vue'
@@ -32,7 +33,7 @@ export { default as WSlider } from './w-slider.vue'
32
33
  export { default as WSpinner } from './w-spinner.vue'
33
34
  export { default as WSteps } from './w-steps.vue'
34
35
  export { default as WSwitch } from './w-switch.vue'
35
- export { default as WTabs } from './w-tabs.vue'
36
+ export { default as WTabs } from './w-tabs/index.vue'
36
37
  export { default as WTable } from './w-table.vue'
37
38
  export { default as WTag } from './w-tag.vue'
38
39
  export { default as WTextarea } from './w-textarea.vue'
@@ -1,5 +1,5 @@
1
1
  <template lang="pug">
2
- .w-app(:class="{ 'theme--dark': dark, 'd-block': block }")
2
+ .w-app(:class="classes")
3
3
  slot
4
4
  notification-manager
5
5
  </template>
@@ -16,7 +16,17 @@ export default {
16
16
  name: 'w-app',
17
17
  props: {
18
18
  dark: { type: Boolean },
19
- block: { type: Boolean }
19
+ block: { type: Boolean },
20
+ row: { type: Boolean },
21
+ alignCenter: { type: Boolean },
22
+ alignEnd: { type: Boolean },
23
+ justifyCenter: { type: Boolean },
24
+ justifyEnd: { type: Boolean },
25
+ justifySpaceBetween: { type: Boolean },
26
+ justifySpaceAround: { type: Boolean },
27
+ justifySpaceEvenly: { type: Boolean },
28
+ textCenter: { type: Boolean },
29
+ textRight: { type: Boolean }
20
30
  },
21
31
 
22
32
  components: { NotificationManager },
@@ -26,6 +36,25 @@ export default {
26
36
  notifManager: null
27
37
  }),
28
38
 
39
+ computed: {
40
+ classes () {
41
+ return {
42
+ 'd-block': this.block,
43
+ 'row': this.row,
44
+ 'align-center': this.alignCenter,
45
+ 'align-end': this.alignEnd,
46
+ 'justify-center': this.justifyCenter,
47
+ 'justify-end': this.justifyEnd,
48
+ 'justify-space-between': this.justifySpaceBetween,
49
+ 'justify-space-around': this.justifySpaceAround,
50
+ 'justify-space-evenly': this.justifySpaceEvenly,
51
+ 'text-center': this.textCenter,
52
+ 'text-right': this.textRight,
53
+ 'theme--dark': this.dark
54
+ }
55
+ }
56
+ },
57
+
29
58
  methods: {
30
59
  getBreakpoint () {
31
60
  const width = window.innerWidth
@@ -85,6 +114,17 @@ export default {
85
114
  flex-direction: column;
86
115
  min-height: 100vh;
87
116
 
117
+ &.row {flex-direction: row;}
88
118
  &.d-block {display: block;}
119
+ &.align-center {align-items: center;}
120
+ &.align-end {align-items: flex-end;}
121
+ &.justify-center {justify-content: center;}
122
+ &.justify-end {justify-content: flex-end;}
123
+ &.justify-space-between {justify-content: space-between;}
124
+ &.justify-space-around {justify-content: space-around;}
125
+ &.justify-space-evenly {justify-content: space-evenly;}
126
+ &.text-center {text-align: center;}
127
+ &.text-right {text-align: right;}
128
+
89
129
  }
90
130
  </style>
@@ -1,5 +1,5 @@
1
1
  <template lang="pug">
2
- .w-badge-wrap
2
+ .w-badge-wrap(v-on="$attrs")
3
3
  slot
4
4
  transition(:name="`${transition}`")
5
5
  .w-badge(
@@ -104,6 +104,7 @@ export default {
104
104
  border-radius: 99em;
105
105
  // Always get an even number for better text vertical align.
106
106
  height: round(1.1 * divide($base-font-size, 2)) * 2;
107
+ line-height: round(1.1 * divide($base-font-size, 2)) * 2;
107
108
  min-width: round(1.1 * divide($base-font-size, 2)) * 2;
108
109
  z-index: 1;
109
110
  padding: 0 $base-increment;
@@ -121,29 +122,38 @@ export default {
121
122
  $height: round(divide($base-font-size, 2)) * 2;
122
123
  font-size: round(0.67 * divide($base-font-size, 2)) * 2;
123
124
  height: $height;
125
+ line-height: $height;
124
126
  min-width: $height;
125
127
 
126
128
  &--round {width: $height;padding: 0 round(divide($height, 2));}
127
129
  }
128
130
  &.size--sm {
131
+ $height: round(1.1 * divide($base-font-size, 2)) * 2;
129
132
  font-size: round(0.75 * divide($base-font-size, 2)) * 2;
130
- height: round(1.1 * divide($base-font-size, 2)) * 2;
131
- min-width: round(1.1 * divide($base-font-size, 2)) * 2;
133
+ height: $height;
134
+ line-height: $height;
135
+ min-width: $height;
132
136
  }
133
137
  &.size--md {
138
+ $height: round(1.3 * divide($base-font-size, 2)) * 2;
134
139
  font-size: round(0.9 * divide($base-font-size, 2)) * 2;
135
- height: round(1.3 * divide($base-font-size, 2)) * 2;
136
- min-width: round(1.3 * divide($base-font-size, 2)) * 2;
140
+ height: $height;
141
+ line-height: $height;
142
+ min-width: $height;
137
143
  }
138
144
  &.size--lg {
145
+ $height: round(1.5 * divide($base-font-size, 2)) * 2;
139
146
  font-size: round(1.05 * divide($base-font-size, 2)) * 2;
140
- height: round(1.5 * divide($base-font-size, 2)) * 2;
141
- min-width: round(1.5 * divide($base-font-size, 2)) * 2;
147
+ height: $height;
148
+ line-height: $height;
149
+ min-width: $height;
142
150
  }
143
151
  &.size--xl {
152
+ $height: round(1.8 * divide($base-font-size, 2)) * 2;
144
153
  font-size: round(1.2 * divide($base-font-size, 2)) * 2;
145
- height: round(1.8 * divide($base-font-size, 2)) * 2;
146
- min-width: round(1.8 * divide($base-font-size, 2)) * 2;
154
+ height: $height;
155
+ line-height: $height;
156
+ min-width: $height;
147
157
  }
148
158
 
149
159
  // Position.
@@ -2,12 +2,12 @@
2
2
  .w-card(:class="classes" :style="styles")
3
3
  .w-card__title(
4
4
  v-if="$slots.title"
5
- :class="{ 'w-card__title--has-toolbar': titleHasToolbar, [titleClass]: titleClass || false }")
5
+ :class="{ 'w-card__title--has-toolbar': titleHasToolbar, ...titleClasses }")
6
6
  slot(name="title")
7
- .w-card__title(v-else-if="title" :class="titleClass || false" v-html="title")
7
+ .w-card__title(v-else-if="title" :class="titleClasses" v-html="title")
8
8
  w-image.w-card__image(v-if="image" :src="image" v-bind="imgProps")
9
9
  slot(name="image-content")
10
- .w-card__content(:class="contentClass || false")
10
+ .w-card__content(:class="contentClasses")
11
11
  slot
12
12
  .w-card__actions(
13
13
  v-if="$slots.actions"
@@ -16,6 +16,8 @@
16
16
  </template>
17
17
 
18
18
  <script>
19
+ import { objectifyClasses } from '../utils/index'
20
+
19
21
  export default {
20
22
  name: 'w-card',
21
23
 
@@ -28,21 +30,31 @@ export default {
28
30
  title: { type: String },
29
31
  image: { type: String },
30
32
  imageProps: { type: Object },
31
- titleClass: { type: String },
32
- contentClass: { type: String }
33
+ titleClass: { type: [String, Object, Array] },
34
+ contentClass: { type: [String, Object, Array] }
33
35
  },
34
36
 
35
37
  emits: [],
36
38
 
37
39
  computed: {
40
+ titleClasses () {
41
+ return objectifyClasses(this.titleClass)
42
+ },
43
+
44
+ contentClasses () {
45
+ return objectifyClasses(this.contentClass)
46
+ },
47
+
38
48
  titleHasToolbar () {
39
49
  const { title } = this.$slots
40
50
  return title && title().map(vnode => vnode.type.name).join('').includes('w-toolbar')
41
51
  },
52
+
42
53
  actionsHasToolbar () {
43
54
  const { actions } = this.$slots
44
55
  return actions && actions().map(vnode => vnode.type.name).join('').includes('w-toolbar')
45
56
  },
57
+
46
58
  imgProps () {
47
59
  return {
48
60
  tag: 'div',
@@ -50,6 +62,7 @@ export default {
50
62
  ...this.imageProps
51
63
  }
52
64
  },
65
+
53
66
  classes () {
54
67
  return {
55
68
  [this.color]: this.color,
@@ -59,6 +72,7 @@ export default {
59
72
  'w-card--shadow': this.shadow
60
73
  }
61
74
  },
75
+
62
76
  styles () {
63
77
  return false
64
78
  }
@@ -0,0 +1,103 @@
1
+ <template lang="pug">
2
+ .w-confirm
3
+ w-menu(v-model="showPopup" v-bind="wMenuProps")
4
+ template(#activator="{ on }")
5
+ w-button.w-confirm__button(v-on="on" v-bind="buttonProps")
6
+ slot
7
+ w-flex(:column="!inline" align-center)
8
+ div
9
+ slot(name="question") Are you sure?
10
+ .w-flex.justify-end(:class="inline ? 'ml2' : 'mt2'")
11
+ w-button.mr2(
12
+ v-if="!noCancel"
13
+ v-bind="cancelButton"
14
+ :bg-color="(cancelButton || {}).bgColor || 'error'"
15
+ @click="onCancel")
16
+ slot(name="cancel") Cancel
17
+ w-button(
18
+ v-bind="confirmButton"
19
+ :bg-color="(confirmButton || {}).bgColor || 'success'"
20
+ @click="onConfirm")
21
+ slot(name="confirm") Confirm
22
+ </template>
23
+
24
+ <script>
25
+ export default {
26
+ name: 'w-confirm',
27
+ props: {
28
+ // Main button props.
29
+ bgColor: { type: String },
30
+ color: { type: String },
31
+ icon: { type: String },
32
+ mainButton: { type: Object }, // Allow passing down an object of props to the w-button component.
33
+
34
+ // Cancel & confirm buttons props.
35
+ noCancel: { type: Boolean }, // Removes the cancel button.
36
+ cancelButton: { type: [Boolean, Object] }, // Allow passing down an object of props to the w-button component.
37
+ confirmButton: { type: Object }, // Allow passing down an object of props to the w-button component.
38
+
39
+ // global menu props.
40
+ inline: { type: Boolean }, // The layout inside the menu.
41
+
42
+ // W-menu props.
43
+ menu: { type: Object }, // Allow passing down an object of props to the w-menu component.
44
+ // All the menu props shorthands, as long as they don't conflict with the button props.
45
+ noArrow: { type: Boolean }, // Adds a directional triangle to the edge of the menu, like a tooltip.
46
+ top: { type: Boolean },
47
+ bottom: { type: Boolean },
48
+ left: { type: Boolean },
49
+ right: { type: Boolean },
50
+ alignTop: { type: Boolean },
51
+ alignBottom: { type: Boolean },
52
+ alignLeft: { type: Boolean },
53
+ alignRight: { type: Boolean },
54
+ persistent: { type: Boolean },
55
+ transition: { type: String }
56
+ },
57
+
58
+ emits: ['cancel', 'confirm'],
59
+
60
+ data: () => ({
61
+ showPopup: false,
62
+ props: []
63
+ }),
64
+
65
+ computed: {
66
+ wMenuProps () {
67
+ return {
68
+ top: this.top,
69
+ bottom: this.bottom,
70
+ left: this.left,
71
+ right: this.right,
72
+ arrow: !this.noArrow,
73
+ alignTop: this.alignTop,
74
+ alignBottom: this.alignBottom,
75
+ alignLeft: this.alignLeft,
76
+ alignRight: this.alignRight,
77
+ persistent: this.persistent,
78
+ transition: this.transition,
79
+ ...this.menu
80
+ }
81
+ },
82
+ buttonProps () {
83
+ return {
84
+ bgColor: this.bgColor,
85
+ color: this.color,
86
+ icon: this.icon,
87
+ ...this.mainButton
88
+ }
89
+ }
90
+ },
91
+
92
+ methods: {
93
+ onCancel () {
94
+ this.$emit('cancel')
95
+ this.showPopup = false
96
+ },
97
+ onConfirm () {
98
+ this.$emit('confirm')
99
+ this.showPopup = false
100
+ }
101
+ }
102
+ }
103
+ </script>
@@ -48,7 +48,7 @@ export default {
48
48
  ligature () {
49
49
  if (!config.iconsLigature) return false
50
50
 
51
- const [fontName, icon] = this.icon.split(' ')
51
+ const [fontName, icon] = this.$slots.default()[0].children
52
52
  return fontName === config.iconsLigature && { fontName, icon }
53
53
  },
54
54
  forcedSize () {
@@ -66,7 +66,7 @@ export default {
66
66
  },
67
67
  classes () {
68
68
  return {
69
- [this.icon]: true,
69
+ [this.$slots.default()[0].children]: true,
70
70
  [this.color]: this.color,
71
71
  [`${this.bgColor}--bg`]: this.bgColor,
72
72
  [`size--${this.presetSize}`]: this.presetSize && !this.forcedSize,
@@ -87,16 +87,6 @@ export default {
87
87
  styles () {
88
88
  return this.forcedSize && `font-size: ${this.forcedSize}`
89
89
  }
90
- },
91
-
92
- created () {
93
- const { default: slotContent } = this.$slots
94
- this.icon = slotContent ? (slotContent()[0].children || '').trim() : ''
95
- },
96
-
97
- beforeUpdate () {
98
- const { default: slotContent } = this.$slots
99
- this.icon = slotContent ? (slotContent()[0].children || '').trim() : ''
100
90
  }
101
91
  }
102
92
  </script>
@@ -121,9 +111,7 @@ export default {
121
111
  &.size--lg {font-size: round(1.7 * $base-font-size);}
122
112
  &.size--xl {font-size: 2 * $base-font-size;}
123
113
 
124
- // In w-button and w-alert.
125
- // .w-button &, .w-alert & {font-size: round(1.4 * $base-font-size);}
126
- // Always an even number to vertical align well in button.
114
+ // Always an even number to align well vertically in a button.
127
115
  .w-button.size--xs & {font-size: round(0.95 * divide($base-font-size, 2)) * 2;}
128
116
  .w-alert.size--xs & {font-size: $base-font-size;}
129
117
  .w-button.size--sm &, .w-alert.size--sm & {font-size: round(1.15 * $base-font-size);}
@@ -55,10 +55,13 @@ component(
55
55
  @change="onFileChange"
56
56
  :multiple="multiple || null"
57
57
  v-bind="attrs")
58
- label.w-input__input(:for="`w-input--${_.uid}`")
59
- template(v-for="(file, i) in inputFiles")
58
+ transition-group.w-input__input.w-input__input--file(tag="label" name="fade" :for="`w-input--${_.uid}`")
59
+ span.w-input__no-file(v-if="!inputFiles.length && isFocused" key="no-file")
60
+ slot(name="no-file")
61
+ template(v-if="$slots['no-file'] === undefined") No file
62
+ span(v-for="(file, i) in inputFiles" :key="file.lastModified")
60
63
  | {{ i ? ', ': '' }}
61
- span {{ file.base }}
64
+ span.filename(:key="`${i}b`") {{ file.base }}
62
65
  | {{ file.extension }}
63
66
 
64
67
  template(v-if="labelPosition === 'inside' && showLabelInside")
@@ -78,7 +81,18 @@ component(
78
81
  :for="`w-input--${_.uid}`"
79
82
  @click="$emit('click:inner-icon-right', $event)") {{ innerIconRight }}
80
83
 
81
- img.w-input__file-preview(v-for="(file, i) in inputFiles" :key="i" :src="file.preview")
84
+ //- Files preview.
85
+ label.d-flex(v-if="type === 'file' && inputFiles.length" :for="`w-input--${_.uid}`")
86
+ template(v-for="(file, i) in inputFiles")
87
+ i.w-icon.wi-spinner.w-icon--spin.size--sm.w-input__file-preview.primary(
88
+ v-if="file.progress < 100"
89
+ :key="`${i}a`")
90
+ img.w-input__file-preview(
91
+ v-else-if="file.preview"
92
+ :key="`${i}b`"
93
+ :src="file.preview"
94
+ alt="")
95
+ i.w-icon.wi-file.w-input__file-preview.primary(v-else :key="`${i}c`")
82
96
 
83
97
  //- Right label.
84
98
  template(v-if="labelPosition === 'right'")
@@ -189,6 +203,7 @@ export default {
189
203
  classes () {
190
204
  return {
191
205
  'w-input': true,
206
+ 'w-input--file': this.type === 'file',
192
207
  'w-input--disabled': this.isDisabled,
193
208
  'w-input--readonly': this.isReadonly,
194
209
  [`w-input--${this.hasValue ? 'filled' : 'empty'}`]: true,
@@ -206,6 +221,7 @@ export default {
206
221
  return {
207
222
  [this.valid === false ? 'error' : this.color]: this.color || this.valid === false,
208
223
  [`${this.bgColor}--bg`]: this.bgColor,
224
+ 'w-input__input-wrap--file': this.type === 'file',
209
225
  'w-input__input-wrap--round': this.round,
210
226
  'w-input__input-wrap--tile': this.tile,
211
227
  // Box adds a padding on input. If there is a bgColor or shadow, a padding is needed.
@@ -235,16 +251,8 @@ export default {
235
251
  this.$emit('blur', e)
236
252
  },
237
253
 
254
+ // For file input.
238
255
  onFileChange (e) {
239
- // [...e.target.files].forEach((file, i) => {
240
- // this.inputFiles[i] = Object.assign({}, file)
241
- // this.filePreview(file)
242
- // })
243
-
244
- // this.inputFiles = [...e.target.files].map(file => {
245
- // this.filePreview(file)
246
- // return file
247
- // })
248
256
  this.inputFiles = [...e.target.files].map(original => {
249
257
  const [, base, extension] = original.name.match(/^(.*)(\..*?)$/)
250
258
  const file = reactive({
@@ -254,7 +262,8 @@ export default {
254
262
  type: original.type,
255
263
  size: original.size,
256
264
  lastModified: original.lastModified,
257
- preview: ''
265
+ preview: null,
266
+ progress: 0
258
267
  })
259
268
 
260
269
  this.filePreview(original, file)
@@ -264,14 +273,22 @@ export default {
264
273
  this.$emit('update:modelValue', this.inputFiles)
265
274
  },
266
275
 
276
+ // For file input.
267
277
  filePreview (original, file) {
268
- // Check if the file is an image.
269
- if (original.type && !original.type.startsWith('image/')) return
270
-
271
278
  const reader = new FileReader()
272
- reader.addEventListener('load', e => {
273
- file.preview = e.target.result
279
+
280
+ // Check if the file is an image and set a preview image.
281
+ if (original.type && original.type.startsWith('image/')) {
282
+ reader.addEventListener('load', e => {
283
+ file.preview = e.target.result
284
+ })
285
+ }
286
+
287
+ // Used to display a spinner while the file is loading.
288
+ reader.addEventListener('progress', e => {
289
+ if (e.loaded && e.total) file.progress = e.loaded * 100 / e.total
274
290
  })
291
+
275
292
  reader.readAsDataURL(original)
276
293
  }
277
294
  },
@@ -295,6 +312,11 @@ $inactive-color: #777;
295
312
  align-items: center;
296
313
  font-size: $base-font-size;
297
314
 
315
+ &--file {
316
+ flex-wrap: nowrap;
317
+ align-items: flex-end;
318
+ }
319
+
298
320
  // Input field wrapper.
299
321
  // ------------------------------------------------------
300
322
  &__input-wrap {
@@ -310,6 +332,9 @@ $inactive-color: #777;
310
332
  .w-input--floating-label & {margin-top: 3 * $base-increment;}
311
333
  .w-input[class^="bdrs"] &, .w-input[class*=" bdrs"] & {border-radius: inherit;}
312
334
 
335
+ // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size
336
+ &--file {min-width: 0;}
337
+
313
338
  &--underline {
314
339
  border-bottom-left-radius: initial;
315
340
  border-bottom-right-radius: initial;
@@ -409,6 +434,32 @@ $inactive-color: #777;
409
434
  opacity: 0;
410
435
  }
411
436
 
437
+ &__input--file {
438
+ > span {
439
+ display: inline-flex;
440
+ overflow: hidden;
441
+ white-space: nowrap;
442
+ }
443
+
444
+ .filename {
445
+ margin-left: 0.2em;
446
+ overflow: hidden;
447
+ text-overflow: ellipsis;
448
+ }
449
+
450
+ > span:first-child .filename {margin-left: 0;}
451
+ }
452
+
453
+ &__no-file {
454
+ position: absolute;
455
+ top: 0;
456
+ bottom: 0;
457
+ left: 0;
458
+ display: flex;
459
+ align-items: center;
460
+ color: $disabled-color;
461
+ }
462
+
412
463
  &__file-preview {
413
464
  margin-left: 4px;
414
465
  max-height: 2em;
@@ -474,6 +525,7 @@ $inactive-color: #777;
474
525
  .w-input--floating-label & {
475
526
  transform-origin: 0 0;
476
527
  transition: $transition-duration ease;
528
+ will-change: transform;
477
529
  }
478
530
 
479
531
  // move label with underline style.