wave-ui 3.3.0 → 3.4.1

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": "3.3.0",
3
+ "version": "3.4.1",
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,7 +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
+ export { default as WScrollable } from './w-scrollable.vue'
32
32
  export { default as WSelect } from './w-select.vue'
33
33
  export { default as WSlider } from './w-slider.vue'
34
34
  export { default as WSpinner } from './w-spinner.vue'
@@ -0,0 +1,243 @@
1
+ <template lang="pug">
2
+ .w-scrollable(
3
+ ref="scrollable"
4
+ @mouseenter="onMouseEnter"
5
+ @mouseleave="onMouseLeave"
6
+ @mousewheel="onMouseWheel"
7
+ :class="scrollableClasses"
8
+ v-bind="$attrs"
9
+ :style="scrollableStyles")
10
+ slot
11
+ .w-scrollbar(ref="track" @mousedown="onTrackMouseDown" :class="scrollbarClasses")
12
+ .w-scrollbar__thumb(ref="thumb" :style="thumbStyles")
13
+ </template>
14
+
15
+ <script>
16
+ const domProps = {
17
+ h: {
18
+ horizOrVert: 'horizontal',
19
+ topOrLeft: 'left',
20
+ widthOrHeight: 'width',
21
+ offsetWidthOrHeight: 'offsetWidth',
22
+ maxWidthOrHeight: 'max-width',
23
+ scrollWidthOrHeight: 'scrollWidth',
24
+ clientXorY: 'clientX',
25
+ deltaXorY: 'deltaX',
26
+ scrollTopOrLeft: 'scrollLeft'
27
+ },
28
+ v: {
29
+ horizOrVert: 'vertical',
30
+ topOrLeft: 'top',
31
+ widthOrHeight: 'height',
32
+ offsetWidthOrHeight: 'offsetHeight',
33
+ maxWidthOrHeight: 'max-height',
34
+ scrollWidthOrHeight: 'scrollHeight',
35
+ clientXorY: 'clientY',
36
+ deltaXorY: 'deltaY',
37
+ scrollTopOrLeft: 'scrollTop'
38
+ }
39
+ }
40
+
41
+ export default {
42
+ name: 'w-scrollable',
43
+ props: {
44
+ color: { type: String, default: 'primary' },
45
+ bgColor: { type: String },
46
+ width: { type: [Number, String] },
47
+ height: { type: [Number, String] }
48
+ },
49
+
50
+ emits: [],
51
+
52
+ data: () => ({
53
+ mounted: false,
54
+ scrollable: {
55
+ top: null,
56
+ left: null,
57
+ hovered: false
58
+ },
59
+ scrollValuePercent: 0
60
+ }),
61
+
62
+ computed: {
63
+ isHorizontal () {
64
+ if (!this.mounted) return false
65
+ console.log('💂‍♂️', this.$refs.scrollable?.scrollWidth, this.$refs.scrollable?.offsetWidth)
66
+ return (this.width && !this.height) || (this.$refs.scrollable?.scrollWidth > this.$refs.scrollable?.offsetWidth)
67
+ },
68
+
69
+ m () { // m = shorthand for map of DOM properties.
70
+ return domProps[this.isHorizontal ? 'h' : 'v']
71
+ },
72
+
73
+ scrollableClasses () {
74
+ return {
75
+ [`w-scrollable--${this.m.horizOrVert}`]: true
76
+ }
77
+ },
78
+
79
+ scrollbarClasses () {
80
+ return {
81
+ [`w-scrollbar--${this.m.horizOrVert}`]: true
82
+ }
83
+ },
84
+
85
+ thumbSizePercent () {
86
+ if (!this.mounted) return 0
87
+ console.log('😒', this[this.m.widthOrHeight], this.$refs.scrollable[[this.m.offsetWidthOrHeight]])
88
+ const widthOrHeight = this[this.m.widthOrHeight] ?? this.$refs.scrollable[[this.m.offsetWidthOrHeight]]
89
+ // if (widthOrHeight === undefined) widthOrHeight = this.$refs.scrollable.offsetWidthOrHeight
90
+ return (widthOrHeight * 100 / this.$refs.scrollable?.[this.m.scrollWidthOrHeight]) || 0
91
+ },
92
+
93
+ scrollableStyles () {
94
+ return {
95
+ [this.m.maxWidthOrHeight]: `${this[this.m.widthOrHeight]}px`
96
+ }
97
+ },
98
+
99
+ thumbStyles () {
100
+ let topOrLeftValue = this.scrollValuePercent
101
+ topOrLeftValue = Math.max(0, Math.min(topOrLeftValue, 100 - this.thumbSizePercent))
102
+ return {
103
+ [this.m.widthOrHeight]: `${this.thumbSizePercent}%`,
104
+ [this.m.topOrLeft]: `${topOrLeftValue}%`
105
+ }
106
+ }
107
+ },
108
+
109
+ methods: {
110
+ onTrackMouseDown (e) {
111
+ if (this.isDisabled || this.isReadonly) return
112
+ // On touch screen don't listen for both touchstart & mousedown.
113
+ if ('ontouchstart' in window && e.type === 'mousedown') return
114
+
115
+ const { top, left, width, height } = this.$refs.track.getBoundingClientRect()
116
+ if (this.isHorizontal) {
117
+ this.$refs.track.width = width
118
+ this.$refs.track.left = left
119
+ }
120
+ else {
121
+ this.$refs.track.height = height
122
+ this.$refs.track.top = top
123
+ }
124
+ this.dragging = true
125
+
126
+ this.computeScroll(e.type === 'touchstart' ? e.touches[0][this.m.clientXorY] : e[this.m.clientXorY])
127
+ this.scroll()
128
+
129
+ document.addEventListener(e.type === 'touchstart' ? 'touchmove' : 'mousemove', this.onDrag)
130
+ document.addEventListener(e.type === 'touchstart' ? 'touchend' : 'mouseup', this.onMouseUp, { once: true })
131
+ },
132
+
133
+ onDrag (e) {
134
+ this.computeScroll((e.type === 'touchmove' ? e.touches[0][this.m.clientXorY] : e[this.m.clientXorY]))
135
+ this.scroll()
136
+ },
137
+
138
+ onMouseUp (e) {
139
+ this.dragging = false
140
+ document.removeEventListener(e.type === 'touchend' ? 'touchmove' : 'mousemove', this.onDrag)
141
+ if (this.$refs.thumb) this.$refs.thumb.focus()
142
+ },
143
+
144
+ onMouseEnter () {
145
+ this.scrollable.hovered = true
146
+ },
147
+
148
+ onMouseLeave () {
149
+ this.scrollable.hovered = false
150
+ },
151
+
152
+ onMouseWheel (e) {
153
+ if (!this.scrollable.hovered) return // Only scroll a w-scrollable element that is being hovered.
154
+
155
+ // When scrolling beyond limits, release the mousewheel and scroll the parent.
156
+ if (this.scrollValuePercent <= 0 && e[this.m.deltaXorY] < 0) return
157
+ else if (this.scrollValuePercent >= 100 - this.thumbSizePercent && e[this.m.deltaXorY] > 0) return
158
+
159
+ e.preventDefault() // Hold the scroll in the hovered w-scrollable element.
160
+
161
+ this.scrollValuePercent += e[this.m.deltaXorY] * 0.05
162
+ this.scrollValuePercent = Math.max(0, Math.min(this.scrollValuePercent, 100))
163
+ this.scroll()
164
+ },
165
+
166
+ computeScroll (cursorPositionXorY) {
167
+ const { top, left, width, height } = this.$refs.scrollable.getBoundingClientRect()
168
+ const topOrLeft = this.isHorizontal ? left : top
169
+ const widthOrHeight = this.isHorizontal ? width : height
170
+ this.scrollValuePercent = Math.max(0, Math.min(((cursorPositionXorY - topOrLeft) / widthOrHeight) * 100, 100))
171
+ },
172
+
173
+ scroll () {
174
+ this.$refs.scrollable[this.m.scrollTopOrLeft] = this.scrollValuePercent * this.$refs.scrollable?.[this.m.scrollWidthOrHeight] / 100
175
+ this.updateThumbPosition()
176
+ },
177
+
178
+ updateThumbPosition () {
179
+ this.$refs.thumb.style[this.m.topOrLeft] = this.scrollValuePercent
180
+ }
181
+ },
182
+
183
+ mounted () {
184
+ this.mounted = true
185
+ const { top, left } = this.$refs.scrollable.getBoundingClientRect()
186
+ this.scrollable.top = top
187
+ this.scrollable.left = left
188
+
189
+ this.$el.parentNode.style.position = 'relative'
190
+ this.$el.parentNode.style[this.m.maxWidthOrHeight] = `${this[this.m.widthOrHeight]}px`
191
+ }
192
+ }
193
+ </script>
194
+
195
+ <style lang="scss">
196
+ .w-scrollable {
197
+ position: relative;
198
+ overflow: hidden;
199
+ }
200
+
201
+ .w-scrollbar {
202
+ position: absolute;
203
+ background: #000;
204
+ user-select: none;
205
+
206
+ &--horizontal {
207
+ left: 0;
208
+ right: 0;
209
+ bottom: 0;
210
+ height: 8px;
211
+ }
212
+ &--vertical {
213
+ top: 0;
214
+ bottom: 0;
215
+ right: 0;
216
+ width: 8px;
217
+ }
218
+
219
+ &__thumb {
220
+ position: absolute;
221
+ background: #333;
222
+ border-radius: $border-radius;
223
+ z-index: 1;
224
+ will-change: top left;
225
+
226
+ &:hover {background: #444;}
227
+ }
228
+ &--horizontal &__thumb {
229
+ height: 6px;
230
+ left: 0;
231
+ right: 0;
232
+ margin-top: 1px;
233
+ margin-bottom: 1px;
234
+ }
235
+ &--vertical &__thumb {
236
+ width: 6px;
237
+ top: 0;
238
+ bottom: 0;
239
+ margin-left: 1px;
240
+ margin-right: 1px;
241
+ }
242
+ }
243
+ </style>
@@ -2,57 +2,79 @@
2
2
  .w-tabs(:class="tabsClasses")
3
3
  .w-tabs__bar(ref="tabs-bar" :class="tabsBarClasses")
4
4
  .w-tabs__bar-item(
5
- v-for="(item, i) in tabsItems"
5
+ v-for="(item, i) in tabs"
6
6
  :key="i"
7
7
  :class="barItemClasses(item)"
8
- @click="!item._disabled && openTab(item)"
8
+ @click="!item._disabled && item._uid !== activeTabUid && openTab(item._uid)"
9
9
  @focus="$emit('focus', getOriginalItem(item))"
10
10
  :tabindex="!item._disabled && 0"
11
- @keypress.enter="!item._disabled && openTab(item)"
12
- :aria-selected="item._index === activeTabIndex ? 'true' : 'false'"
11
+ @keypress.enter="!item._disabled && openTab(item._uid)"
12
+ :aria-selected="item._uid === activeTabUid ? 'true' : 'false'"
13
13
  role="tab")
14
14
  slot(
15
15
  v-if="$slots[`item-title.${item.id || i + 1}`]"
16
16
  :name="`item-title.${item.id || i + 1}`"
17
17
  :item="getOriginalItem(item)"
18
18
  :index="i + 1"
19
- :active="item._index === activeTabIndex")
19
+ :active="item._uid === activeTabUid")
20
20
  slot(
21
21
  v-else
22
22
  name="item-title"
23
23
  :item="getOriginalItem(item)"
24
24
  :index="i + 1"
25
- :active="item._index === activeTabIndex")
25
+ :active="item._uid === activeTabUid")
26
26
  div(v-html="item[itemTitleKey]")
27
27
  .w-tabs__bar-extra(v-if="$slots['tabs-bar-extra']")
28
28
  slot(name="tabs-bar-extra")
29
29
  .w-tabs__slider(v-if="!noSlider && !card" :class="sliderColor" :style="sliderStyles")
30
30
 
31
- .w-tabs__content-wrap(v-if="tabsItems.length")
32
- transition(:name="transitionName" :mode="transitionMode")
33
- keep-alive
31
+ .w-tabs__content-wrap(v-if="tabs.length")
32
+ transition-group(v-if="keepInDom" :name="transitionName")
33
+ tab-content(
34
+ v-for="(tab, i) in tabs"
35
+ :key="tab._uid"
36
+ :item="tab"
37
+ v-show="tab._uid === activeTab._uid"
38
+ :class="contentClass")
39
+ slot(
40
+ v-if="$slots[`item-content.${tab._index + 1}`]"
41
+ :name="`item-content.${tab._index + 1}`"
42
+ :item="getOriginalItem(tab)"
43
+ :index="tab._index + 1"
44
+ :active="tab._index === activeTab._index")
45
+ slot(
46
+ v-else
47
+ name="item-content"
48
+ :item="getOriginalItem(tab)"
49
+ :index="tab._index + 1"
50
+ :active="tab._index === activeTab._index")
51
+ div(v-if="tab[itemContentKey]" v-html="tab[itemContentKey]")
52
+ transition(v-else :name="transitionName" :mode="transitionMode")
53
+ keep-alive(:exclude="keepAlive ? '' : 'tab-content'")
34
54
  //- Keep-alive only works with components, not with DOM nodes.
35
- tab-content(:key="activeTab._index" :item="activeTab" :class="contentClass")
55
+ tab-content(:key="activeTabUid" :item="activeTab" :class="contentClass")
36
56
  template(#default="{ item }")
37
- slot(
38
- v-if="$slots[`item-content.${item._index + 1}`]"
39
- :name="`item-content.${item._index + 1}`"
40
- :item="getOriginalItem(item)"
41
- :index="item._index + 1"
42
- :active="item._index === activeTab._index")
43
- slot(
44
- v-else
45
- name="item-content"
46
- :item="getOriginalItem(item)"
47
- :index="item._index + 1"
48
- :active="item._index === activeTab._index")
49
- div(v-if="item[itemContentKey]" v-html="item[itemContentKey]")
57
+ template(v-if="item")
58
+ slot(
59
+ v-if="$slots[`item-content.${item._index + 1}`]"
60
+ :name="`item-content.${item._index + 1}`"
61
+ :item="getOriginalItem(item)"
62
+ :index="item._index + 1"
63
+ :active="item._uid === activeTabUid")
64
+ slot(
65
+ v-else
66
+ name="item-content"
67
+ :item="getOriginalItem(item)"
68
+ :index="item._index + 1"
69
+ :active="item._uid === activeTabUid")
70
+ div(v-if="item[itemContentKey]" v-html="item[itemContentKey]")
50
71
  </template>
51
72
 
52
73
  <script>
53
- import { reactive } from 'vue'
54
74
  import TabContent from './tab-content.vue'
55
75
 
76
+ let uid = 0
77
+
56
78
  export default {
57
79
  name: 'w-tabs',
58
80
 
@@ -61,6 +83,7 @@ export default {
61
83
  color: { type: String },
62
84
  bgColor: { type: String },
63
85
  items: { type: [Array, Number] },
86
+ itemIdKey: { type: String, default: 'id' },
64
87
  itemTitleKey: { type: String, default: 'title' },
65
88
  itemContentKey: { type: String, default: 'content' },
66
89
  titleClass: { type: String },
@@ -75,7 +98,9 @@ export default {
75
98
  right: { type: Boolean },
76
99
  card: { type: Boolean },
77
100
  dark: { type: Boolean },
78
- light: { type: Boolean }
101
+ light: { type: Boolean },
102
+ keepAlive: { type: Boolean, default: true },
103
+ keepInDom: { type: Boolean, default: false }
79
104
  },
80
105
 
81
106
  components: { TabContent },
@@ -83,7 +108,9 @@ export default {
83
108
  emits: ['input', 'update:modelValue', 'focus'],
84
109
 
85
110
  data: () => ({
111
+ tabs: [],
86
112
  activeTabEl: null,
113
+ activeTabUid: null,
87
114
  activeTabIndex: 0,
88
115
  prevTabIndex: -1, // To detect transition direction.
89
116
  slider: {
@@ -107,18 +134,13 @@ export default {
107
134
  return this.activeTab._index < this.prevTabIndex ? 'right' : 'left'
108
135
  },
109
136
 
110
- tabsItems () {
111
- const items = typeof this.items === 'number' ? Array(this.items).fill({}) : this.items
112
-
113
- return items.map((item, _index) => reactive({
114
- ...item,
115
- _index,
116
- _disabled: !!item.disabled
117
- }))
137
+ activeTab () {
138
+ return this.tabsByUid[this.activeTabUid] || this.tabs[0] || {}
118
139
  },
119
140
 
120
- activeTab () {
121
- return this.tabsItems[this.activeTabIndex] || this.tabsItems[0] || {}
141
+ // An object indexing the tabs by their uid.
142
+ tabsByUid () {
143
+ return this.tabs.reduce((obj, tab) => ((obj[tab._uid] = tab) && obj), {})
122
144
  },
123
145
 
124
146
  tabsClasses () {
@@ -149,6 +171,54 @@ export default {
149
171
  },
150
172
 
151
173
  methods: {
174
+ // Adding a tab in the list.
175
+ addTab (item) {
176
+ // If there is no unique ID provided, inject one in each tab.
177
+ // This will cause a single other update from watching the tabs items and stop there.
178
+ if (!(item[this.itemIdKey] ?? item._uid ?? false)) item._uid = +`${this._.uid}${++uid}`
179
+
180
+ this.tabs.push({
181
+ _uid: item[this.itemIdKey] ?? item._uid,
182
+ _index: this.tabs.length,
183
+ ...item,
184
+ _disabled: !!item.disabled
185
+ })
186
+ },
187
+
188
+ refreshTabs () {
189
+ let items = this.items
190
+ if (typeof items === 'number') items = Array(items).fill().map((_, i) => this.tabs[i] || {})
191
+
192
+ this.tabs = items.map((item, _index) => {
193
+ // If there is no unique ID provided, inject one in each tab.
194
+ // This will cause a single other update from watching the tabs items and stop there.
195
+ if (!(item[this.itemIdKey] ?? item._uid ?? false)) item._uid = +`${this._.uid}${++uid}`
196
+
197
+ return {
198
+ ...item,
199
+ _uid: item[this.itemIdKey] ?? item._uid,
200
+ _index,
201
+ _disabled: !!item.disabled
202
+ }
203
+ })
204
+ },
205
+
206
+ reopenTheActiveTab () {
207
+ // If there is only 1 tab left open it.
208
+ if (this.tabs.length === 1) return this.openTab(this.tabs[0]._uid)
209
+
210
+ // First try to find the same uid in remaining tabs.
211
+ let uid = this.tabsByUid[this.activeTabUid]?._uid
212
+
213
+ // If not found, try to open the tab with the same index.
214
+ if (!uid) uid = this.tabs[this.activeTabIndex]?._uid
215
+
216
+ // If not found (no tab to the right), try to open the next tab to the left.
217
+ if (!uid) uid = this.tabs[Math.max(this.activeTabIndex - 1, this.tabs.length - 1)]?._uid
218
+
219
+ if (uid) this.openTab(uid)
220
+ },
221
+
152
222
  onResize () {
153
223
  this.updateSlider(false)
154
224
  },
@@ -165,11 +235,14 @@ export default {
165
235
  }
166
236
  },
167
237
 
168
- openTab (item) {
238
+ // Switching tabs.
239
+ openTab (uid) {
169
240
  this.prevTabIndex = this.activeTabIndex // To resolve the transition direction.
170
- this.activeTabIndex = item._index
171
- this.$emit('update:modelValue', item._index)
172
- this.$emit('input', item._index)
241
+ const tab = this.tabsByUid[uid]
242
+ this.activeTabIndex = tab._index
243
+ this.activeTabUid = tab._uid
244
+ this.$emit('update:modelValue', tab._index)
245
+ this.$emit('input', tab._index)
173
246
 
174
247
  if (!this.noSlider) this.$nextTick(this.updateSlider)
175
248
  },
@@ -190,34 +263,42 @@ export default {
190
263
  this.slider.width = `${width}px`
191
264
  }
192
265
  else {
193
- this.slider.left = `${this.activeTab._index * 100 / this.tabsItems.length}%`
194
- this.slider.width = `${100 / this.tabsItems.length}%`
266
+ this.slider.left = `${this.activeTab._index * 100 / this.tabs.length}%`
267
+ this.slider.width = `${100 / this.tabs.length}%`
195
268
  }
196
269
  },
197
270
 
198
271
  updateActiveTab (index) {
199
272
  if (typeof index === 'string') index = ~~index
200
273
  else if (isNaN(index) || index < 0) index = 0
201
- this.activeTabIndex = index
202
274
 
203
- // Scroll the new active tab item title into view if needed.
204
- this.$nextTick(() => {
205
- const ref = this.$refs['tabs-bar']
206
- this.activeTabEl = ref && ref.querySelector(`.w-tabs__bar-item:nth-child(${index + 1})`)
207
- if (this.activeTabEl) {
208
- this.activeTabEl.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' })
209
- }
210
- })
275
+ // Only open the tab if it is found.
276
+ if (this.tabs[index]?._uid) {
277
+ this.openTab(this.tabs[index]?._uid)
278
+
279
+ // Scroll the new active tab item title into view if needed.
280
+ this.$nextTick(() => {
281
+ const ref = this.$refs['tabs-bar']
282
+ this.activeTabEl = ref && ref.querySelector(`.w-tabs__bar-item:nth-child(${index + 1})`)
283
+ if (this.activeTabEl) {
284
+ this.activeTabEl.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' })
285
+ }
286
+ })
287
+ }
211
288
  },
212
289
 
213
290
  // Return the original item (so there is no `_index`, etc.).
214
291
  getOriginalItem (item) {
215
- return this.items[item._index]
292
+ return this.items[item._index] || {}
216
293
  }
217
294
  },
218
295
 
219
296
  beforeMount () {
220
- this.updateActiveTab(this.modelValue)
297
+ this.tabs = [] // Reset for hot-reloading.
298
+ const items = typeof this.items === 'number' ? Array(this.items).fill().map(Object) : this.items
299
+ items.forEach(this.addTab)
300
+
301
+ if (this.modelValue ?? false) this.updateActiveTab(this.modelValue)
221
302
 
222
303
  this.$nextTick(() => {
223
304
  this.updateSlider()
@@ -234,13 +315,17 @@ export default {
234
315
 
235
316
  watch: {
236
317
  modelValue (index) {
237
- this.updateActiveTab(index)
318
+ if (index !== this.activeTabIndex) this.updateActiveTab(index)
238
319
  },
239
- items () {
240
- // When deleting a tab, activate the previous one.
241
- while (this.activeTabIndex > 0 && !this.tabsItems[this.activeTabIndex]) this.activeTabIndex--
320
+ items: {
321
+ handler () {
322
+ this.refreshTabs()
242
323
 
243
- if (!this.noSlider) this.$nextTick(this.updateSlider)
324
+ if (this.tabs.length) this.reopenTheActiveTab()
325
+
326
+ if (!this.noSlider) this.$nextTick(this.updateSlider)
327
+ },
328
+ deep: true
244
329
  },
245
330
  fillBar () {
246
331
  if (!this.noSlider) this.$nextTick(this.updateSlider)
@@ -381,8 +466,10 @@ export default {
381
466
  .w-tabs-slide-left-leave-active,
382
467
  .w-tabs-slide-right-leave-active {
383
468
  position: absolute;
469
+ top: 0;
384
470
  left: 0;
385
471
  right: 0;
472
+ overflow: hidden;
386
473
  }
387
474
 
388
475
  .w-tabs-slide-left-enter-active {animation: w-tabs-slide-left-enter $transition-duration + 0.15s;}
@@ -5,7 +5,14 @@
5
5
 
6
6
  <script>
7
7
  // Keep-alive only works with components, not with DOM nodes.
8
+
8
9
  export default {
9
- props: { item: Object }
10
+ name: 'tab-content', // Keep-alive include/exclude mechanism is component-name-based.
11
+
12
+ props: { item: Object },
13
+
14
+ mounted () {
15
+ console.log('mounted!', this.item._uid)
16
+ }
10
17
  }
11
18
  </script>
@@ -1,24 +0,0 @@
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>