wave-ui 1.61.0 → 1.63.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": "1.61.0",
3
+ "version": "1.63.0",
4
4
  "description": "An emerging UI framework for Vue.js (2 & 3) with only the bright side. :sunny:",
5
5
  "author": "Antoni Andre <antoniandre.web@gmail.com>",
6
6
  "homepage": "https://antoniandre.github.io/wave-ui",
@@ -28,6 +28,7 @@ export { default as WProgress } from './w-progress.vue'
28
28
  export { default as WRadio } from './w-radio.vue'
29
29
  export { default as WRadios } from './w-radios.vue'
30
30
  export { default as WRating } from './w-rating.vue'
31
+ export { default as WScrollbar } from './w-scrollbar.vue'
31
32
  export { default as WSelect } from './w-select.vue'
32
33
  export { default as WSlider } from './w-slider.vue'
33
34
  export { default as WSpinner } from './w-spinner.vue'
@@ -27,6 +27,7 @@ export default {
27
27
 
28
28
  data: () => ({
29
29
  el: {
30
+ savedState: false,
30
31
  originalStyles: '',
31
32
  width: 0,
32
33
  height: 0,
@@ -59,7 +60,7 @@ export default {
59
60
  beforeAppear (el) {
60
61
  // Only save original state once before a 'clean' transition start.
61
62
  // Not when clicking very fast and mixing states order.
62
- if (this.cleanTransitionCycle) this.saveOriginalStyles(el)
63
+ if (this.cleanTransitionCycle) this.saveOriginalInlineStyles(el)
63
64
  this.cleanTransitionCycle = false
64
65
  },
65
66
  appear (el, done) {
@@ -76,7 +77,7 @@ export default {
76
77
  beforeEnter (el) {
77
78
  // Only save original state once before a 'clean' transition start.
78
79
  // Not when clicking very fast and mixing states order.
79
- if (this.cleanTransitionCycle) this.saveOriginalStyles(el)
80
+ if (this.cleanTransitionCycle) this.saveOriginalInlineStyles(el)
80
81
  this.cleanTransitionCycle = false
81
82
  },
82
83
  enter (el, done) {
@@ -91,6 +92,9 @@ export default {
91
92
  this.cleanTransitionCycle = false
92
93
  },
93
94
  beforeLeave (el) {
95
+ // When starting with an open item.
96
+ if (!this.el.savedState) this.saveComputedStyles(el)
97
+
94
98
  this.beforeHide(el)
95
99
  this.cleanTransitionCycle = false
96
100
  },
@@ -102,6 +106,9 @@ export default {
102
106
  afterLeave (el) {
103
107
  this.applyOriginalStyles(el)
104
108
  this.cleanTransitionCycle = true
109
+ // Reset for recomputing the next time we start the transition from an open state.
110
+ // In case there might be some changed styles from last closing.
111
+ this.el.savedState = false
105
112
  },
106
113
 
107
114
  applyHideStyles (el) {
@@ -151,11 +158,25 @@ export default {
151
158
  applyOriginalStyles (el) {
152
159
  el.style.cssText = this.el.originalStyles
153
160
  },
154
- saveOriginalStyles (el) {
155
- // Keep the original styles to restore them after transition.
161
+ saveOriginalInlineStyles (el) {
162
+ // Keep any original inline styles to restore them after transition.
156
163
  this.el.originalStyles = el.style.cssText
157
164
  },
158
165
  show (el, done) {
166
+ this.saveComputedStyles(el)
167
+ this.applyHideStyles(el)
168
+
169
+ setTimeout(() => this.applyShowStyles(el), 20)
170
+ setTimeout(done, this.duration)
171
+ },
172
+ beforeHide (el) {
173
+ this.applyShowStyles(el)
174
+ },
175
+ hide (el, done) {
176
+ setTimeout(() => this.applyHideStyles(el), 20)
177
+ setTimeout(done, this.duration)
178
+ },
179
+ saveComputedStyles (el) {
159
180
  const computedStyles = window.getComputedStyle(el, null)
160
181
 
161
182
  // Save the width & height then set them to 0 as the animation starting point.
@@ -177,17 +198,7 @@ export default {
177
198
  this.el.borderTopWidth = computedStyles.getPropertyValue('borderTopWidth')
178
199
  this.el.borderBottomWidth = computedStyles.getPropertyValue('borderBottomWidth')
179
200
  }
180
- this.applyHideStyles(el)
181
-
182
- setTimeout(() => this.applyShowStyles(el), 20)
183
- setTimeout(done, this.duration)
184
- },
185
- beforeHide (el) {
186
- this.applyShowStyles(el)
187
- },
188
- hide (el, done) {
189
- setTimeout(() => this.applyHideStyles(el), 20)
190
- setTimeout(done, this.duration)
201
+ this.el.savedState = true
191
202
  }
192
203
  }
193
204
  }
@@ -2,7 +2,9 @@
2
2
  .w-confirm
3
3
  w-menu(v-model="showPopup" v-bind="wMenuProps")
4
4
  template(#activator="{ on }")
5
- w-button.w-confirm__button(v-on="{ ...$listeners, ...on }" v-bind="buttonProps")
5
+ w-button.w-confirm__button(
6
+ v-on="{ ...$listeners, ...(disablePrompt ? {} : on) }"
7
+ v-bind="buttonProps")
6
8
  slot
7
9
  w-flex(:column="!inline" align-center)
8
10
  div
@@ -32,6 +34,7 @@ export default {
32
34
  bgColor: { type: String },
33
35
  color: { type: String },
34
36
  icon: { type: String },
37
+ disablePrompt: { type: Boolean }, // If true, the confirm button acts like a simple w-button.
35
38
  mainButton: { type: Object }, // Allow passing down an object of props to the w-button component.
36
39
  question: { type: String, default: 'Are you sure?' },
37
40
 
@@ -302,7 +302,7 @@ export default {
302
302
  // eslint-disable-next-line vue/custom-event-name-casing
303
303
  else if (e.keyCode === 27) this.$emit('keydown:escape')
304
304
  // On arrow keys press, navigate to prev/next item.
305
- else if (this.arrowsNavigation) {
305
+ else if (this.arrowsNavigation && [38, 40].includes(e.keyCode)) {
306
306
  e.preventDefault()
307
307
  if (e.keyCode === 38) this.focusPrevNextItem(li._index, false)
308
308
  if (e.keyCode === 40) this.focusPrevNextItem(li._index, true)
@@ -407,7 +407,10 @@ export default {
407
407
  if (!this.isMultipleSelect) this.listItems.forEach(item => (item._selected = false))
408
408
 
409
409
  this.checkSelection(selection) // Create an array with the selected values.
410
- .forEach(val => (this.listItems.find(item => item._value === val)._selected = true))
410
+ .forEach(val => {
411
+ const foundItem = this.listItems.find(item => item._value === val)
412
+ if (foundItem) foundItem._selected = true
413
+ })
411
414
  }
412
415
  },
413
416
 
@@ -63,12 +63,12 @@ export default {
63
63
  .w-notification-manager {
64
64
  position: fixed;
65
65
  top: 0;
66
- bottom: 0;
66
+ max-height: 100%;
67
67
  right: 0;
68
68
  z-index: 1000;
69
- pointer-events: none;
70
69
  width: 280px;
71
70
  overflow-x: hidden;
71
+ overflow-y: auto;
72
72
 
73
73
  &--left {right: auto;left: 0;}
74
74
 
@@ -79,7 +79,6 @@ export default {
79
79
  right: 0;
80
80
  margin: 8px;
81
81
  flex-grow: 1;
82
- pointer-events: all;
83
82
  }
84
83
  }
85
84
  </style>
@@ -0,0 +1,24 @@
1
+ <template lang="pug">
2
+ .w-scrollbar
3
+ </template>
4
+
5
+ <script>
6
+ export default {
7
+ name: 'w-scrollbar',
8
+ props: {
9
+
10
+ },
11
+
12
+ emits: [],
13
+
14
+ data: () => ({
15
+
16
+ })
17
+ }
18
+ </script>
19
+
20
+ <style lang="scss">
21
+ .w-scrollbar {
22
+
23
+ }
24
+ </style>
@@ -60,7 +60,7 @@ component(
60
60
  v-for="(val, i) in (inputValue.length ? inputValue : [{}])"
61
61
  :key="i"
62
62
  type="hidden"
63
- :value="val.value || ''"
63
+ :value="val.value === undefined ? '' : val.value.toString()"
64
64
  :name="inputName + (multiple ? '[]' : '')")
65
65
  template(v-if="labelPosition === 'inside' && showLabelInside")
66
66
  label.w-select__label.w-select__label--inside.w-form-el-shakable(
@@ -299,7 +299,7 @@ export default {
299
299
  // Also accept objects if returnObject is true.
300
300
  // In any case, always end up with an array.
301
301
  checkSelection (items) {
302
- items = Array.isArray(items) ? items : (items ? [items] : [])
302
+ items = Array.isArray(items) ? items : (items !== undefined ? [items] : [])
303
303
  // `selectItems` items always have a value.
304
304
  const allValues = this.selectItems.map(item => item.value)
305
305
 
@@ -424,8 +424,10 @@ export default {
424
424
  &__selection {
425
425
  width: 100%;
426
426
  height: 100%;
427
- font-size: inherit;
427
+ min-height: inherit;
428
+ font: inherit;
428
429
  color: inherit;
430
+ text-align: inherit;
429
431
  background: none;
430
432
  border: none;
431
433
  outline: none;
@@ -522,12 +524,15 @@ export default {
522
524
  position: absolute;
523
525
  top: 50%;
524
526
  left: 0;
525
- // Use margin instead of padding as the scale transformation bellow decreases the real padding
527
+ right: 0;
528
+ // Use margin instead of padding as the scale transformation below decreases the real padding
526
529
  // size and misaligns the label.
527
530
  margin-left: 2 * $base-increment;
528
531
  transform: translateY(-50%);
529
532
  pointer-events: none;
530
533
 
534
+ .w-select--inner-icon-right & {padding-right: 22px;}
535
+
531
536
  .w-select--no-padding & {
532
537
  left: 0;
533
538
  margin-left: 0;
@@ -38,7 +38,7 @@ component(
38
38
  v-if="loading"
39
39
  circle
40
40
  color="inherit"
41
- v-bind="typeof loading === 'number' ? { 'model-value': loading } : {}")
41
+ v-bind="typeof loading === 'number' ? { value: loading } : {}")
42
42
  slot(v-else name="thumb")
43
43
  template(v-if="hasLabel && !labelOnLeft")
44
44
  label.w-switch__label.w-switch__label--right.w-form-el-shakable(
@@ -128,12 +128,34 @@
128
128
  slot(name="extra-row")
129
129
 
130
130
  //- Table footer.
131
- tfoot.w-table__footer(v-if="$slots.footer || $slots['footer-row']")
131
+ tfoot.w-table__footer(v-if="$slots.footer || $slots['footer-row'] || pagination")
132
132
  slot(v-if="$slots['footer-row']" name="footer-row")
133
- tr.w-table__row(v-else)
133
+ tr.w-table__row(v-else-if="$slots.footer")
134
134
  td.w-table__cell(:colspan="headers.length")
135
135
  slot(name="footer")
136
- //- .pagination
136
+ tr.w-table__row.w-table__pagination-wrap(v-if="pagination && paginationConfig")
137
+ td.w-table__cell(:colspan="headers.length")
138
+ .w-table__pagination
139
+ w-select.pagination-number.pagination-number--items-per-page(
140
+ v-if="paginationConfig.itemsPerPageOptions"
141
+ v-model="paginationConfig.itemsPerPage"
142
+ :items="paginationConfig.itemsPerPageOptions"
143
+ label-position="left"
144
+ label="Items per page"
145
+ label-color="inherit")
146
+ span.pagination-number.pagination-number--results.
147
+ {{ paginationConfig.start }}-{{ paginationConfig.end }} of {{ paginationConfig.total }}
148
+ .pagination-arrows
149
+ w-button.pagination-arrow.pagination-arrow--prev(
150
+ @click="paginationConfig.page--"
151
+ icon="wi-chevron-left"
152
+ text
153
+ lg)
154
+ w-button.pagination-arrow.pagination-arrow--next(
155
+ @click="paginationConfig.page++"
156
+ icon="wi-chevron-right"
157
+ text
158
+ lg)
137
159
  </template>
138
160
 
139
161
  <script>
@@ -189,13 +211,28 @@ export default {
189
211
 
190
212
  forceSelection: { type: Boolean },
191
213
 
192
- // Useful to select or expand a row, and even after a filter, the same row will stay selected or exanded.
214
+ // Useful to select or expand a row, and even after a filter, the same row will stay selected or expanded.
193
215
  uidKey: { type: String, default: 'id' },
194
216
 
195
217
  filter: { type: Function },
196
218
  sortFunction: { type: Function },
197
219
  mobileBreakpoint: { type: Number, default: 0 },
198
- resizableColumns: { type: Boolean }
220
+ resizableColumns: { type: Boolean },
221
+
222
+ pagination: {
223
+ type: [Boolean, Object, String],
224
+ validator: object => {
225
+ if (!object) return true // Accept any falsy value.
226
+ else if (typeof object === 'object' && (!object.itemsPerPage || (object.page && isNaN(object.page)))) {
227
+ consoleError(
228
+ 'Wrong pagination config received in the w-table\'s `pagination` prop (received: `' + JSON.stringify(object) + '`). ' +
229
+ '\nExpected object: { itemsPerPage: Integer, page: Integer } or { itemsPerPage: Integer, start: Integer }.'
230
+ )
231
+ return false
232
+ }
233
+ return true
234
+ }
235
+ }
199
236
  },
200
237
 
201
238
  emits: [
@@ -222,7 +259,8 @@ export default {
222
259
  nextColWidth: null,
223
260
  columnEl: null,
224
261
  nextColumnEl: null
225
- }
262
+ },
263
+ paginationConfig: {}
226
264
  }),
227
265
 
228
266
  computed: {
@@ -490,6 +528,20 @@ export default {
490
528
  this.colResizing.colWidth = null
491
529
  this.colResizing.nextColWidth = null
492
530
  }, 0)
531
+ },
532
+
533
+ updatePaginationConfig () {
534
+ const itemsPerPage = this.pagination?.itemsPerPage || 10
535
+ const total = this.pagination?.total || this.items.length
536
+ const page = this.pagination?.page || 1
537
+ this.paginationConfig = {
538
+ itemsPerPage,
539
+ itemsPerPageOptions: this.pagination?.itemsPerPageOptions || [{ label: '10', value: 10 }, { label: '100', value: 100 }, { label: 'All', value: 0 }],
540
+ page,
541
+ start: this.pagination?.start || 1,
542
+ end: total >= (itemsPerPage * page) ? (itemsPerPage * page) : (total % (itemsPerPage * page)),
543
+ total
544
+ }
493
545
  }
494
546
  },
495
547
 
@@ -499,6 +551,8 @@ export default {
499
551
 
500
552
  if ((this.expandedRows || []).length) this.expandedRowsInternal = this.expandedRows
501
553
  if ((this.selectedRows || []).length) this.selectedRowsInternal = this.selectedRows
554
+
555
+ if (this.pagination) this.updatePaginationConfig()
502
556
  },
503
557
 
504
558
  watch: {
@@ -739,14 +793,45 @@ $tr-border-top: 1px;
739
793
  border-bottom: $border;
740
794
  }
741
795
  }
796
+
797
+ &__pagination {
798
+ display: flex;
799
+ align-items: center;
800
+ justify-content: flex-end;
801
+ padding-top: $base-increment;
802
+ padding-bottom: $base-increment;
803
+
804
+ .pagination-number--items-per-page {
805
+ margin-right: 6 * $base-increment;
806
+ flex-grow: 0;
807
+ text-align: right;
808
+ }
809
+ .pagination-number--of {
810
+ margin-left: $base-increment;
811
+ margin-right: $base-increment;
812
+ }
813
+ .w-select__selection {max-width: 60px;}
814
+
815
+ .pagination-arrows {
816
+ margin-left: 6 * $base-increment;
817
+ }
818
+ }
742
819
  }
743
820
 
744
821
  // Mobile layout.
745
822
  .w-table--mobile {
823
+ display: flex;
824
+
746
825
  thead {display: none;}
747
- td {display: block;}
826
+ tbody {
827
+ display: flex;
828
+ flex-direction: column;
829
+ flex-grow: 1;
830
+ }
748
831
  tr {
749
- display: block;
832
+ display: flex;
833
+ flex-direction: column;
834
+ flex-grow: 1;
750
835
  padding-top: $base-increment;
751
836
  padding-bottom: $base-increment;
752
837
  }
@@ -4,22 +4,27 @@ ul.w-tree(:class="classes")
4
4
  v-for="(item, i) in currentDepthItems"
5
5
  :key="i"
6
6
  :class="itemClasses(item)")
7
- .w-tree__item-label(
8
- @click="!disabled && onLabelClick(item, $event)"
9
- @keydown="!disabled && onLabelKeydown(item, $event)"
10
- :tabindex="!disabled && (item.children || item.branch || selectable) && !(unexpandableEmpty && !item.children) ? 0 : null")
7
+ //- The keys `route` & `disabled` are always present in any currentDepthItems.
8
+ component.w-tree__item-label(
9
+ :is="!disabled && !item.disabled && item.route ? (!$router || hasExternalLink(item) ? 'a' : 'router-link') : 'div'"
10
+ v-bind="item.route && { [!$router || hasExternalLink(item) ? 'href' : 'to']: item.route }"
11
+ @click="!disabled && !item.disabled && onLabelClick(item, $event)"
12
+ @keydown="!disabled && !item.disabled && onLabelKeydown(item, $event)"
13
+ :tabindex="!disabled && !item.disabled && (item.children || item.branch || selectable) && !(unexpandableEmpty && !item.children) ? 0 : null")
14
+ //- @click.stop to not follow link if item is a link.
11
15
  w-button.w-tree__item-expand(
12
16
  v-if="(item.children || item.branch) && ((expandOpenIcon && item.open) || expandIcon) && !(unexpandableEmpty && !item.children)"
17
+ @click.stop="!disabled && !item.disabled && onLabelClick(item, $event)"
13
18
  color="inherit"
14
19
  :icon="(item.open && expandOpenIcon) || expandIcon"
15
20
  :icon-props="{ rotate90a: !item.open }"
16
21
  :tabindex="-1"
17
- :disabled="disabled"
22
+ :disabled="disabled || item.disabled"
18
23
  text
19
24
  sm)
20
- slot(name="item-label" :item="item.originalItem" :depth="depth" :open="item.open")
21
- w-icon(v-if="itemIcon(item)" class="w-tree__item-icon") {{ itemIcon(item) }}
22
- span {{ item.label }}
25
+ slot(name="item" :item="item.originalItem" :depth="depth" :open="item.open")
26
+ w-icon(v-if="itemIcon(item)" class="w-tree__item-icon" :color="item.originalItem[itemIconColorKey] || iconColor") {{ itemIcon(item) }}
27
+ span(v-html="item.label")
23
28
  span.ml1(v-if="counts && (item.children || item.branch)").
24
29
  ({{ item.originalItem.children ? item.originalItem.children.length : 0 }})
25
30
  component(
@@ -39,16 +44,15 @@ ul.w-tree(:class="classes")
39
44
  @click="$emit('click', $event)"
40
45
  @select="$emit('select', $event)"
41
46
  @input="$emit('input', $event)")
42
- template(#item-label="{ item, depth, open }")
43
- slot(name="item-label" :item="item" :depth="depth" :open="open")
47
+ template(#item="{ item, depth, open }")
48
+ slot(name="item" :item="item" :depth="depth" :open="open")
44
49
  </template>
45
50
 
46
51
  <script>
52
+ import { consoleWarn } from '../utils/console'
47
53
  /**
48
- * @todo things to support:
49
- * - items routes
50
- * - icon per item
51
- * - left border?
54
+ * @todo:
55
+ * - option to add a left border.
52
56
  **/
53
57
 
54
58
  export default {
@@ -70,8 +74,14 @@ export default {
70
74
  noTransition: { type: Boolean },
71
75
  selectable: { type: Boolean },
72
76
  // By default it only reacts to items count change (added or deleted items) not property of items change.
73
- depthReactivity: { type: Boolean },
74
- counts: { type: Boolean }
77
+ deepReactivity: { type: Boolean },
78
+ counts: { type: Boolean },
79
+ itemIconKey: { type: String, default: 'icon' }, // Support a different icon per item.
80
+ iconColor: { type: String }, // Applies a color on all the label item icons.
81
+ itemIconColorKey: { type: String, default: 'iconColor' }, // Applies a specific color on each label item icons.
82
+ itemRouteKey: { type: String, default: 'route' }, // Uses a router link if the item has the `route` key.
83
+ itemDisabledKey: { type: String, default: 'disabled' }, // Disables the item click and selection.
84
+ itemOpenKey: { type: String, default: 'open' } // Open the item by default.
75
85
  },
76
86
 
77
87
  emits: ['input', 'before-open', 'open', 'before-close', 'close', 'click', 'select'],
@@ -97,6 +107,12 @@ export default {
97
107
  updateCurrentDepthTree (items, oldItems = []) {
98
108
  this.currentDepthItems = []
99
109
 
110
+ if (!Array.isArray(items) && typeof items !== 'object') {
111
+ return consoleWarn(`[w-tree] the tree items must be of type array or object, ${typeof items} received.`, items)
112
+ }
113
+
114
+ if (!Array.isArray(items)) items = [items]
115
+
100
116
  items.forEach((item, i) => {
101
117
  this.currentDepthItems.push({
102
118
  originalItem: item, // Store the original item to return it on event emits.
@@ -104,8 +120,10 @@ export default {
104
120
  label: item.label,
105
121
  children: !!item.children, // The children tree remains available in originalItem.
106
122
  branch: item.branch,
123
+ route: item[this.itemRouteKey],
124
+ disabled: item[this.itemDisabledKey],
107
125
  depth: this.depth,
108
- open: oldItems[i]?.open || false
126
+ open: !!(oldItems[i]?.open || this.expandAll || item[this.itemOpenKey])
109
127
  })
110
128
  })
111
129
  },
@@ -132,6 +150,9 @@ export default {
132
150
  },
133
151
 
134
152
  onLabelClick (item, e) {
153
+ const route = item[this.itemRouteKey]
154
+ if (route && this.$router && !this.hasExternalLink(item)) e.preventDefault()
155
+
135
156
  this.$emit('click', { item: item.originalItem, depth: this.depth, e })
136
157
  if (item.children || (item.branch && !this.unexpandableEmpty)) this.expandDepth(item)
137
158
 
@@ -183,6 +204,7 @@ export default {
183
204
  * @param {String} selector any valid DOM selector to match the siblings.
184
205
  */
185
206
  getPreviousSibling (node, selector) {
207
+ // eslint-disable-next-line no-unmodified-loop-condition
186
208
  while (selector && (node = node.previousElementSibling)) {
187
209
  if (node.matches(selector)) return node
188
210
  }
@@ -196,6 +218,7 @@ export default {
196
218
  * @param {String} selector any valid DOM selector to match the siblings.
197
219
  */
198
220
  getNextSibling (node, selector) {
221
+ // eslint-disable-next-line no-unmodified-loop-condition
199
222
  while (selector && (node = node.nextElementSibling)) {
200
223
  if (node.matches(selector)) return node
201
224
  }
@@ -208,15 +231,20 @@ export default {
208
231
 
209
232
  itemIcon (item) {
210
233
  return (
211
- item.originalItem.icon ||
234
+ item.originalItem[this.itemIconKey] ||
212
235
  (!item.children && !item.branch && this.leafIcon) ||
213
236
  ((item.children || item.branch) && ((item.open && this.branchOpenIcon) || this.branchIcon))
214
237
  )
215
238
  },
216
239
 
240
+ hasExternalLink (item) {
241
+ return /^(https?:)?\/\/|mailto:|tel:/.test(item[this.itemRouteKey])
242
+ },
243
+
217
244
  itemClasses (item) {
218
245
  return {
219
246
  [item.children || item.branch ? 'w-tree__item--branch' : 'w-tree__item--leaf']: true,
247
+ 'w-tree__item--disabled': item[this.itemDisabledKey],
220
248
  'w-tree__item--empty': item.branch && !item.children,
221
249
  'w-tree__item--unexpandable': item.branch && !item.children && this.unexpandableEmpty
222
250
  }
@@ -230,7 +258,7 @@ export default {
230
258
  // The open property of each item has to be retained from this.currentDepthItems in order to stay
231
259
  // in the same state after DOM repaint.
232
260
  items => this.updateCurrentDepthTree(items, this.currentDepthItems),
233
- { deep: !!this.depthReactivity } // Deep watching is more resource consuming. Only enable on user demand.
261
+ { deep: !!this.deepReactivity } // Deep watching is more resource consuming. Only enable on user demand.
234
262
  )
235
263
  },
236
264
 
@@ -259,6 +287,7 @@ $expand-icon-size: 20px;
259
287
  position: relative;
260
288
  display: inline-flex;
261
289
  align-items: center;
290
+ user-select: none;
262
291
 
263
292
  &:before {
264
293
  content: '';
@@ -269,16 +298,24 @@ $expand-icon-size: 20px;
269
298
  right: - $base-increment - 2px;
270
299
  border-radius: $border-radius;
271
300
  }
301
+ &:hover:before {background-color: rgba($primary, 0.05);}
272
302
  &:focus:before {background-color: rgba($primary, 0.1);}
273
303
  }
274
304
  &__item--leaf &__item-label:before {
275
305
  left: - $base-increment;
276
306
  right: - $base-increment;
277
307
  }
308
+ &__item--disabled &__item-label {opacity: 0.5;}
309
+ &__item--disabled &__item-label:before {display: none;}
278
310
 
279
311
  &__item-expand {margin-right: 2px;}
280
312
 
281
313
  &__item--branch > &__item-label {cursor: pointer;}
314
+ &__item--disabled > &__item-label {
315
+ color: $disabled-color;
316
+ cursor: not-allowed;
317
+ -webkit-tap-highlight-color: transparent;
318
+ }
282
319
  &__item--unexpandable > &__item-label {
283
320
  margin-left: $expand-icon-size + 2px;
284
321
  cursor: auto;