@weni/unnnic-system 3.9.1 → 3.9.2

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": "@weni/unnnic-system",
3
- "version": "3.9.1",
3
+ "version": "3.9.2",
4
4
  "type": "commonjs",
5
5
  "files": [
6
6
  "dist",
@@ -56,6 +56,7 @@
56
56
  </tr>
57
57
  </thead>
58
58
  <tbody
59
+ ref="tbodyRef"
59
60
  :class="[
60
61
  'unnnic-data-table__body',
61
62
  { 'unnnic-data-table__body--hide-headers': props.hideHeaders },
@@ -120,6 +121,27 @@
120
121
  </td>
121
122
  </template>
122
123
  </tr>
124
+ <tr
125
+ v-if="props.infiniteScroll && props.isLoadingMore"
126
+ :class="[
127
+ 'unnnic-data-table__body-row',
128
+ 'unnnic-data-table__body-row--loading-more',
129
+ ]"
130
+ >
131
+ <td
132
+ :class="[
133
+ 'unnnic-data-table__body-cell',
134
+ `unnnic-data-table__body-cell--${size}`,
135
+ ]"
136
+ >
137
+ <img
138
+ class="unnnic-data-table__body-cell--loading"
139
+ data-testid="body-row-loading-more"
140
+ src="../../assets/icons/weni-loading.svg"
141
+ height="40"
142
+ />
143
+ </td>
144
+ </tr>
123
145
  </template>
124
146
  <tr
125
147
  v-else
@@ -166,6 +188,7 @@
166
188
 
167
189
  <script setup lang="ts">
168
190
  import { computed, ComputedRef, ref, useSlots } from 'vue';
191
+ import { useInfiniteScroll } from '@vueuse/core';
169
192
 
170
193
  import Icon from '../Icon.vue';
171
194
  import IconArrowsDefault from '../icons/iconArrowsDefault.vue';
@@ -205,6 +228,10 @@ interface Props {
205
228
  pageInterval?: number;
206
229
  locale?: string;
207
230
  sort?: SortState;
231
+ infiniteScroll?: boolean;
232
+ infiniteScrollDistance?: number;
233
+ infiniteScrollDisabled?: boolean;
234
+ isLoadingMore?: boolean;
208
235
  }
209
236
 
210
237
  defineOptions({
@@ -217,6 +244,7 @@ const emit = defineEmits<{
217
244
  'update:sort': [sort: { header: string; itemKey: string; order: string }];
218
245
  itemClick: [item: DataTableItem];
219
246
  'update:page': [page: number];
247
+ loadMore: [];
220
248
  }>();
221
249
 
222
250
  const props = withDefaults(defineProps<Props>(), {
@@ -233,6 +261,10 @@ const props = withDefaults(defineProps<Props>(), {
233
261
  pageInterval: 5,
234
262
  locale: 'en',
235
263
  sort: undefined,
264
+ infiniteScroll: false,
265
+ infiniteScrollDistance: 100,
266
+ infiniteScrollDisabled: false,
267
+ isLoadingMore: false,
236
268
  });
237
269
 
238
270
  const defaultTranslations = {
@@ -318,6 +350,21 @@ const handleClickRow = (item: DataTableItem) => {
318
350
 
319
351
  emit('itemClick', item);
320
352
  };
353
+
354
+ const tbodyRef = ref<HTMLElement | null>(null);
355
+
356
+ const handleLoadMore = () => {
357
+ if (props.infiniteScrollDisabled || props.isLoading || props.isLoadingMore) {
358
+ return;
359
+ }
360
+ emit('loadMore');
361
+ };
362
+
363
+ if (props.infiniteScroll) {
364
+ useInfiniteScroll(tbodyRef, handleLoadMore, {
365
+ distance: props.infiniteScrollDistance,
366
+ });
367
+ }
321
368
  </script>
322
369
 
323
370
  <style scoped lang="scss">
@@ -428,6 +475,7 @@ $tableBorder: $unnnic-border-width-thinner solid $unnnic-color-neutral-soft;
428
475
  grid-template-columns: v-bind(gridTemplateColumns);
429
476
 
430
477
  &--loading,
478
+ &--loading-more,
431
479
  &--without-results {
432
480
  grid-template-columns: 1fr;
433
481
  }
@@ -1,6 +1,31 @@
1
1
  import UnnnicDataTable from '../components/DataTable/index.vue';
2
2
  import { action } from '@storybook/addon-actions';
3
3
 
4
+ const SAMPLE_NAMES = [
5
+ 'Eduardo',
6
+ 'Marcus',
7
+ 'Paulo',
8
+ 'Cristian',
9
+ 'Aldemylla',
10
+ 'João',
11
+ 'Maria',
12
+ 'Ana',
13
+ 'Pedro',
14
+ 'Lucas',
15
+ ];
16
+
17
+ const SAMPLE_COUNTRIES = ['Brazil', 'USA', 'Canada', 'Argentina', 'Chile'];
18
+
19
+ const generateItems = (count, startId) => {
20
+ return Array.from({ length: count }, (_, i) => ({
21
+ id: String(startId + i),
22
+ name: SAMPLE_NAMES[Math.floor(Math.random() * SAMPLE_NAMES.length)],
23
+ age: Math.floor(Math.random() * 30) + 20,
24
+ country:
25
+ SAMPLE_COUNTRIES[Math.floor(Math.random() * SAMPLE_COUNTRIES.length)],
26
+ }));
27
+ };
28
+
4
29
  export default {
5
30
  title: 'Data Display/DataTable',
6
31
  component: UnnnicDataTable,
@@ -70,6 +95,26 @@ export default {
70
95
  control: { type: 'select' },
71
96
  options: ['en', 'pt-br', 'es'],
72
97
  },
98
+ infiniteScroll: {
99
+ description:
100
+ 'Enables infinite scroll functionality. When enabled, the table will emit a loadMore event when the user scrolls near the bottom.',
101
+ control: 'boolean',
102
+ },
103
+ infiniteScrollDistance: {
104
+ description:
105
+ 'Distance in pixels from the bottom of the table to trigger the loadMore event.',
106
+ control: 'number',
107
+ },
108
+ infiniteScrollDisabled: {
109
+ description:
110
+ 'Disables the infinite scroll functionality. Useful when all data has been loaded.',
111
+ control: 'boolean',
112
+ },
113
+ isLoadingMore: {
114
+ description:
115
+ 'Indicates whether more data is being loaded for infinite scroll. Shows a loading indicator at the bottom of the table.',
116
+ control: 'boolean',
117
+ },
73
118
  },
74
119
  render: (args) => ({
75
120
  components: {
@@ -390,3 +435,150 @@ export const ControlledSort = {
390
435
  `,
391
436
  }),
392
437
  };
438
+
439
+ export const InfiniteScroll = {
440
+ args: { headers },
441
+ render: (args) => ({
442
+ components: {
443
+ UnnnicDataTable,
444
+ },
445
+ data() {
446
+ return {
447
+ args,
448
+ currentId: 11,
449
+ displayedItems: generateItems(10, 1),
450
+ isLoadingMore: false,
451
+ };
452
+ },
453
+ methods: {
454
+ loadMore() {
455
+ action('loadMore')();
456
+ this.isLoadingMore = true;
457
+
458
+ setTimeout(() => {
459
+ const newItems = generateItems(5, this.currentId);
460
+ this.displayedItems = [...this.displayedItems, ...newItems];
461
+ this.currentId += 5;
462
+ this.isLoadingMore = false;
463
+ }, 1000);
464
+ },
465
+ },
466
+ template: `
467
+ <UnnnicDataTable
468
+ v-bind="args"
469
+ :headers="args.headers"
470
+ :items="displayedItems"
471
+ :infiniteScroll="true"
472
+ :infiniteScrollDistance="100"
473
+ :isLoadingMore="isLoadingMore"
474
+ :hidePagination="true"
475
+ height="400px"
476
+ @loadMore="loadMore"
477
+ >
478
+ </UnnnicDataTable>
479
+ `,
480
+ }),
481
+ };
482
+
483
+ export const InfiniteScrollWithFixedHeaders = {
484
+ args: { headers },
485
+ render: (args) => ({
486
+ components: {
487
+ UnnnicDataTable,
488
+ },
489
+ data() {
490
+ return {
491
+ args,
492
+ currentId: 11,
493
+ displayedItems: generateItems(10, 1),
494
+ isLoadingMore: false,
495
+ hasMore: true,
496
+ };
497
+ },
498
+ methods: {
499
+ loadMore() {
500
+ if (!this.hasMore) return;
501
+
502
+ action('loadMore')();
503
+ this.isLoadingMore = true;
504
+
505
+ setTimeout(() => {
506
+ const newItems = generateItems(5, this.currentId);
507
+ this.displayedItems = [...this.displayedItems, ...newItems];
508
+ this.currentId += 5;
509
+
510
+ if (this.displayedItems.length >= 50) {
511
+ this.hasMore = false;
512
+ }
513
+
514
+ this.isLoadingMore = false;
515
+ }, 1000);
516
+ },
517
+ },
518
+ template: `
519
+ <UnnnicDataTable
520
+ v-bind="args"
521
+ :headers="args.headers"
522
+ :items="displayedItems"
523
+ :infiniteScroll="true"
524
+ :infiniteScrollDistance="50"
525
+ :infiniteScrollDisabled="!hasMore"
526
+ :isLoadingMore="isLoadingMore"
527
+ :hidePagination="true"
528
+ :fixedHeaders="true"
529
+ height="400px"
530
+ @loadMore="loadMore"
531
+ >
532
+ </UnnnicDataTable>
533
+ `,
534
+ }),
535
+ };
536
+
537
+ export const InfiniteScrollClickable = {
538
+ args: { headers },
539
+ render: (args) => ({
540
+ components: {
541
+ UnnnicDataTable,
542
+ },
543
+ data() {
544
+ return {
545
+ args,
546
+ currentId: 11,
547
+ displayedItems: generateItems(10, 1),
548
+ isLoadingMore: false,
549
+ };
550
+ },
551
+ methods: {
552
+ loadMore() {
553
+ action('loadMore')();
554
+ this.isLoadingMore = true;
555
+
556
+ setTimeout(() => {
557
+ const newItems = generateItems(5, this.currentId);
558
+ this.displayedItems = [...this.displayedItems, ...newItems];
559
+ this.currentId += 5;
560
+ this.isLoadingMore = false;
561
+ }, 1000);
562
+ },
563
+ itemClick(item) {
564
+ action('itemClick')(item);
565
+ },
566
+ },
567
+ template: `
568
+ <UnnnicDataTable
569
+ v-bind="args"
570
+ :headers="args.headers"
571
+ :items="displayedItems"
572
+ :infiniteScroll="true"
573
+ :infiniteScrollDistance="100"
574
+ :isLoadingMore="isLoadingMore"
575
+ :hidePagination="true"
576
+ :clickable="true"
577
+ height="400px"
578
+ @loadMore="loadMore"
579
+ @itemClick="itemClick"
580
+ >
581
+ </UnnnicDataTable>
582
+ `,
583
+ }),
584
+ };