wave-ui 2.26.0 → 2.29.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.
@@ -1,11 +1,10 @@
1
1
  <template lang="pug">
2
- .w-menu-wrap(ref="wrapper")
2
+ .w-menu-wrap
3
3
  slot(name="activator" :on="activatorEventHandlers")
4
- transition(:name="transitionName")
4
+ transition(:name="transitionName" appear)
5
5
  .w-menu(
6
- v-if="custom"
6
+ v-if="custom && menuVisible"
7
7
  ref="menu"
8
- v-show="showMenu"
9
8
  @click="hideOnMenuClick && closeMenu(true)"
10
9
  @mouseenter="showOnHover && (hoveringMenu = true)"
11
10
  @mouseleave="showOnHover && ((hoveringMenu = false), closeMenu())"
@@ -13,15 +12,14 @@
13
12
  :style="styles")
14
13
  slot
15
14
  w-card.w-menu(
16
- v-else
15
+ v-else-if="menuVisible"
17
16
  ref="menu"
18
- v-show="showMenu"
19
17
  @click.native="hideOnMenuClick && closeMenu(true)"
20
18
  @mouseenter.native="showOnHover && (hoveringMenu = true)"
21
19
  @mouseleave.native="showOnHover && ((hoveringMenu = false), closeMenu())"
22
20
  :tile="tile"
23
- :title-class="titleClass"
24
- :content-class="contentClass"
21
+ :title-class="titleClasses"
22
+ :content-class="contentClasses"
25
23
  :shadow="shadow"
26
24
  :no-border="noBorder"
27
25
  :class="classes"
@@ -34,12 +32,12 @@
34
32
  w-overlay(
35
33
  v-if="overlay"
36
34
  ref="overlay"
37
- :model-value="showMenu"
35
+ :model-value="menuVisible"
38
36
  :persistent="persistent"
39
- :class="overlayClass || null"
37
+ :class="overlayClasses"
40
38
  v-bind="overlayProps"
41
39
  :z-index="(zIndex || 200) - 1"
42
- @update:model-value="showMenu = false")
40
+ @update:model-value="menuVisible = false")
43
41
  </template>
44
42
 
45
43
  <script>
@@ -52,6 +50,7 @@
52
50
  * and move the menu elsewhere in the DOM.
53
51
  */
54
52
 
53
+ import { objectifyClasses } from '../utils/index'
55
54
  import { consoleWarn } from '../utils/console'
56
55
 
57
56
  // const marginFromWindowSide = 4 // Amount of px from a window side, instead of overflowing.
@@ -71,10 +70,11 @@ export default {
71
70
  round: { type: Boolean },
72
71
  noBorder: { type: Boolean },
73
72
  transition: { type: String },
74
- menuClass: { type: String },
75
- titleClass: { type: String },
76
- contentClass: { type: String },
73
+ menuClass: { type: [String, Object, Array] },
74
+ titleClass: { type: [String, Object, Array] },
75
+ contentClass: { type: [String, Object, Array] },
77
76
  // Position.
77
+ arrow: { type: Boolean }, // The small triangle pointing toward the activator.
78
78
  detachTo: { type: [String, Boolean, Object] },
79
79
  fixed: { type: Boolean },
80
80
  top: { type: Boolean },
@@ -88,7 +88,7 @@ export default {
88
88
  zIndex: { type: [Number, String, Boolean] },
89
89
  minWidth: { type: [Number, String] }, // can be like: `40`, `5em`, `activator`.
90
90
  overlay: { type: Boolean },
91
- overlayClass: { type: String },
91
+ overlayClass: { type: [String, Object, Array] },
92
92
  overlayProps: { type: Object }, // Allow passing down an object of props to the w-overlay component.
93
93
  persistent: { type: Boolean },
94
94
  noPosition: { type: Boolean }
@@ -97,7 +97,7 @@ export default {
97
97
  emits: ['input', 'update:modelValue', 'open', 'close'],
98
98
 
99
99
  data: () => ({
100
- showMenu: false,
100
+ menuVisible: false,
101
101
  hoveringActivator: false,
102
102
  hoveringMenu: false,
103
103
  // The menu computed top & left coordinates.
@@ -117,25 +117,29 @@ export default {
117
117
  },
118
118
 
119
119
  // DOM element to attach menu to.
120
+ // ! \ This computed uses the DOM - NO SSR (only trigger from beforeMount and later).
120
121
  detachToTarget () {
121
- let target = this.detachTo || '.w-app'
122
- if (target === true) target = '.w-app'
123
- else if (target && !['object', 'string'].includes(typeof target)) target = '.w-app'
122
+ const defaultTarget = '.w-app'
123
+
124
+ let target = this.detachTo || defaultTarget
125
+ if (target === true) target = defaultTarget
126
+ else if (target && !['object', 'string'].includes(typeof target)) target = defaultTarget
124
127
  else if (typeof target === 'object' && !target.nodeType) {
125
- target = '.w-app'
128
+ target = defaultTarget
126
129
  consoleWarn('Invalid node provided in w-menu `detach-to`. Falling back to .w-app.', this)
127
130
  }
128
131
  if (typeof target === 'string') target = document.querySelector(target)
129
132
 
130
133
  if (!target) {
131
- consoleWarn(`Unable to locate ${this.detachTo ? `target ${this.detachTo}` : '.w-app'}`, this)
132
- target = document.querySelector('.w-app')
134
+ consoleWarn(`Unable to locate ${this.detachTo ? `target ${this.detachTo}` : defaultTarget}`, this)
135
+ target = document.querySelector(defaultTarget)
133
136
  }
134
137
 
135
138
  return target
136
139
  },
137
140
 
138
141
  // DOM element that will receive the menu.
142
+ // ! \ This computed uses the DOM - NO SSR (only trigger from beforeMount and later).
139
143
  menuParentEl () {
140
144
  return this.detachToTarget
141
145
  },
@@ -165,27 +169,46 @@ export default {
165
169
  )
166
170
  },
167
171
 
172
+ menuClasses () {
173
+ return objectifyClasses(this.menuClass)
174
+ },
175
+
176
+ titleClasses () {
177
+ return objectifyClasses(this.titleClass)
178
+ },
179
+
180
+ contentClasses () {
181
+ return objectifyClasses(this.contentClass)
182
+ },
183
+
184
+ overlayClasses () {
185
+ return objectifyClasses(this.overlayClass)
186
+ },
187
+
168
188
  classes () {
169
189
  return {
170
190
  [this.color]: this.color,
171
191
  [`${this.bgColor}--bg`]: this.bgColor,
172
- [this.menuClass]: this.menuClass,
173
- [`w-menu--${this.position}`]: true,
174
- [`w-menu--align-${this.alignment}`]: this.alignment,
192
+ ...this.menuClasses,
193
+ [`w-menu--${this.position}`]: !this.noPosition,
194
+ [`w-menu--align-${this.alignment}`]: !this.noPosition && this.alignment,
175
195
  'w-menu--tile': this.tile,
176
196
  'w-menu--card': !this.custom,
177
197
  'w-menu--round': this.round,
198
+ 'w-menu--arrow': this.arrow,
178
199
  'w-menu--shadow': this.shadow,
179
200
  'w-menu--fixed': this.fixed
180
201
  }
181
202
  },
182
203
 
204
+ // The floating menu styles.
183
205
  styles () {
184
206
  return {
185
207
  zIndex: this.zIndex || this.zIndex === 0 || (this.overlay && !this.zIndex && 200) || null,
186
208
  top: (this.menuCoordinates.top && `${~~this.menuCoordinates.top}px`) || null,
187
209
  left: (this.menuCoordinates.left && `${~~this.menuCoordinates.left}px`) || null,
188
- minWidth: (this.minWidth && this.menuMinWidth) || null
210
+ minWidth: (this.minWidth && this.menuMinWidth) || null,
211
+ '--w-menu-bg-color': this.arrow && this.$waveui.colors[this.bgColor || 'white']
189
212
  }
190
213
  },
191
214
 
@@ -208,8 +231,10 @@ export default {
208
231
  }, 10)
209
232
  }
210
233
  }
211
-
212
- if ('ontouchstart' in window) handlers.click = this.toggleMenu
234
+ // Check the window exists: SSR-proof.
235
+ if (typeof window !== 'undefined' && 'ontouchstart' in window) {
236
+ handlers.click = this.toggleMenu
237
+ }
213
238
  }
214
239
  else handlers = { click: this.toggleMenu }
215
240
  return handlers
@@ -217,8 +242,9 @@ export default {
217
242
  },
218
243
 
219
244
  methods: {
245
+ // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
220
246
  toggleMenu (e) {
221
- let shouldShowMenu = this.showMenu
247
+ let shouldShowMenu = this.menuVisible
222
248
  if ('ontouchstart' in window && this.showOnHover && e.type === 'click') {
223
249
  shouldShowMenu = !shouldShowMenu
224
250
  }
@@ -234,11 +260,21 @@ export default {
234
260
 
235
261
  this.timeoutId = clearTimeout(this.timeoutId)
236
262
 
237
- if (shouldShowMenu) this.openMenu(e)
263
+ if (shouldShowMenu) {
264
+ this.$emit('update:modelValue', (this.menuVisible = true))
265
+ this.$emit('input', true)
266
+ this.$emit('open')
267
+
268
+ this.openMenu(e)
269
+ }
238
270
  else this.closeMenu()
239
271
  },
240
272
 
241
- openMenu (e) {
273
+ // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
274
+ async openMenu (e) {
275
+ this.menuVisible = true
276
+ await this.insertMenu()
277
+
242
278
  if (this.minWidth === 'activator') this.activatorWidth = this.activatorEl.offsetWidth
243
279
 
244
280
  if (!this.noPosition) this.computeMenuPosition(e)
@@ -247,10 +283,10 @@ export default {
247
283
  // if we don't postpone the Menu apparition it will start transition from a visible menu and
248
284
  // thus will not transition.
249
285
  this.timeoutId = setTimeout(() => {
250
- this.$emit('update:modelValue', (this.showMenu = true))
286
+ this.$emit('update:modelValue', true)
251
287
  this.$emit('input', true)
252
288
  this.$emit('open')
253
- }, 10)
289
+ }, 0)
254
290
 
255
291
  if (!this.persistent) document.addEventListener('mousedown', this.onOutsideMousedown)
256
292
  if (!this.noPosition) window.addEventListener('resize', this.onResize)
@@ -261,6 +297,7 @@ export default {
261
297
  * - click of activator
262
298
  * - hover outside if showOnHover
263
299
  * - click inside menu if hideOnMenuClick.
300
+ * / ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
264
301
  *
265
302
  * @param {Boolean} force when showOnHover is set to true, hovering menu should keep it open.
266
303
  * But if hideOnMenuClick is also set to true, this should force close
@@ -269,14 +306,14 @@ export default {
269
306
  async closeMenu (force = false) {
270
307
  // Might be already closed.
271
308
  // E.g. showOnHover & hideOnMenuClick: on click, force hide then mouseleave is also firing.
272
- if (!this.showMenu) return
309
+ if (!this.menuVisible) return
273
310
 
274
311
  if (this.showOnHover && !force) {
275
312
  await new Promise(resolve => setTimeout(resolve, 10))
276
313
  if (this.showOnHover && (this.hoveringMenu || this.hoveringActivator)) return
277
314
  }
278
315
 
279
- this.$emit('update:modelValue', (this.showMenu = false))
316
+ this.$emit('update:modelValue', (this.menuVisible = false))
280
317
  this.$emit('input', false)
281
318
  this.$emit('close')
282
319
  // Remove the mousedown listener if the menu got closed without a mousedown outside of the menu.
@@ -284,9 +321,10 @@ export default {
284
321
  window.removeEventListener('resize', this.onResize)
285
322
  },
286
323
 
324
+ // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
287
325
  onOutsideMousedown (e) {
288
326
  if (!this.menuEl.contains(e.target) && !this.activatorEl.contains(e.target)) {
289
- this.$emit('update:modelValue', (this.showMenu = false))
327
+ this.$emit('update:modelValue', (this.menuVisible = false))
290
328
  this.$emit('input', false)
291
329
  this.$emit('close')
292
330
  document.removeEventListener('mousedown', this.onOutsideMousedown)
@@ -299,6 +337,7 @@ export default {
299
337
  this.computeMenuPosition()
300
338
  },
301
339
 
340
+ // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
302
341
  getCoordinates (e) {
303
342
  // Get the activator coordinates relative to window.
304
343
  const { top, left, width, height } = (e ? e.target : this.activatorEl).getBoundingClientRect()
@@ -318,6 +357,7 @@ export default {
318
357
  return coords
319
358
  },
320
359
 
360
+ // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
321
361
  computeMenuPosition (e) {
322
362
  // Get the activator coordinates.
323
363
  let { top, left, width, height } = this.getCoordinates(e)
@@ -401,49 +441,53 @@ export default {
401
441
  this.menuEl.style.visibility = null
402
442
 
403
443
  // The menu coordinates are also recalculated while resizing window with open menu: keep the menu visible.
404
- if (!this.showMenu) this.menuEl.style.display = 'none'
444
+ if (!this.menuVisible) this.menuEl.style.display = 'none'
405
445
 
406
446
  this.menuCoordinates = { top, left }
407
447
  },
408
448
 
409
449
  insertMenu () {
410
- const wrapper = this.$refs.wrapper
411
- this.menuEl = this.$refs.menu.$el || this.$refs.menu
412
- // Unwrap the activator element.
413
- wrapper.parentNode.insertBefore(this.activatorEl, wrapper)
414
-
415
- // Unwrap the overlay.
416
- if (this.overlay) wrapper.parentNode.insertBefore(this.overlayEl, wrapper)
417
-
418
- // Move the menu elsewhere in the DOM.
419
- // wrapper.parentNode.insertBefore(this.menuEl, wrapper)
420
- this.detachToTarget.appendChild(this.menuEl)
450
+ return new Promise(resolve => {
451
+ this.$nextTick(() => {
452
+ this.menuEl = this.$refs.menu?.$el || this.$refs.menu
453
+
454
+ // Move the menu elsewhere in the DOM.
455
+ // wrapper.parentNode.insertBefore(this.menuEl, wrapper)
456
+ this.detachToTarget.appendChild(this.menuEl)
457
+ resolve()
458
+ })
459
+ })
421
460
  },
422
461
 
423
462
  removeMenu () {
424
- // el.remove() doesn't work on IE11.
425
- if (this.menuEl && this.menuEl.parentNode) this.menuEl.parentNode.removeChild(this.menuEl)
463
+ if (this.menuEl && this.menuEl.parentNode) this.menuEl.remove()
426
464
  }
427
465
  },
428
466
 
429
467
  mounted () {
430
- this.activatorEl = this.$refs.wrapper.firstElementChild
431
- this.overlayEl = this.overlay ? this.$refs.overlay.$el : null
432
- this.insertMenu()
468
+ const wrapper = this.$el
469
+ this.activatorEl = wrapper.firstElementChild
470
+ // Unwrap the activator element.
471
+ wrapper.parentNode.insertBefore(this.activatorEl, wrapper)
472
+
473
+ // Unwrap the overlay.
474
+ if (this.overlay) {
475
+ this.overlayEl = this.$refs.overlay?.$el
476
+ wrapper.parentNode.insertBefore(this.overlayEl, wrapper)
477
+ }
433
478
 
434
479
  if (this.modelValue) this.toggleMenu({ type: 'click', target: this.activatorEl })
435
480
  },
436
481
 
437
482
  beforeUnmount () {
438
483
  this.removeMenu()
439
- // el.remove() doesn't work on IE11.
440
- if (this.overlay && this.overlayEl.parentNode) this.overlayEl.parentNode.removeChild(this.overlayEl)
441
- if (this.activatorEl && this.activatorEl.parentNode) this.activatorEl.parentNode.removeChild(this.activatorEl)
484
+ if (this.overlay && this.overlayEl.parentNode) this.overlayEl.remove()
485
+ if (this.activatorEl && this.activatorEl.parentNode) this.activatorEl.remove()
442
486
  },
443
487
 
444
488
  watch: {
445
489
  modelValue (bool) {
446
- if (!!bool !== this.showMenu) this.toggleMenu({ type: 'click', target: this.activatorEl })
490
+ if (!!bool !== this.menuVisible) this.toggleMenu({ type: 'click', target: this.activatorEl })
447
491
  },
448
492
  detachTo () {
449
493
  this.removeMenu()
@@ -473,5 +517,14 @@ export default {
473
517
  &--bottom {margin-top: 3 * $base-increment;}
474
518
  &--left {margin-left: -3 * $base-increment;}
475
519
  &--right {margin-left: 3 * $base-increment;}
520
+
521
+ &--arrow {
522
+ &.w-menu--top {margin-top: -4 * $base-increment;}
523
+ &.w-menu--bottom {margin-top: 4 * $base-increment;}
524
+ &.w-menu--left {margin-left: -4 * $base-increment;}
525
+ &.w-menu--right {margin-left: 4 * $base-increment;}
526
+
527
+ @include triangle(var(--w-menu-bg-color), '.w-menu', 9px);
528
+ }
476
529
  }
477
530
  </style>
@@ -62,7 +62,7 @@ export default {
62
62
  z-index: 1000;
63
63
  pointer-events: none;
64
64
  width: 280px;
65
- overflow: auto;
65
+ overflow-x: hidden;
66
66
 
67
67
  &--left {right: auto;left: 0;}
68
68
 
@@ -5,7 +5,7 @@
5
5
  @mousedown="onMouseDown"
6
6
  @mouseover="onMouseOver"
7
7
  @mouseout="onMouseOut")
8
- colgroup
8
+ colgroup(ref="colgroup")
9
9
  col.w-table__col(
10
10
  v-for="(header, i) in headers"
11
11
  :key="i"
@@ -15,7 +15,7 @@
15
15
  th.w-table__header(
16
16
  v-for="(header, i) in headers"
17
17
  :key="i"
18
- @click="header.sortable !== false && sortTable(header)"
18
+ @click="!colResizing.dragging && header.sortable !== false && sortTable(header)"
19
19
  :class="headerClasses(header)")
20
20
  w-icon.w-table__header-sort(
21
21
  v-if="header.sortable !== false && header.align === 'right'"
@@ -44,7 +44,7 @@
44
44
  .w-table__loading-text
45
45
  slot(name="loading") Loading...
46
46
  //- No data.
47
- tr.no-data(v-if="!tableItems.length")
47
+ tr.no-data(v-else-if="!tableItems.length")
48
48
  td.w-table__cell.text-center(:colspan="headers.length")
49
49
  slot(name="no-data") No data to show.
50
50
 
@@ -58,12 +58,12 @@
58
58
  :item="item"
59
59
  :index="i + 1"
60
60
  :select="() => doSelectRow(item, i)"
61
- :classes="{ 'w-table__row': true, 'w-table__row--selected': selectedRowsByUid[item._uid] !== undefined, 'w-table__row--has-expanded': expandedRowsByUid[item._uid] !== undefined }")
61
+ :classes="{ 'w-table__row': true, 'w-table__row--selected': selectedRowsByUid[item._uid] !== undefined, 'w-table__row--expanded': expandedRowsByUid[item._uid] !== undefined }")
62
62
 
63
63
  tr.w-table__row(
64
64
  v-else
65
65
  @click="doSelectRow(item, i)"
66
- :class="{ 'w-table__row--selected': selectedRowsByUid[item._uid] !== undefined, 'w-table__row--has-expanded': expandedRowsByUid[item._uid] !== undefined }")
66
+ :class="{ 'w-table__row--selected': selectedRowsByUid[item._uid] !== undefined, 'w-table__row--expanded': expandedRowsByUid[item._uid] !== undefined }")
67
67
  template(v-for="(header, j) in headers")
68
68
  td.w-table__cell(
69
69
  v-if="$slots[`item-cell.${header.key}`] || $slots[`item-cell.${j + 1}`] || $slots['item-cell']"
@@ -106,13 +106,14 @@
106
106
  :class="{ 'w-table__col-resizer--hover': colResizing.hover === j, 'w-table__col-resizer--active': colResizing.columnIndex === j }")
107
107
 
108
108
  //- Expanded row.
109
- tr.w-table__row.w-table__row--expanded(v-if="expandedRowsByUid[item._uid]")
109
+ tr.w-table__row.w-table__row--expansion(v-if="expandedRowsByUid[item._uid]")
110
110
  td.w-table__cell(:colspan="headers.length")
111
- div(v-if="expandedRowsByUid[item._uid]")
112
- slot(name="expanded-row" :item="item" :index="i + 1")
113
- span.w-table__col-resizer(
114
- v-if="j < headers.length - 1 && resizableColumns"
115
- :class="{ 'w-table__col-resizer--hover': colResizing.hover === j, 'w-table__col-resizer--active': colResizing.columnIndex === j }")
111
+ w-transition-expand(y)
112
+ div(v-if="expandedRowsByUid[item._uid]")
113
+ slot(name="row-expansion" :item="item" :index="i + 1")
114
+ span.w-table__col-resizer(
115
+ v-if="i < headers.length - 1 && resizableColumns"
116
+ :class="{ 'w-table__col-resizer--hover': colResizing.hover === i, 'w-table__col-resizer--active': colResizing.columnIndex === j }")
116
117
  </template>
117
118
 
118
119
  <script>
@@ -122,6 +123,9 @@
122
123
 
123
124
  import { consoleError } from '../utils/console'
124
125
 
126
+ // When column resizing is on, this is the minimum cell width that we can resize to.
127
+ const minColumnWidth = 15
128
+
125
129
  export default {
126
130
  name: 'w-table',
127
131
  props: {
@@ -171,7 +175,7 @@ export default {
171
175
  resizableColumns: { type: Boolean }
172
176
  },
173
177
 
174
- emits: ['row-select', 'row-expand', 'row-click', 'update:sort', 'update:selected-rows', 'update:expanded-rows'],
178
+ emits: ['row-select', 'row-expand', 'row-click', 'update:sort', 'update:selected-rows', 'update:expanded-rows', 'column-resize'],
175
179
 
176
180
  data: () => ({
177
181
  activeSorting: [],
@@ -199,8 +203,7 @@ export default {
199
203
  },
200
204
 
201
205
  filteredItems () {
202
- if (typeof this.filter === 'function') return this.tableItems.filter(this.filter)
203
- return this.tableItems
206
+ return typeof this.filter === 'function' ? this.tableItems.filter(this.filter) : this.tableItems
204
207
  },
205
208
 
206
209
  sortedItems () {
@@ -404,15 +407,17 @@ export default {
404
407
  columnEl.style.width = colWidth + deltaX + 'px'
405
408
  nextColumnEl.style.width = nextColWidth - deltaX + 'px'
406
409
 
407
- // 2. Check if we went too far (the width applyed is different than the browser-computed one).
408
- const minWidthReached = deltaX < 0 && columnEl.offsetWidth > newColWidth
410
+ // 2. Check if we went too far (the width applied is different than the browser-computed one).
411
+ const minWidthReached = (deltaX < 0 && columnEl.offsetWidth > newColWidth) ||
412
+ columnEl.offsetWidth <= minColumnWidth
409
413
  const maxWidthReached = deltaX > 0 && nextColumnEl.offsetWidth > newNextColWidth
410
414
 
411
415
  // 3. If we went too far, correct the value of both cells widths.
412
416
  // Make sure we don't shrink enough to push other left cells.
413
417
  if (minWidthReached) {
414
- columnEl.style.width = columnEl.offsetWidth + 'px'
415
- nextColumnEl.style.width = maxWidth - columnEl.offsetWidth + 'px'
418
+ const newWidth = Math.max(columnEl.offsetWidth, minColumnWidth)
419
+ columnEl.style.width = newWidth + 'px'
420
+ nextColumnEl.style.width = maxWidth - newWidth + 'px'
416
421
  }
417
422
  // Make sure we don't grow enough to push other right cells.
418
423
  else if (maxWidthReached) {
@@ -421,19 +426,28 @@ export default {
421
426
  }
422
427
  },
423
428
 
424
- onResizerMouseUp (e) {
429
+ onResizerMouseUp () {
425
430
  // Remove listeners.
426
431
  document.removeEventListener('mousemove', this.onResizerMouseMove)
427
432
  document.removeEventListener('mouseup', this.onResizerMouseUp)
428
433
 
429
434
  // Reset all the variables (better for debugging).
430
- this.colResizing.dragging = false
431
- this.colResizing.columnIndex = null
432
- this.colResizing.startCursorX = null
433
- this.colResizing.columnEl = null
434
- this.colResizing.nextColumnEl = null
435
- this.colResizing.colWidth = null
436
- this.colResizing.nextColWidth = null
435
+ // setTimeout 0 to make sure the sorting is not applied when releasing the mouse on a header
436
+ // cell after resizing.
437
+ // (releasing the mouse on table header triggers a click event captured by the sorting feature)
438
+ setTimeout(() => {
439
+ // On Mouse up, emit an event containing all the new widths of the columns.
440
+ const widths = [...this.$refs.colgroup.childNodes].map(column => column.style?.width || column.offsetWidth)
441
+ this.$emit('column-resize', { index: this.colResizing.columnIndex, widths })
442
+
443
+ this.colResizing.dragging = false
444
+ this.colResizing.columnIndex = null
445
+ this.colResizing.startCursorX = null
446
+ this.colResizing.columnEl = null
447
+ this.colResizing.nextColumnEl = null
448
+ this.colResizing.colWidth = null
449
+ this.colResizing.nextColWidth = null
450
+ }, 0)
437
451
  }
438
452
  },
439
453
 
@@ -490,6 +504,10 @@ $tr-border-top: 1px;
490
504
  border-collapse: collapse;
491
505
  border: none;
492
506
 
507
+ &--resizable-cols {
508
+ table-layout: fixed; // Allow resizing beyond the cell minimum text width.
509
+ }
510
+
493
511
  &--resizing {
494
512
  &, * {cursor: col-resize;}
495
513
 
@@ -498,8 +516,11 @@ $tr-border-top: 1px;
498
516
 
499
517
  // Table headers.
500
518
  // ------------------------------------------------------
501
- &__header {
502
- padding: $base-increment;
519
+ &__header {padding: $base-increment;}
520
+ &__header--resizable {
521
+ overflow: hidden;
522
+ white-space: nowrap;
523
+ text-overflow: ellipsis;
503
524
  }
504
525
 
505
526
  &--fixed-header th {
@@ -596,7 +617,15 @@ $tr-border-top: 1px;
596
617
  &__header:first-child, &__cell:first-child {padding-left: 2 * $base-increment;}
597
618
  &__header:last-child, &__cell:last-child {padding-right: 2 * $base-increment;}
598
619
 
599
- &--resizable-cols &__cell {position: relative;}
620
+ &--resizable-cols &__cell {
621
+ position: relative;
622
+
623
+ &, & * {
624
+ overflow: hidden;
625
+ // white-space: nowrap; // If you only want the content cell on a single line.
626
+ text-overflow: ellipsis;
627
+ }
628
+ }
600
629
 
601
630
  .no-data &__cell {
602
631
  background-color: rgba(255, 255, 255, 0.2);
@@ -170,7 +170,8 @@ export default {
170
170
  // Updates the slider position.
171
171
  updateSlider (domLookup = true) {
172
172
  if (domLookup) {
173
- this.activeTabEl = this.$refs['tabs-bar'].querySelector('.w-tabs__bar-item--active')
173
+ const ref = this.$refs['tabs-bar']
174
+ this.activeTabEl = ref && ref.querySelector('.w-tabs__bar-item--active')
174
175
  }
175
176
 
176
177
  if (!this.fillBar && this.activeTabEl) {
@@ -116,7 +116,7 @@ export default {
116
116
  return listeners
117
117
  },
118
118
  hasValue () {
119
- return this.inputValue
119
+ return this.inputValue || this.inputValue === 0
120
120
  },
121
121
  hasLabel () {
122
122
  return this.label || this.$slots.default