wave-ui 1.60.1 → 1.62.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.60.1",
3
+ "version": "1.62.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",
@@ -48,7 +48,7 @@
48
48
  "lint": "vite lint"
49
49
  },
50
50
  "devDependencies": {
51
- "@babel/core": "^7.20.2",
51
+ "@babel/core": "^7.20.5",
52
52
  "@babel/eslint-parser": "^7.19.1",
53
53
  "@babel/plugin-proposal-class-properties": "^7.18.6",
54
54
  "@mdi/font": "^6.9.96",
@@ -1,4 +1,3 @@
1
- // Keep all the `.vue` extensions for Vite & Rollup.
2
1
  export { default as WAccordion } from './w-accordion.vue'
3
2
  export { default as WAlert } from './w-alert.vue'
4
3
  export { default as WApp } from './w-app.vue'
@@ -49,3 +48,4 @@ export { default as WTransitionScaleFade } from './transitions/w-transition-scal
49
48
  export { default as WTransitionSlide } from './transitions/w-transition-slide.vue'
50
49
  export { default as WTransitionSlideFade } from './transitions/w-transition-slide-fade.vue'
51
50
  export { default as WTransitionTwist } from './transitions/w-transition-twist.vue'
51
+ export { default as WTree } from './w-tree.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
 
@@ -123,7 +123,7 @@ export default {
123
123
  overflow: auto;
124
124
  background-color: #fff;
125
125
 
126
- .w-dialog--fullscreen & {
126
+ .w-dialog--fullscreen > & {
127
127
  flex: 1 1 auto;
128
128
  height: 100%;
129
129
  max-width: none;
@@ -78,6 +78,7 @@ export default {
78
78
  absolute: { type: Boolean },
79
79
  overlayColor: { type: String },
80
80
  overlayOpacity: { type: [Number, String, Boolean] },
81
+ drawerClass: { type: String },
81
82
  tag: { type: String, default: 'aside' }
82
83
  },
83
84
 
@@ -127,6 +128,7 @@ export default {
127
128
  },
128
129
  drawerClasses () {
129
130
  return {
131
+ [this.drawerClass]: true,
130
132
  [this.color]: this.color,
131
133
  [`${this.bgColor}--bg`]: this.bgColor,
132
134
  'w-drawer--open': !!this.showDrawer,
@@ -128,6 +128,7 @@ export default {
128
128
  .w-button.size--lg &, .w-alert.size--lg & {font-size: round(1.7 * $base-font-size);}
129
129
  .w-button.size--xl &, .w-alert.size--xl & {font-size: 2 * $base-font-size;}
130
130
 
131
+ &:before {transition: transform $transition-duration;}
131
132
  &--spin:before {animation: w-icon--spin 2s infinite linear;}
132
133
  &--spin-a:before {animation: w-icon--spin-a 2s infinite linear;}
133
134
  &--rotate45:before {transform: rotate(45deg);}
@@ -9,7 +9,7 @@ component.w-image-wrap(:is="wrapperTag" :class="wrapperClasses" :style="wrapperS
9
9
  :src="tag === 'img' ? imgSrc : null")
10
10
  .w-image__loader(v-if="!noSpinner && loading")
11
11
  slot(v-if="$slots.loading" name="loading")
12
- w-progress(v-else circle indeterminate)
12
+ w-progress(v-else circle indeterminate v-bind="spinnerColor ? { color: spinnerColor } : {}")
13
13
  component.w-image__content(v-if="$slots.default" :is="wrapperTag" :class="contentClass")
14
14
  slot
15
15
  </template>
@@ -22,9 +22,10 @@ component.w-image-wrap(:is="wrapperTag" :class="wrapperClasses" :style="wrapperS
22
22
  * - adaptive size: given ratio + width 100% (use bg)
23
23
  * - adaptive size: given ratio + height 100% (use bg)
24
24
  * - adaptive & locked size: given width or height and using <img>
25
+ *
26
+ * @todo handle figure, captions, srcset, webp.
25
27
  **/
26
28
 
27
- // @todo handle figure, captions, srcset, webp.
28
29
  import { consoleWarn } from '../utils/console'
29
30
 
30
31
  export default {
@@ -40,6 +41,7 @@ export default {
40
41
  fixed: { type: Boolean },
41
42
  contain: { type: Boolean },
42
43
  noSpinner: { type: Boolean },
44
+ spinnerColor: { type: String },
43
45
  fallback: { type: String },
44
46
  transition: { type: String, default: 'fade' },
45
47
  contentClass: { type: [String, Array, Object] }
@@ -453,7 +453,7 @@ $inactive-color: #777;
453
453
  &__input {
454
454
  width: 100%;
455
455
  height: 100%;
456
- font-size: inherit;
456
+ font: inherit;
457
457
  color: inherit;
458
458
  text-align: inherit;
459
459
  display: inline-flex;
@@ -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)
@@ -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;
527
+ right: 0;
525
528
  // Use margin instead of padding as the scale transformation bellow 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,6 +793,29 @@ $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.