sprintify-ui 0.0.179 → 0.0.181

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.
Files changed (31) hide show
  1. package/dist/sprintify-ui.es.js +6896 -6710
  2. package/dist/style.css +1 -1
  3. package/dist/types/src/components/BaseDataIterator.vue.d.ts +69 -14
  4. package/dist/types/src/components/BaseDataIteratorSectionBox.vue.d.ts +23 -0
  5. package/dist/types/src/components/BaseDataIteratorSectionButton.vue.d.ts +20 -0
  6. package/dist/types/src/components/{BaseDataTableToggleColumns.vue.d.ts → BaseDataIteratorSectionColumns.vue.d.ts} +10 -40
  7. package/dist/types/src/components/BaseDataIteratorSectionModal.vue.d.ts +29 -0
  8. package/dist/types/src/components/BaseDataTable.vue.d.ts +65 -11
  9. package/dist/types/src/components/BaseDataTableRowAction.vue.d.ts +18 -0
  10. package/dist/types/src/components/BaseMenu.vue.d.ts +9 -0
  11. package/dist/types/src/components/BaseMenuItem.vue.d.ts +9 -0
  12. package/dist/types/src/components/BaseTable.vue.d.ts +3 -17
  13. package/dist/types/src/index.d.ts +12 -0
  14. package/dist/types/src/types/index.d.ts +15 -0
  15. package/package.json +1 -1
  16. package/src/assets/main.css +23 -0
  17. package/src/components/BaseActionItem.vue +3 -1
  18. package/src/components/BaseDataIterator.vue +135 -81
  19. package/src/components/BaseDataIteratorSectionBox.vue +33 -0
  20. package/src/components/BaseDataIteratorSectionButton.vue +34 -0
  21. package/src/components/{BaseDataTableToggleColumns.vue → BaseDataIteratorSectionColumns.vue} +3 -3
  22. package/src/components/BaseDataIteratorSectionModal.vue +41 -0
  23. package/src/components/BaseDataTable.stories.js +45 -14
  24. package/src/components/BaseDataTable.vue +251 -78
  25. package/src/components/BaseDataTableRowAction.vue +28 -0
  26. package/src/components/BaseMenu.vue +7 -0
  27. package/src/components/BaseMenuItem.vue +17 -1
  28. package/src/components/BaseTable.vue +44 -85
  29. package/src/lang/en.json +3 -0
  30. package/src/lang/fr.json +3 -0
  31. package/src/types/index.ts +17 -0
@@ -7,6 +7,10 @@
7
7
  :searchable="searchable"
8
8
  :actions="actions"
9
9
  :history-mode="historyMode"
10
+ :layout="layout"
11
+ :sections="sectionsInternal"
12
+ :scroll-top-on-fetch="maxHeight ? false : scrollTopOnFetch"
13
+ @will-scroll-top="onWillScrollTop"
10
14
  >
11
15
  <template
12
16
  #default="{
@@ -20,25 +24,61 @@
20
24
  }"
21
25
  >
22
26
  <BaseCard clipped class="w-full overflow-hidden">
27
+ <div v-if="newCheckedRows.length">
28
+ <div
29
+ class="flex items-center justify-between border-b border-slate-200 bg-slate-50 py-2 pl-3 pr-2 text-sm"
30
+ >
31
+ <div>
32
+ <span class="mr-3 text-slate-500"
33
+ >{{
34
+ $t('sui.x_rows_selected', {
35
+ count: newCheckedRows.length,
36
+ })
37
+ }}.</span
38
+ >
39
+ <button
40
+ type="button"
41
+ class="mr-3 inline text-slate-700 underline"
42
+ @click="uncheckAll()"
43
+ >
44
+ {{ $t('sui.deselect_all') }}
45
+ </button>
46
+ </div>
47
+ <BaseMenu
48
+ v-if="checkableActions?.length"
49
+ menu-class="w-52"
50
+ :items="checkableActions"
51
+ >
52
+ <template #button="{ open }">
53
+ <div
54
+ class="flex h-10 w-10 items-center justify-center rounded-full border border-slate-300 bg-white duration-150 hover:bg-slate-50"
55
+ :class="[
56
+ open ? 'ring-2 ring-primary-500 ring-offset-2' : false,
57
+ ]"
58
+ >
59
+ <BaseIcon icon="heroicons-solid:dots-vertical" />
60
+ </div>
61
+ </template>
62
+ </BaseMenu>
63
+ </div>
64
+ </div>
65
+
23
66
  <BaseTable
24
67
  ref="table"
68
+ :checked-rows="newCheckedRows"
25
69
  :data="items"
26
70
  :loading="loading"
27
71
  :detailed="detailed"
28
72
  :has-detailed-visible="hasDetailedVisible"
29
73
  :checkable="checkable"
30
- :checkable-actions="checkableActions"
31
- :checked-rows="checkedRows"
32
74
  :is-row-checkable="isRowCheckable"
33
75
  checkbox-position="left"
34
76
  :sort-field="sortField"
35
77
  :sort-direction="sortDirection"
36
78
  :max-height="maxHeight"
37
79
  :visible-columns="visibleColumns"
80
+ @update:checked-rows="onCheckedRowsUpdate"
38
81
  @sort="onSortChange"
39
- @check="$emit('check', $event)"
40
- @update:checked-rows="$emit('update:checked-rows', $event)"
41
- @check-all="$emit('checkAll', $event)"
42
82
  @cell-click="onCellClick"
43
83
  >
44
84
  <template #default>
@@ -52,36 +92,38 @@
52
92
  custom-key="actions"
53
93
  class="overflow-hidden"
54
94
  >
55
- <div class="flex justify-end gap-1 text-right">
95
+ <div class="flex justify-end gap-1 pr-2 text-right">
56
96
  <slot name="rowActions" :row="row" />
57
97
 
58
- <router-link
59
- v-if="editButton && editUrl"
60
- :to="editUrl(row)"
61
- :disabled="!canUpdate(row)"
62
- >
63
- <button
64
- class="btn btn-white border border-slate-300 p-2 shadow-sm"
98
+ <div class="btn-group">
99
+ <template
100
+ v-for="rowAction in visibleRowActions"
101
+ :key="rowAction.icon"
65
102
  >
66
- <BaseIcon
67
- icon="heroicons:cog-6-tooth-solid"
68
- class="text-slate-500"
69
- />
70
- </button>
71
- </router-link>
72
-
73
- <button
74
- v-if="deleteButton && deleteUrl"
75
- type="button"
76
- class="btn btn-white border border-slate-300 p-2 shadow-sm"
77
- :disabled="!canDelete(row)"
78
- @click="onDeleteClick(row)"
79
- >
80
- <BaseIcon
81
- icon="heroicons:trash-solid"
82
- class="text-slate-500"
83
- />
84
- </button>
103
+ <BaseDataTableRowAction
104
+ :row="row"
105
+ :row-action="rowAction"
106
+ ></BaseDataTableRowAction>
107
+ </template>
108
+ <BaseMenu
109
+ v-if="showRowActionMenu"
110
+ :items="rowActionMenuItems(row)"
111
+ size="sm"
112
+ >
113
+ <template #button="{ open }">
114
+ <div
115
+ class="flex h-8 w-8 items-center justify-center rounded-r border border-l-0 border-slate-300 bg-white duration-150 hover:bg-slate-50"
116
+ :class="[
117
+ open
118
+ ? 'ring-2 ring-primary-500 ring-offset-2'
119
+ : false,
120
+ ]"
121
+ >
122
+ <BaseIcon icon="heroicons-solid:dots-vertical" />
123
+ </div>
124
+ </template>
125
+ </BaseMenu>
126
+ </div>
85
127
  </div>
86
128
  </BaseTableColumn>
87
129
  </template>
@@ -139,58 +181,47 @@
139
181
  <slot name="sidebarTop" v-bind="sidebarProps"></slot>
140
182
  </template>
141
183
 
142
- <template v-if="toggleable" #sidebarBottom>
143
- <div class="mb-3">
144
- <BaseCard>
145
- <BaseCardRow size="sm">
146
- <button
147
- type="button"
148
- class="flex w-full items-center justify-between"
149
- @click="showColumnsDesktop = !showColumnsDesktop"
150
- >
151
- <h2 class="font-semibold">
152
- {{ $t('sui.columns') }}
153
- </h2>
154
-
155
- <BaseIcon
156
- :icon="
157
- showColumnsDesktop
158
- ? 'heroicons:chevron-down'
159
- : 'heroicons:chevron-up'
160
- "
161
- ></BaseIcon>
162
- </button>
163
-
164
- <div v-show="showColumnsDesktop" class="mt-4">
165
- <BaseDataTableToggleColumns
166
- v-model:visibleColumns="visibleColumns"
167
- :table="table"
168
- @update:visible-columns="onUpdateVisibleColumn"
169
- ></BaseDataTableToggleColumns>
170
- </div>
171
- </BaseCardRow>
172
- </BaseCard>
173
- </div>
184
+ <template #sidebarBottom="sidebarProps">
185
+ <slot name="sidebarBottom" v-bind="sidebarProps"></slot>
186
+ </template>
187
+
188
+ <template v-if="toggleable" #columns>
189
+ <BaseDataIteratorSectionColumns
190
+ v-model:visibleColumns="visibleColumns"
191
+ :table="table"
192
+ @update:visible-columns="onUpdateVisibleColumn"
193
+ ></BaseDataIteratorSectionColumns>
194
+ </template>
195
+
196
+ <template v-for="section in sections" :key="section.name" #[section.name]>
197
+ <slot :name="section.name" />
174
198
  </template>
175
199
  </BaseDataIterator>
176
200
  </template>
177
201
 
178
202
  <script lang="ts" setup>
179
203
  import { PropType } from 'vue';
180
- import { CollectionItem, DataTableQuery, MenuItemInterface } from '@/types';
204
+ import {
205
+ CollectionItem,
206
+ DataIteratorSection,
207
+ DataTableQuery,
208
+ MenuItemInterface,
209
+ RowAction,
210
+ } from '@/types';
181
211
  import { useDialogsStore } from '@/stores/dialogs';
182
212
  import { useNotificationsStore } from '../stores/notifications';
183
213
  import BaseDataIterator from './BaseDataIterator.vue';
184
- import { isArray } from 'lodash';
214
+ import { cloneDeep, isArray } from 'lodash';
185
215
 
186
216
  import BaseCard from './BaseCard.vue';
187
- import BaseCardRow from './BaseCardRow.vue';
188
217
  import BaseTable from './BaseTable.vue';
189
218
  import BaseTableColumn from './BaseTableColumn.vue';
190
- import BaseDataTableToggleColumns from './BaseDataTableToggleColumns.vue';
191
- import { config } from '@/index';
219
+ import BaseDataIteratorSectionColumns from './BaseDataIteratorSectionColumns.vue';
220
+ import { BaseIcon, config } from '@/index';
192
221
  import BaseEmptyState from '../svg/BaseEmptyState.vue';
193
222
  import { RouteLocationRaw } from 'vue-router';
223
+ import BaseMenu from './BaseMenu.vue';
224
+ import BaseDataTableRowAction from './BaseDataTableRowAction.vue';
194
225
 
195
226
  const i18n = useI18n();
196
227
  const router = useRouter();
@@ -365,15 +396,40 @@ const props = defineProps({
365
396
  default: undefined,
366
397
  type: Number,
367
398
  },
399
+
400
+ /**
401
+ * Layout type
402
+ */
403
+ layout: {
404
+ default: 'default',
405
+ type: String as PropType<'default' | 'compact'>,
406
+ },
407
+
408
+ sections: {
409
+ default: undefined,
410
+ type: Array as PropType<DataIteratorSection[]>,
411
+ },
412
+
413
+ rowActions: {
414
+ default: undefined,
415
+ type: Array as PropType<RowAction[]>,
416
+ },
417
+
418
+ numberOfVisibleRowActions: {
419
+ default: 2,
420
+ type: Number,
421
+ },
422
+
423
+ /**
424
+ * Scroll to top when fetching new data
425
+ */
426
+ scrollTopOnFetch: {
427
+ default: true,
428
+ type: Boolean,
429
+ },
368
430
  });
369
431
 
370
- const emit = defineEmits([
371
- 'cell-click',
372
- 'delete',
373
- 'checkAll',
374
- 'update:checked-rows',
375
- 'check',
376
- ]);
432
+ const emit = defineEmits(['cell-click', 'delete', 'update:checked-rows']);
377
433
 
378
434
  const dataIterator = ref<null | InstanceType<typeof BaseDataIterator>>(null);
379
435
 
@@ -457,8 +513,6 @@ const onDelete = (row: CollectionItem) => {
457
513
  |--------------------------------------------------------------------------
458
514
  */
459
515
 
460
- const showColumnsDesktop = ref<boolean>(false);
461
-
462
516
  const visibleColumns = ref<number[]>([]);
463
517
 
464
518
  // Find visible columns in local storage
@@ -506,6 +560,125 @@ function onUpdateVisibleColumn() {
506
560
  );
507
561
  }
508
562
 
563
+ /*
564
+ |--------------------------------------------------------------------------
565
+ | Row Actions
566
+ |--------------------------------------------------------------------------
567
+ */
568
+
569
+ const rowActionsInternal = computed<RowAction[]>(() => {
570
+ const actions = cloneDeep(props.rowActions) ?? [];
571
+
572
+ if (props.editUrl && props.editButton) {
573
+ actions.push({
574
+ label: i18n.t('sui.edit'),
575
+ icon: 'heroicons:cog-6-tooth-solid',
576
+ to: (row: CollectionItem) => (props.editUrl ? props.editUrl(row) : ''),
577
+ disabled: (row: CollectionItem) => !canUpdate(row),
578
+ });
579
+ }
580
+
581
+ if (props.deleteUrl && props.deleteButton) {
582
+ actions.push({
583
+ label: i18n.t('sui.delete'),
584
+ icon: 'heroicons:trash-20-solid',
585
+ action: onDeleteClick,
586
+ disabled: (row: CollectionItem) => !canDelete(row),
587
+ });
588
+ }
589
+
590
+ return actions;
591
+ });
592
+
593
+ const visibleRowActions = computed<RowAction[]>(() => {
594
+ return rowActionsInternal.value.slice(0, props.numberOfVisibleRowActions);
595
+ });
596
+
597
+ const showRowActionMenu = computed<boolean>(() => {
598
+ return rowActionsInternal.value.length > props.numberOfVisibleRowActions;
599
+ });
600
+
601
+ function rowActionMenuItems(row: CollectionItem): MenuItemInterface[] {
602
+ return rowActionsInternal.value.map((action) => {
603
+ return {
604
+ label: action.label,
605
+ icon: action.icon,
606
+ disabled: action.disabled && action.disabled(row),
607
+ action: action.action
608
+ ? () => {
609
+ if (action.action) action.action(row);
610
+ }
611
+ : undefined,
612
+ to: action.to ? action.to(row) : undefined,
613
+ };
614
+ });
615
+ }
616
+
617
+ /*
618
+ |--------------------------------------------------------------------------
619
+ | Checkable
620
+ |--------------------------------------------------------------------------
621
+ */
622
+
623
+ const newCheckedRows = ref<Record<string, any>[]>([]);
624
+
625
+ watch(
626
+ () => props.checkedRows,
627
+ (checkedRows) => {
628
+ newCheckedRows.value = checkedRows;
629
+ }
630
+ );
631
+
632
+ function uncheckAll() {
633
+ table.value?.uncheckAll();
634
+ }
635
+
636
+ const sectionsInternal = computed<DataIteratorSection[]>(() => {
637
+ const sections = props.sections ?? [];
638
+
639
+ if (props.toggleable) {
640
+ return [
641
+ ...sections,
642
+ {
643
+ name: 'columns',
644
+ icon: 'heroicons:table-cells-20-solid',
645
+ title: i18n.t('sui.columns'),
646
+ closeText: i18n.t('sui.apply'),
647
+ opened: false,
648
+ },
649
+ ];
650
+ }
651
+
652
+ return sections;
653
+ });
654
+
655
+ function onCheckedRowsUpdate(checkedRows: Record<string, any>[]) {
656
+ newCheckedRows.value = checkedRows;
657
+ emit('update:checked-rows', checkedRows);
658
+ }
659
+
660
+ /*
661
+ |--------------------------------------------------------------------------
662
+ | Scrolling behavior
663
+ |--------------------------------------------------------------------------
664
+ */
665
+
666
+ function onWillScrollTop() {
667
+ if (!props.scrollTopOnFetch) {
668
+ return;
669
+ }
670
+
671
+ if (props.maxHeight) {
672
+ table.value?.scrollTop();
673
+
674
+ const top = dataIterator.value?.$el?.getBoundingClientRect()?.top ?? 0;
675
+
676
+ if (top < 0) {
677
+ dataIterator.value?.scrollIntoView();
678
+ }
679
+ }
680
+ }
681
+
509
682
  /*
510
683
  |--------------------------------------------------------------------------
511
684
  | Exposed functions
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <button
3
+ v-if="rowAction.action"
4
+ type="button"
5
+ class="btn btn-white border border-slate-300 p-2 shadow-sm"
6
+ :disabled="rowAction.disabled && rowAction.disabled(row)"
7
+ @click="rowAction.action ? rowAction.action(row) : null"
8
+ >
9
+ <BaseIcon :icon="rowAction.icon" class="text-slate-500" />
10
+ </button>
11
+ <router-link
12
+ v-else-if="rowAction.to"
13
+ :to="rowAction.to(row)"
14
+ :disabled="rowAction.disabled && rowAction.disabled(row)"
15
+ class="btn btn-white border border-slate-300 p-2 shadow-sm hover:bg-slate-100"
16
+ >
17
+ <BaseIcon :icon="rowAction.icon" class="text-slate-500" />
18
+ </router-link>
19
+ </template>
20
+
21
+ <script lang="ts" setup>
22
+ import { CollectionItem, RowAction } from '@/types';
23
+
24
+ defineProps<{
25
+ row: CollectionItem;
26
+ rowAction: RowAction;
27
+ }>();
28
+ </script>
@@ -46,6 +46,7 @@
46
46
  :icon="item.icon"
47
47
  :color="item.color"
48
48
  :active="active"
49
+ :size="size"
49
50
  />
50
51
  </slot>
51
52
  </MenuItem>
@@ -64,6 +65,7 @@
64
65
  :icon="item.icon"
65
66
  :color="item.color"
66
67
  :active="active"
68
+ :size="size"
67
69
  />
68
70
  </slot>
69
71
  </MenuItem>
@@ -83,6 +85,7 @@
83
85
  :icon="item.icon"
84
86
  :color="item.color"
85
87
  :active="active"
88
+ :size="size"
86
89
  />
87
90
  </slot>
88
91
  </MenuItem>
@@ -112,6 +115,10 @@ const props = defineProps({
112
115
  default: 'bottom-left',
113
116
  type: String as PropType<'bottom-left' | 'bottom-right' | 'custom'>,
114
117
  },
118
+ size: {
119
+ default: 'sm',
120
+ type: String as PropType<'xs' | 'sm' | 'md'>,
121
+ },
115
122
  });
116
123
 
117
124
  const menuPositionClass = computed(() => {
@@ -2,7 +2,7 @@
2
2
  <div :class="buttonClasses">
3
3
  <div class="flex items-center">
4
4
  <BaseIcon v-if="icon" :icon="icon" :class="iconClasses" />
5
- {{ label }}
5
+ <span :class="textSize">{{ label }}</span>
6
6
  </div>
7
7
  <div v-if="count" class="relative -top-px ml-[5px]">
8
8
  <BaseCounter
@@ -41,6 +41,10 @@ const props = defineProps({
41
41
  'dark' | 'light' | 'danger' | 'success' | 'warning'
42
42
  >,
43
43
  },
44
+ size: {
45
+ default: 'md',
46
+ type: String as PropType<'xs' | 'sm' | 'md'>,
47
+ },
44
48
  });
45
49
 
46
50
  const textColor = computed((): string => {
@@ -59,6 +63,18 @@ const textColor = computed((): string => {
59
63
  return '';
60
64
  });
61
65
 
66
+ const textSize = computed((): string => {
67
+ if (props.size == 'xs') {
68
+ return 'text-xs';
69
+ } else if (props.size == 'sm') {
70
+ return 'text-sm';
71
+ } else if (props.size == 'md') {
72
+ return 'text-base';
73
+ }
74
+
75
+ return '';
76
+ });
77
+
62
78
  const buttonClasses = computed((): string => {
63
79
  let baseClasses =
64
80
  'flex items-center justify-between w-full leading-tight py-2 text-sm text-left rounded';