wave-ui 1.66.1 → 1.67.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.
@@ -9,7 +9,8 @@
9
9
  col.w-table__col(
10
10
  v-for="(header, i) in headers"
11
11
  :key="i"
12
- :width="header.width || null")
12
+ :width="header.width || null"
13
+ :class="colClasses[i]")
13
14
 
14
15
  //- Table header.
15
16
  thead(v-if="!noHeaders")
@@ -58,7 +59,7 @@
58
59
 
59
60
  //- Normal rows.
60
61
  template(v-if="tableItems.length && loading !== true")
61
- template(v-for="(item, i) in sortedItems")
62
+ template(v-for="(item, i) in paginatedItems")
62
63
  //- Fully custom tr (`item` slot).
63
64
  slot(
64
65
  v-if="$scopedSlots['item']"
@@ -135,27 +136,41 @@
135
136
  slot(name="footer")
136
137
  tr.w-table__row.w-table__pagination-wrap(v-if="pagination && paginationConfig")
137
138
  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)
139
+ .w-table__pagination.w-pagination
140
+ slot(
141
+ name="pagination"
142
+ :range="`${paginationConfig.start}-${paginationConfig.end}`"
143
+ :total="paginationConfig.total")
144
+ w-select.w-pagination__items-per-page(
145
+ v-if="paginationConfig.itemsPerPageOptions"
146
+ v-model="paginationConfig.itemsPerPage"
147
+ @input="updatePaginationConfig({ itemsPerPage: paginationConfig.itemsPerPage })"
148
+ :items="paginationConfig.itemsPerPageOptions"
149
+ label-position="left"
150
+ label="Items per page"
151
+ label-color="inherit")
152
+ .pages-wrap
153
+ w-button.w-pagination__arrow.w-pagination__arrow--prev(
154
+ @click="goToPage('-1')"
155
+ :disabled="paginationConfig.page <= 1"
156
+ icon="wi-chevron-left"
157
+ text
158
+ lg)
159
+ w-button.w-pagination__page(
160
+ v-for="i in paginationConfig.pagesCount"
161
+ :key="i"
162
+ @click="i !== paginationConfig.page && goToPage(i)"
163
+ :class="{ 'w-pagination__page--active': i === paginationConfig.page }"
164
+ round
165
+ lg) {{ i }}
166
+ w-button.w-pagination__arrow.w-pagination__arrow--next(
167
+ @click="goToPage('+1')"
168
+ :disabled="paginationConfig.page >= paginationConfig.pagesCount"
169
+ icon="wi-chevron-right"
170
+ text
171
+ lg)
172
+ span.w-pagination__results.
173
+ {{ paginationConfig.start }}-{{ paginationConfig.end || paginationConfig.total }} of {{ paginationConfig.total }}
159
174
  </template>
160
175
 
161
176
  <script>
@@ -180,6 +195,9 @@ export default {
180
195
  loading: { type: [Boolean, String] }, // Bool or 'header' to only display the bar in the header.
181
196
  // Allow single sort: `+id`, or multiple in an array like: ['+id', '-firstName'].
182
197
  sort: { type: [String, Array] },
198
+ sortFunction: { type: Function },
199
+ filter: { type: Function },
200
+ fetch: { type: Function },
183
201
 
184
202
  expandableRows: {
185
203
  validator: value => {
@@ -214,11 +232,16 @@ export default {
214
232
  // Useful to select or expand a row, and even after a filter, the same row will stay selected or expanded.
215
233
  uidKey: { type: String, default: 'id' },
216
234
 
217
- filter: { type: Function },
218
- sortFunction: { type: Function },
219
235
  mobileBreakpoint: { type: Number, default: 0 },
220
236
  resizableColumns: { type: Boolean },
221
237
 
238
+ // An object containing:
239
+ // - itemsPerPage
240
+ // - itemsPerPageOptions
241
+ // - start
242
+ // - end
243
+ // - page
244
+ // - total
222
245
  pagination: {
223
246
  type: [Boolean, Object, String],
224
247
  validator: object => {
@@ -260,13 +283,20 @@ export default {
260
283
  columnEl: null,
261
284
  nextColumnEl: null
262
285
  },
263
- paginationConfig: {}
286
+ paginationConfig: {
287
+ itemsPerPage: 0,
288
+ itemsPerPageOptions: {},
289
+ start: 0,
290
+ end: 0,
291
+ page: 1,
292
+ total: 0
293
+ }
264
294
  }),
265
295
 
266
296
  computed: {
267
297
  tableItems () {
268
298
  return this.items.map((item, i) => {
269
- item._uid = item[this.uidKey] !== undefined ? item[this.uidKey] : i
299
+ item._uid = item[this.uidKey] ?? i
270
300
  return item
271
301
  })
272
302
  },
@@ -276,7 +306,7 @@ export default {
276
306
  },
277
307
 
278
308
  sortedItems () {
279
- if (!this.activeSorting.length || this.sortFunction) return this.filteredItems
309
+ if (!this.activeSorting.length || this.sortFunction || this.fetch) return this.filteredItems
280
310
 
281
311
  // Only sort with 1 key for now, may handle more later.
282
312
  const sortKey1 = this.activeSorting[0].replace(/^[+-]/, '')
@@ -293,6 +323,10 @@ export default {
293
323
  })
294
324
  },
295
325
 
326
+ paginatedItems () {
327
+ return typeof this.fetch === 'function' ? this.sortedItems : this.sortedItems.slice(this.paginationConfig.start - 1, this.paginationConfig.end)
328
+ },
329
+
296
330
  // Returns an object containing { key1: '+', key2: '-' }. With + or - for ASC/DESC.
297
331
  activeSortingKeys () {
298
332
  return this.activeSorting.reduce((obj, item) => {
@@ -307,8 +341,16 @@ export default {
307
341
  }
308
342
  },
309
343
 
344
+ colClasses () {
345
+ return this.headers.map(header => {
346
+ return { 'w-table__col--highlighted': this.activeSortingKeys[header.key] }
347
+ }) || []
348
+ },
349
+
310
350
  classes () {
311
351
  return {
352
+ 'w-table--loading': this.loading,
353
+ 'w-table--loading-in-header': this.loading === 'header',
312
354
  'w-table--fixed-layout': this.fixedLayout || this.resizableColumns || this.hasStickyColumn,
313
355
  'w-table--mobile': this.isMobile || null,
314
356
  'w-table--resizable-cols': this.resizableColumns || null,
@@ -366,9 +408,8 @@ export default {
366
408
 
367
409
  this.$emit('update:sort', this.activeSorting)
368
410
 
369
- if (typeof this.sortFunction === 'function') {
370
- await this.sortFunction(this.activeSorting)
371
- }
411
+ if (typeof this.sortFunction === 'function') await this.sortFunction(this.activeSorting)
412
+ else if (typeof this.fetch === 'function') await this.callApiFetch()
372
413
  },
373
414
 
374
415
  doSelectRow (item, index) {
@@ -530,18 +571,75 @@ export default {
530
571
  }, 0)
531
572
  },
532
573
 
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 = {
574
+ initPagination () {
575
+ const itemsPerPage = this.pagination?.itemsPerPage ?? 20 // Can also be `0` for all.
576
+
577
+ const itemsPerPageOptions = this.pagination?.itemsPerPageOptions || [20, 100, { label: 'All', value: 0 }]
578
+ // If the given itemsPerPage is not in the itemsPerPageOptions, add it.
579
+ if (!itemsPerPageOptions.find(item => (item?.value ?? item) === +itemsPerPage)) {
580
+ itemsPerPageOptions.push(itemsPerPage)
581
+ }
582
+ this.paginationConfig.itemsPerPageOptions = itemsPerPageOptions.map(item => ({
583
+ label: ['string', 'number'].includes(typeof item) ? item.toString() : (item.label || item.value),
584
+ value: ['string', 'number'].includes(typeof item) ? ~~item : (item.value ?? item.label)
585
+ }))
586
+ // Sort the options in an ascending order.
587
+ this.paginationConfig.itemsPerPageOptions.sort((a, b) => a.value < b.value ? -1 : 1)
588
+ const optionAll = this.paginationConfig.itemsPerPageOptions.shift()
589
+ this.paginationConfig.itemsPerPageOptions.push(optionAll)
590
+
591
+ this.updatePaginationConfig({
538
592
  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
593
+ page: this.pagination.page || 1,
594
+ total: this.pagination.total || this.items.length
595
+ })
596
+ },
597
+
598
+ updatePaginationConfig ({ itemsPerPage, page, total }) {
599
+ if (total) this.paginationConfig.total = total
600
+ if (itemsPerPage !== undefined) {
601
+ this.paginationConfig.itemsPerPage = itemsPerPage
602
+ itemsPerPage = itemsPerPage || this.paginationConfig.total // If `0`, take all the results.
603
+ this.paginationConfig.page = 1;
604
+ ({ page } = this.paginationConfig) // Shorthand var for next lines.
605
+ total = this.paginationConfig.total // Shorthand var for next lines.
606
+ this.paginationConfig.start = 1
607
+ this.paginationConfig.end = total >= (itemsPerPage * page) ? (itemsPerPage * page) : (total % (itemsPerPage * page))
608
+ this.paginationConfig.pagesCount = Math.ceil(total / itemsPerPage)
544
609
  }
610
+ if (page) this.goToPage(page)
611
+ },
612
+
613
+ /**
614
+ * Goes to a given page or to the next or previous page.
615
+ *
616
+ * @param {Number|String} page a number to go to a specific page or `-1`, `+1` for prev & next page.
617
+ */
618
+ async goToPage (page) {
619
+ if (['-1', '+1'].includes(page)) this.paginationConfig.page += +page
620
+ else this.paginationConfig.page = page
621
+ const { itemsPerPage, total } = this.paginationConfig
622
+ this.paginationConfig.page = Math.max(1, this.paginationConfig.page)
623
+ this.paginationConfig.start = (itemsPerPage * (this.paginationConfig.page - 1)) + 1
624
+ this.paginationConfig.end = (this.paginationConfig.start - 1) + (itemsPerPage || total)
625
+
626
+ if (typeof this.fetch === 'function') await this.callApiFetch()
627
+ },
628
+
629
+ /**
630
+ * Call a user provided fetch function in order to fetch table items from an API.
631
+ * While waiting for the call to resolve, nothing in the table will change.
632
+ */
633
+ async callApiFetch () {
634
+ const { page, start, end, total, itemsPerPage } = this.paginationConfig
635
+ return await this.fetch({
636
+ page,
637
+ start,
638
+ end: end || total,
639
+ total,
640
+ itemsPerPage: itemsPerPage || total,
641
+ sorting: this.activeSorting
642
+ })
545
643
  }
546
644
  },
547
645
 
@@ -552,7 +650,7 @@ export default {
552
650
  if ((this.expandedRows || []).length) this.expandedRowsInternal = this.expandedRows
553
651
  if ((this.selectedRows || []).length) this.selectedRowsInternal = this.selectedRows
554
652
 
555
- if (this.pagination) this.updatePaginationConfig()
653
+ if (this.pagination) this.initPagination()
556
654
  },
557
655
 
558
656
  watch: {
@@ -577,6 +675,16 @@ export default {
577
675
 
578
676
  selectedRows (array) {
579
677
  this.selectedRowsInternal = Array.isArray(array) && array.length ? this.selectedRows : []
678
+ },
679
+
680
+ 'pagination.page' (page) {
681
+ this.updatePaginationConfig({ page })
682
+ },
683
+ 'pagination.itemsPerPage' (itemsPerPage) {
684
+ this.updatePaginationConfig({ itemsPerPage })
685
+ },
686
+ 'pagination.total' (total) {
687
+ this.updatePaginationConfig({ total })
580
688
  }
581
689
  }
582
690
  }
@@ -610,6 +718,10 @@ $tr-border-top: 1px;
610
718
  user-select: none;
611
719
  }
612
720
 
721
+ // Table columns.
722
+ // ------------------------------------------------------
723
+ &__col--highlighted {background-color: rgba(#000, 0.04);}
724
+
613
725
  // Table headers.
614
726
  // ------------------------------------------------------
615
727
  thead {position: relative;}
@@ -699,7 +811,7 @@ $tr-border-top: 1px;
699
811
  left: 0;
700
812
  right: 0;
701
813
  }
702
- &__progress-bar td {padding: 0;height: 1px;}
814
+ &__progress-bar td {padding: 0;height: 0;}
703
815
  @-moz-document url-prefix() {
704
816
  &__progress-bar td {height: 100%;}
705
817
  }
@@ -708,7 +820,7 @@ $tr-border-top: 1px;
708
820
  display: flex;
709
821
  align-items: center;
710
822
  justify-content: center;
711
- height:100%;
823
+ height: 100%;
712
824
  width: 100%;
713
825
  padding-top: 2 * $base-increment;
714
826
  padding-bottom: 2 * $base-increment;
@@ -716,7 +828,10 @@ $tr-border-top: 1px;
716
828
 
717
829
  // Table body.
718
830
  // ------------------------------------------------------
719
- tbody tr {border-top: $tr-border-top solid rgba(0, 0, 0, 0.06);}
831
+ tbody {transition: opacity $transition-duration;}
832
+ &--loading-in-header tbody {opacity: 0.6;}
833
+
834
+ tbody tr {border-top: $tr-border-top solid rgba(#000, 0.06);}
720
835
  // Don't apply built-in bg color if a bg color is already found on a tr.
721
836
  tbody tr:nth-child(odd):not(.no-data):not([class*="--bg"]) {background-color: $table-tr-odd-color;}
722
837
  tbody .w-table__row:hover:not(.no-data):not([class*="--bg"]) {background-color: $table-tr-hover-color;}
@@ -773,47 +888,82 @@ $tr-border-top: 1px;
773
888
 
774
889
  // Table footer.
775
890
  // ------------------------------------------------------
776
- &__footer &__cell {
777
- padding-top: $base-increment;
778
- padding-bottom: $base-increment;
779
- }
780
-
781
891
  &--fixed-footer tfoot {
782
892
  position: sticky;
783
- bottom: 0;
893
+ bottom: -1px;
784
894
  background-color: #fff;
785
895
  z-index: 1; // For sticky columns to go under.
786
896
 
787
897
  &:after {
788
898
  content: '';
789
899
  position: absolute;
790
- bottom: 0;
900
+ top: 0;
791
901
  left: 0;
792
902
  right: 0;
793
- border-bottom: $border;
903
+ border-top: $border;
794
904
  }
795
905
  }
796
906
 
907
+ &__footer &__cell {
908
+ padding-top: $base-increment;
909
+ padding-bottom: $base-increment;
910
+ }
911
+
912
+ // Pagination.
913
+ // ------------------------------------------------------
797
914
  &__pagination {
798
915
  display: flex;
799
916
  align-items: center;
800
917
  justify-content: flex-end;
801
- padding-top: $base-increment;
802
- padding-bottom: $base-increment;
803
918
 
804
- .pagination-number--items-per-page {
805
- margin-right: 6 * $base-increment;
806
- flex-grow: 0;
919
+ .w-pagination__items-per-page {
920
+ flex: 0 0 auto;
807
921
  text-align: right;
808
922
  }
809
- .pagination-number--of {
810
- margin-left: $base-increment;
811
- margin-right: $base-increment;
923
+
924
+ .pages-wrap {
925
+ margin-left: 3 * $base-increment;
926
+ margin-right: 3 * $base-increment;
927
+ padding-left: 1px; // Prevent overflow causing scrollbar.
928
+ padding-right: 1px;
929
+ overflow: auto;
930
+ max-height: 4.5em;
931
+ }
932
+
933
+ .w-pagination__page {
934
+ margin: 0.5 * $base-increment;
935
+ font-size: 0.9em;
936
+ aspect-ratio: 1;
937
+ overflow: hidden;
938
+ color: rgba(#000, 0.65);
939
+ background-color: rgba(#fff, 0.4);
940
+
941
+ &:hover:before {
942
+ background-color: $primary;
943
+ opacity: 0.1;
944
+ }
945
+ &:active:before {
946
+ background-color: $primary;
947
+ opacity: 0.2;
948
+ }
949
+
950
+ &--active {
951
+ font-weight: bold;
952
+ color: $primary;
953
+
954
+ &:before {
955
+ background-color: $primary;
956
+ opacity: 0.1;
957
+ }
958
+ }
812
959
  }
813
- .w-select__selection {max-width: 60px;}
814
960
 
815
- .pagination-arrows {
816
- margin-left: 6 * $base-increment;
961
+ .w-pagination__results {
962
+ margin-left: $base-increment;
963
+ margin-right: $base-increment;
964
+ white-space: nowrap;
965
+ min-width: 90px;
966
+ text-align: right;
817
967
  }
818
968
  }
819
969
  }
@@ -147,7 +147,9 @@ export default {
147
147
  'w-tabs--no-slider': this.noSlider,
148
148
  'w-tabs--pill-slider': this.pillSlider,
149
149
  'w-tabs--fill-bar': this.fillBar,
150
- 'w-tabs--init': this.init
150
+ 'w-tabs--init': this.init,
151
+ 'w-tabs--dark': this.dark,
152
+ 'w-tabs--light': this.light
151
153
  }
152
154
  },
153
155
 
@@ -103,6 +103,7 @@ export default {
103
103
  $font-size: round(0.7 * $base-font-size);
104
104
  font-size: $font-size;
105
105
  line-height: $font-size + 2px;
106
+ padding: round(0.25 * $base-increment) $base-increment;
106
107
  }
107
108
  &.size--sm {
108
109
  $font-size: round(0.82 * $base-font-size);