wave-ui 1.69.0 → 1.70.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 +390 -69
  4. package/dist/wave-ui.umd.js +1 -1
  5. package/package.json +13 -13
  6. package/src/wave-ui/components/index.js +1 -0
  7. package/src/wave-ui/components/transitions/w-transition-expand.vue +2 -4
  8. package/src/wave-ui/components/w-accordion.vue +1 -4
  9. package/src/wave-ui/components/w-alert.vue +1 -4
  10. package/src/wave-ui/components/w-autocomplete.vue +404 -0
  11. package/src/wave-ui/components/w-badge.vue +1 -0
  12. package/src/wave-ui/components/w-button/button.vue +3 -8
  13. package/src/wave-ui/components/w-card.vue +2 -0
  14. package/src/wave-ui/components/w-drawer.vue +2 -8
  15. package/src/wave-ui/components/w-icon.vue +1 -1
  16. package/src/wave-ui/components/w-image.vue +2 -8
  17. package/src/wave-ui/components/w-input.vue +17 -16
  18. package/src/wave-ui/components/w-list.vue +1 -4
  19. package/src/wave-ui/components/w-notification-manager.vue +3 -3
  20. package/src/wave-ui/components/w-progress.vue +2 -8
  21. package/src/wave-ui/components/w-rating.vue +1 -4
  22. package/src/wave-ui/components/w-select.vue +66 -34
  23. package/src/wave-ui/components/w-slider.vue +6 -5
  24. package/src/wave-ui/components/w-spinner.vue +2 -0
  25. package/src/wave-ui/components/w-switch.vue +1 -1
  26. package/src/wave-ui/components/w-table.vue +220 -210
  27. package/src/wave-ui/components/w-tabs/index.vue +1 -4
  28. package/src/wave-ui/components/w-tag.vue +1 -4
  29. package/src/wave-ui/components/w-textarea.vue +0 -1
  30. package/src/wave-ui/components/w-timeline.vue +1 -0
  31. package/src/wave-ui/components/w-tree.vue +7 -7
  32. package/src/wave-ui/scss/_variables.scss +1 -1
@@ -508,10 +508,7 @@ export default {
508
508
  &:before {
509
509
  content: '';
510
510
  position: absolute;
511
- top: 0;
512
- left: 0;
513
- bottom: 0;
514
- right: 0;
511
+ inset: 0;
515
512
  background-color: currentColor;
516
513
  opacity: 0;
517
514
  transition: 0.2s;
@@ -47,10 +47,9 @@ export default {
47
47
  <style lang="scss">
48
48
  .w-notification-manager {
49
49
  position: fixed;
50
- top: 0;
51
- max-height: 100%;
52
- right: 0;
50
+ inset: 0 0 0 auto;
53
51
  z-index: 1000;
52
+ pointer-events: none;
54
53
  width: 280px;
55
54
  overflow-x: hidden;
56
55
  overflow-y: auto;
@@ -64,6 +63,7 @@ export default {
64
63
  right: 0;
65
64
  margin: 8px;
66
65
  flex-grow: 1;
66
+ pointer-events: all;
67
67
  }
68
68
  }
69
69
  </style>
@@ -154,10 +154,7 @@ $circle-size: 40;
154
154
  &.w-progress--default-bg:after {
155
155
  content: '';
156
156
  position: absolute;
157
- top: 0;
158
- bottom: 0;
159
- left: 0;
160
- right: 0;
157
+ inset: 0;
161
158
  border-radius: inherit;
162
159
  background-color: currentColor;
163
160
  opacity: 0.15;
@@ -188,10 +185,7 @@ $circle-size: 40;
188
185
  &:before, &:after {
189
186
  content: '';
190
187
  position: absolute;
191
- top: 0;
192
- bottom: 0;
193
- left: 0;
194
- right: -5%;
188
+ inset: 0 -5% 0 0;
195
189
  background: currentColor;
196
190
  z-index: 1;
197
191
  will-change: transform;
@@ -232,10 +232,7 @@ export default {
232
232
  &__button:after {
233
233
  content: "";
234
234
  position: absolute;
235
- top: 0;
236
- left: 0;
237
- right: 0;
238
- bottom: 0;
235
+ inset: 0;
239
236
  background-color: currentColor;
240
237
  border-radius: 100%;
241
238
  transform: translateX(100%) scale(0);
@@ -24,7 +24,7 @@ component(
24
24
  custom
25
25
  min-width="activator"
26
26
  v-bind="menuProps || {}")
27
- template(#activator="{ on }")
27
+ template(#activator)
28
28
  //- Input wrapper.
29
29
  .w-select__selection-wrap(
30
30
  @click="!isDisabled && !isReadonly && onInputFieldClick()"
@@ -43,16 +43,11 @@ component(
43
43
  slot(name="selection" :item="multiple ? inputValue : inputValue[0]")
44
44
  .w-select__selection(
45
45
  ref="selection-input"
46
- :contenteditable="isDisabled || isReadonly ? 'false' : 'true'"
47
46
  @focus="!isDisabled && !isReadonly && onFocus($event)"
48
47
  @blur="onBlur"
49
48
  @keydown="!isDisabled && !isReadonly && onKeydown($event)"
50
- :class="{ 'w-select__selection--placeholder': !$scopedSlots.selection && !selectionString && placeholder }"
51
- :disabled="isDisabled || null"
52
- readonly
53
- aria-readonly="true"
54
- :tabindex="tabindex || null"
55
- v-html="($scopedSlots.selection ? '' : selectionString) || placeholder")
49
+ v-bind="selectionAttributes"
50
+ v-html="selectionHtml")
56
51
  //- For standard HTML form submission.
57
52
  input(
58
53
  v-for="(val, i) in (inputValue.length ? inputValue : [{}])"
@@ -74,6 +69,7 @@ component(
74
69
  @input="onInput"
75
70
  @item-click="$emit('item-click', $event)"
76
71
  @item-select="onListItemSelect"
72
+ @keydown.native="onWListKeydown"
77
73
  @keydown:enter="noUnselect && !multiple && closeMenu()"
78
74
  @keydown:escape="showMenu && (showMenu = false) /* Will call closeMenu() from w-menu(@close). */"
79
75
  :value="inputValue"
@@ -161,7 +157,10 @@ export default {
161
157
  showMenu: false,
162
158
  menuMinWidth: 0,
163
159
  isFocused: false,
164
- selectionWrapRef: undefined
160
+ selectionWrapRef: undefined,
161
+ // Lookup a select list item from typing the first characters.
162
+ // If typing is too slow (> 1s), the lookup string is cleared.
163
+ quickLookup: { string: '', timeout: null }
165
164
  }),
166
165
 
167
166
  computed: {
@@ -178,27 +177,39 @@ export default {
178
177
  return obj
179
178
  })
180
179
  },
181
- hasValue () {
182
- return Array.isArray(this.inputValue) ? this.inputValue.length : (this.inputValue !== null)
183
- },
184
180
  hasLabel () {
185
181
  return this.label || this.$slots.default
186
182
  },
187
183
  showLabelInside () {
188
- return !this.staticLabel || (!this.hasValue && !this.placeholder)
184
+ return !this.staticLabel || (!this.inputValue.length && !this.placeholder)
185
+ },
186
+ selectionAttributes () {
187
+ return {
188
+ class: { 'w-select__selection--placeholder': !this.$scopedSlots.selection && !this.selectionString && this.placeholder },
189
+ disabled: this.isDisabled || null,
190
+ readonly: true,
191
+ ariareadonly: 'true',
192
+ tabindex: this.tabindex ?? null,
193
+ contenteditable: this.isDisabled || this.isReadonly ? 'false' : 'true'
194
+ }
189
195
  },
190
196
  selectionString () {
191
- return this.inputValue && this.inputValue.map(
197
+ return this.inputValue.map(
192
198
  item => item[this.itemValueKey] !== undefined ? item[this.itemLabelKey] : (item[this.itemLabelKey] ?? item)
193
199
  ).join(', ')
194
200
  },
201
+ selectionHtml () {
202
+ if (!this.inputValue.length) return this.placeholder || ''
203
+ if (this.$scopedSlots.selection) return ''
204
+ return this.selectionString
205
+ },
195
206
  classes () {
196
207
  return {
197
208
  'w-select': true,
198
209
  'w-select--disabled': this.isDisabled,
199
210
  'w-select--fit-to-content': this.fitToContent,
200
211
  'w-select--readonly': this.isReadonly,
201
- [`w-select--${this.hasValue ? 'filled' : 'empty'}`]: true,
212
+ [`w-select--${this.inputValue.length ? 'filled' : 'empty'}`]: true,
202
213
  'w-select--focused': (this.isFocused || this.showMenu) && !this.isReadonly,
203
214
  'w-select--dark': this.dark,
204
215
  'w-select--floating-label': this.hasLabel && this.labelPosition === 'inside' && !this.staticLabel,
@@ -291,13 +302,40 @@ export default {
291
302
  if (!allItemsAreDisabled) this.onInput(items[index])
292
303
  }
293
304
  }
305
+
306
+ // `e.key.length === 1`: only the keys that output a character.
307
+ else if (e.key.length === 1) this.focusItemOnQuickLookup(e)
308
+ },
309
+
310
+ onWListKeydown (e) {
311
+ // `e.key.length === 1`: only the keys that output a character.
312
+ if (e.key.length === 1) this.focusItemOnQuickLookup(e)
313
+ },
314
+
315
+ focusItemOnQuickLookup (e) {
316
+ // Reset the timer every time a new valid key is pressed so we concat the string of chars.
317
+ if (this.quickLookup.timeout) clearTimeout(this.quickLookup.timeout)
318
+ // On each keypress, wait for 1s and clear the lookup string unless a key is pressed again.
319
+ this.quickLookup.timeout = setTimeout(() => this.quickLookup.string = '', 1000)
320
+
321
+ // Form a lookup string that is tested (starting from the first char) on each list item until
322
+ // a match is found.
323
+ this.quickLookup.string += e.key
324
+ const re = new RegExp(`^${this.quickLookup.string}`, 'i')
325
+ const itemIndexToFocus = this.selectItems.findIndex(
326
+ item => !item.disabled && item[this.itemLabelKey].match(re)
327
+ ) + 1 // 0 if not found, more if found.
328
+ if (itemIndexToFocus) {
329
+ const selector = `.w-list__item:nth-child(${itemIndexToFocus}) .w-list__item-label`
330
+ this.$refs['w-list']?.$el?.querySelector(selector)?.focus()
331
+ }
294
332
  },
295
333
 
296
334
  // The items are given by the w-list component.
297
335
  onInput (items) {
298
336
  this.inputValue = items === null ? [] : (this.multiple ? items : [items])
299
337
  // Return the original items when returnObject is true (no `value` if there wasn't),
300
- // or the the item value otherwise.
338
+ // or the item value otherwise.
301
339
  items = this.inputValue.map(item => this.returnObject ? this.items[item.index] : item.value)
302
340
 
303
341
  // Emit the selection to the v-model.
@@ -306,6 +344,7 @@ export default {
306
344
  this.$emit('update:modelValue', selection)
307
345
  this.$emit('input', selection)
308
346
  },
347
+
309
348
  onInputFieldClick () {
310
349
  if (this.showMenu) this.showMenu = false // Will call `closeMenu()` from w-menu(@close).
311
350
  else this.openMenu()
@@ -338,7 +377,7 @@ export default {
338
377
  return items.map(item => {
339
378
  let value = item
340
379
  if (item && typeof item === 'object') { // `null` is also an object!
341
- value = item[this.itemValueKey] !== undefined ? item[this.itemValueKey] : (item[this.itemLabelKey] !== undefined ? item[this.itemLabelKey] : item)
380
+ value = item[this.itemValueKey] ?? item[this.itemLabelKey] ?? item
342
381
  }
343
382
 
344
383
  return this.selectItems[allValues.indexOf(value)]
@@ -362,7 +401,7 @@ export default {
362
401
 
363
402
  this.showMenu = false
364
403
  // Set the focus back on the main w-select input.
365
- setTimeout(() => this.$refs['selection-input'].focus(), 50)
404
+ setTimeout(() => this.$refs['selection-input']?.focus(), 50)
366
405
  }
367
406
  },
368
407
 
@@ -471,6 +510,9 @@ export default {
471
510
  align-items: center;
472
511
  cursor: pointer;
473
512
  caret-color: transparent;
513
+ border-radius: inherit;
514
+
515
+ &--placeholder {color: #888;}
474
516
 
475
517
  .w-select__selection-slot + & {
476
518
  position: absolute;
@@ -497,8 +539,6 @@ export default {
497
539
  }
498
540
 
499
541
  .w-select--readonly & {cursor: auto;}
500
-
501
- &--placeholder {color: #888;}
502
542
  }
503
543
 
504
544
  &__selection-slot {
@@ -560,14 +600,12 @@ export default {
560
600
 
561
601
  &__label--inside {
562
602
  position: absolute;
563
- top: 50%;
564
- left: 0;
565
- right: 0;
603
+ inset: 0 0 auto;
604
+ min-height: inherit;
566
605
  white-space: nowrap;
567
606
  // Use margin instead of padding as the scale transformation below decreases the real padding
568
607
  // size and misaligns the label.
569
608
  margin-left: 2 * $base-increment;
570
- transform: translateY(-50%);
571
609
  pointer-events: none;
572
610
 
573
611
  .w-select--inner-icon-right & {padding-right: 26px;}
@@ -591,21 +629,15 @@ export default {
591
629
  .w-select--open.w-select--floating-label &,
592
630
  .w-select--filled.w-select--floating-label &,
593
631
  .w-select--has-placeholder.w-select--floating-label & {
594
- transform: translateY(-160%) scale(0.85);
632
+ transform: translateY(-80%) scale(0.85);
595
633
  }
596
- // Chrome & Safari - Must remain in a separated rule as Firefox discard the whole rule seeing -webkit-.
634
+ // Chrome & Safari - Must stay a separated rule or Firefox discards the whole rule seeing -webkit-.
597
635
  .w-select--floating-label .w-select__select:-webkit-autofill & {
598
- transform: translateY(-160%) scale(0.85);
599
- }
600
- // Move label with outline style or with shadow.
601
- .w-select--open.w-select--floating-label .w-select__selection-wrap--box &,
602
- .w-select--filled.w-select--floating-label .w-select__selection-wrap--box &,
603
- .w-select--has-placeholder.w-select--floating-label .w-select__selection-wrap--box & {
604
- transform: translateY(-180%) scale(0.85);
636
+ transform: translateY(-80%) scale(0.85);
605
637
  }
606
638
  .w-select--open.w-select--floating-label.w-select--inner-icon-left &,
607
639
  .w-select--filled.w-select--floating-label.w-select--inner-icon-left & {left: 0;}
608
- // Chrome & Safari - Must remain in a separated rule as Firefox discard the whole rule seeing -webkit-.
640
+ // Chrome & Safari - Must stay a separated rule or Firefox discards the whole rule seeing -webkit-.
609
641
  .w-select--floating-label.w-select--inner-icon-left .w-select__select:-webkit-autofill & {left: 0;}
610
642
  }
611
643
 
@@ -296,7 +296,8 @@ export default {
296
296
  top: 0;
297
297
  width: $base-increment;
298
298
  aspect-ratio: 1;
299
- background-color: rgba(0, 0, 0, 0.2);
299
+ min-width: 0; // Safari ratio fix (e.g. losing ratio if height is set and side padding are added).
300
+ background-color: $slider-step-label-bg-color;
300
301
  border-radius: 99em;
301
302
  // box-shadow: 0 0 0 1px #fff;
302
303
  box-sizing: border-box;
@@ -359,6 +360,7 @@ export default {
359
360
  position: absolute;
360
361
  width: 3 * $base-increment;
361
362
  aspect-ratio: 1;
363
+ min-width: 0; // Safari ratio fix (e.g. losing ratio if height is set and side padding are added).
362
364
  left: 100%;
363
365
  top: 50%;
364
366
  transform: translate(-50%, -50%);
@@ -374,6 +376,7 @@ export default {
374
376
  top: 0;
375
377
  width: 100%;
376
378
  aspect-ratio: 1;
379
+ min-width: 0; // Safari ratio fix (e.g. losing ratio if height is set and side padding are added).
377
380
  border: none;
378
381
  border-radius: 99em;
379
382
  cursor: pointer;
@@ -389,10 +392,7 @@ export default {
389
392
  }
390
393
  // Colored border on thumb when hover and active - but with a transparency.
391
394
  &:before {
392
- left: 0;
393
- right: 0;
394
- top: 0;
395
- bottom: 0;
395
+ inset: 0;
396
396
  opacity: 0.5;
397
397
  border: 1px solid currentColor;
398
398
  }
@@ -453,6 +453,7 @@ export default {
453
453
  border-radius: 99em 99em 99em 0;
454
454
  width: 2.8em;
455
455
  aspect-ratio: 1;
456
+ min-width: 0; // Safari ratio fix (e.g. losing ratio if height is set and side padding are added).
456
457
 
457
458
  & > div {
458
459
  position: absolute;
@@ -62,6 +62,7 @@ export default {
62
62
  font-size: 2rem;
63
63
  width: 1em;
64
64
  aspect-ratio: 1;
65
+ min-width: 0; // Safari ratio fix (e.g. losing ratio if height is set and side padding are added).
65
66
 
66
67
  &.size--xs {font-size: round(0.9 * divide($base-font-size, 2)) * 2;}
67
68
  &.size--sm {font-size: round(1.5 * $base-font-size);}
@@ -74,6 +75,7 @@ export default {
74
75
  position: absolute;
75
76
  width: 100%;
76
77
  aspect-ratio: 1;
78
+ min-width: 0; // Safari ratio fix (e.g. losing ratio if height is set and side padding are added).
77
79
  top: 0;
78
80
  left: 0;
79
81
  background-color: currentColor;
@@ -252,7 +252,7 @@ $disabled-color: #ddd;
252
252
 
253
253
  // The focus outline & ripple on switch activation.
254
254
  &__input:before {
255
- content: "";
255
+ content: '';
256
256
  position: absolute;
257
257
  left: 0;
258
258
  top: 0;