sprintify-ui 0.0.178 → 0.0.180

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 (35) hide show
  1. package/dist/sprintify-ui.es.js +8880 -8644
  2. package/dist/style.css +1 -1
  3. package/dist/types/src/components/BaseDataIterator.vue.d.ts +52 -13
  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} +6 -40
  7. package/dist/types/src/components/BaseDataIteratorSectionModal.vue.d.ts +29 -0
  8. package/dist/types/src/components/BaseDataTable.vue.d.ts +71 -17
  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 +2 -17
  13. package/dist/types/src/components/BaseTableColumn.vue.d.ts +10 -0
  14. package/dist/types/src/index.d.ts +12 -0
  15. package/dist/types/src/types/index.d.ts +15 -0
  16. package/package.json +9 -9
  17. package/src/assets/main.css +23 -0
  18. package/src/components/BaseActionItem.vue +3 -1
  19. package/src/components/BaseDataIterator.vue +126 -87
  20. package/src/components/BaseDataIteratorSectionBox.vue +33 -0
  21. package/src/components/BaseDataIteratorSectionButton.vue +34 -0
  22. package/src/components/{BaseDataTableToggleColumns.vue → BaseDataIteratorSectionColumns.vue} +3 -3
  23. package/src/components/BaseDataIteratorSectionModal.vue +41 -0
  24. package/src/components/BaseDataTable.stories.js +73 -17
  25. package/src/components/BaseDataTable.vue +239 -79
  26. package/src/components/BaseDataTableRowAction.vue +28 -0
  27. package/src/components/BaseFieldI18n.stories.js +1 -1
  28. package/src/components/BaseMediaLibrary.stories.js +1 -1
  29. package/src/components/BaseMenu.vue +7 -0
  30. package/src/components/BaseMenuItem.vue +17 -1
  31. package/src/components/BaseTable.vue +165 -112
  32. package/src/components/BaseTableColumn.vue +5 -0
  33. package/src/lang/en.json +3 -0
  34. package/src/lang/fr.json +3 -0
  35. package/src/types/index.ts +17 -0
@@ -7,6 +7,8 @@
7
7
  :searchable="searchable"
8
8
  :actions="actions"
9
9
  :history-mode="historyMode"
10
+ :layout="layout"
11
+ :sections="sectionsInternal"
10
12
  >
11
13
  <template
12
14
  #default="{
@@ -20,25 +22,61 @@
20
22
  }"
21
23
  >
22
24
  <BaseCard clipped class="w-full overflow-hidden">
25
+ <div v-if="newCheckedRows.length">
26
+ <div
27
+ class="flex items-center justify-between border-b border-slate-200 bg-slate-50 py-2 pl-3 pr-2 text-sm"
28
+ >
29
+ <div>
30
+ <span class="mr-3 text-slate-500"
31
+ >{{
32
+ $t('sui.x_rows_selected', {
33
+ count: newCheckedRows.length,
34
+ })
35
+ }}.</span
36
+ >
37
+ <button
38
+ type="button"
39
+ class="mr-3 inline text-slate-700 underline"
40
+ @click="uncheckAll()"
41
+ >
42
+ {{ $t('sui.deselect_all') }}
43
+ </button>
44
+ </div>
45
+ <BaseMenu
46
+ v-if="checkableActions?.length"
47
+ menu-class="w-52"
48
+ :items="checkableActions"
49
+ >
50
+ <template #button="{ open }">
51
+ <div
52
+ class="flex h-10 w-10 items-center justify-center rounded-full border border-slate-300 bg-white duration-150 hover:bg-slate-50"
53
+ :class="[
54
+ open ? 'ring-2 ring-primary-500 ring-offset-2' : false,
55
+ ]"
56
+ >
57
+ <BaseIcon icon="heroicons-solid:dots-vertical" />
58
+ </div>
59
+ </template>
60
+ </BaseMenu>
61
+ </div>
62
+ </div>
63
+
23
64
  <BaseTable
24
65
  ref="table"
66
+ :checked-rows="newCheckedRows"
25
67
  :data="items"
26
68
  :loading="loading"
27
69
  :detailed="detailed"
28
70
  :has-detailed-visible="hasDetailedVisible"
29
71
  :checkable="checkable"
30
- :checkable-actions="checkableActions"
31
- :checked-rows="checkedRows"
32
72
  :is-row-checkable="isRowCheckable"
33
73
  checkbox-position="left"
34
74
  :sort-field="sortField"
35
75
  :sort-direction="sortDirection"
36
76
  :max-height="maxHeight"
37
77
  :visible-columns="visibleColumns"
78
+ @update:checked-rows="onCheckedRowsUpdate"
38
79
  @sort="onSortChange"
39
- @check="$emit('check', $event)"
40
- @update:checked-rows="$emit('update:checked-rows', $event)"
41
- @check-all="$emit('checkAll', $event)"
42
80
  @cell-click="onCellClick"
43
81
  >
44
82
  <template #default>
@@ -50,35 +88,40 @@
50
88
  :toggle="false"
51
89
  :clickable="false"
52
90
  custom-key="actions"
91
+ class="overflow-hidden"
53
92
  >
54
- <div class="flex justify-end text-right">
93
+ <div class="flex justify-end gap-1 pr-2 text-right">
55
94
  <slot name="rowActions" :row="row" />
56
95
 
57
- <router-link
58
- v-if="editButton && editUrl"
59
- :to="editUrl(row)"
60
- :disabled="!canUpdate(row)"
61
- >
62
- <button class="btn btn-white bg-transparent p-2">
63
- <BaseIcon
64
- icon="heroicons:cog-6-tooth-solid"
65
- class="text-slate-500"
66
- />
67
- </button>
68
- </router-link>
69
-
70
- <button
71
- v-if="deleteButton && deleteUrl"
72
- type="button"
73
- class="btn btn-white bg-transparent p-2"
74
- :disabled="!canDelete(row)"
75
- @click="onDeleteClick(row)"
76
- >
77
- <BaseIcon
78
- icon="heroicons:trash-solid"
79
- class="text-slate-500"
80
- />
81
- </button>
96
+ <div class="btn-group">
97
+ <template
98
+ v-for="rowAction in visibleRowActions"
99
+ :key="rowAction.icon"
100
+ >
101
+ <BaseDataTableRowAction
102
+ :row="row"
103
+ :row-action="rowAction"
104
+ ></BaseDataTableRowAction>
105
+ </template>
106
+ <BaseMenu
107
+ v-if="showRowActionMenu"
108
+ :items="rowActionMenuItems(row)"
109
+ size="sm"
110
+ >
111
+ <template #button="{ open }">
112
+ <div
113
+ 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"
114
+ :class="[
115
+ open
116
+ ? 'ring-2 ring-primary-500 ring-offset-2'
117
+ : false,
118
+ ]"
119
+ >
120
+ <BaseIcon icon="heroicons-solid:dots-vertical" />
121
+ </div>
122
+ </template>
123
+ </BaseMenu>
124
+ </div>
82
125
  </div>
83
126
  </BaseTableColumn>
84
127
  </template>
@@ -136,60 +179,50 @@
136
179
  <slot name="sidebarTop" v-bind="sidebarProps"></slot>
137
180
  </template>
138
181
 
139
- <template v-if="toggleable" #sidebarBottom>
140
- <div class="mb-3">
141
- <BaseCard>
142
- <BaseCardRow size="sm">
143
- <button
144
- type="button"
145
- class="flex w-full items-center justify-between"
146
- @click="showColumnsDesktop = !showColumnsDesktop"
147
- >
148
- <h2 class="font-semibold">
149
- {{ $t('sui.columns') }}
150
- </h2>
151
-
152
- <BaseIcon
153
- :icon="
154
- showColumnsDesktop
155
- ? 'heroicons:chevron-down'
156
- : 'heroicons:chevron-up'
157
- "
158
- ></BaseIcon>
159
- </button>
160
-
161
- <div v-show="showColumnsDesktop" class="mt-4">
162
- <BaseDataTableToggleColumns
163
- v-model:visibleColumns="visibleColumns"
164
- :table="table"
165
- @update:visible-columns="onUpdateVisibleColumn"
166
- ></BaseDataTableToggleColumns>
167
- </div>
168
- </BaseCardRow>
169
- </BaseCard>
170
- </div>
182
+ <template #sidebarBottom="sidebarProps">
183
+ <slot name="sidebarBottom" v-bind="sidebarProps"></slot>
184
+ </template>
185
+
186
+ <template v-if="toggleable" #columns>
187
+ <BaseDataIteratorSectionColumns
188
+ v-model:visibleColumns="visibleColumns"
189
+ :table="table"
190
+ @update:visible-columns="onUpdateVisibleColumn"
191
+ ></BaseDataIteratorSectionColumns>
192
+ </template>
193
+
194
+ <template v-for="section in sections" :key="section.name" #[section.name]>
195
+ <slot :name="section.name" />
171
196
  </template>
172
197
  </BaseDataIterator>
173
198
  </template>
174
199
 
175
200
  <script lang="ts" setup>
176
201
  import { PropType } from 'vue';
177
- import { CollectionItem, DataTableQuery, MenuItemInterface } from '@/types';
202
+ import {
203
+ CollectionItem,
204
+ DataIteratorSection,
205
+ DataTableQuery,
206
+ MenuItemInterface,
207
+ RowAction,
208
+ } from '@/types';
178
209
  import { useDialogsStore } from '@/stores/dialogs';
179
210
  import { useNotificationsStore } from '../stores/notifications';
180
211
  import BaseDataIterator from './BaseDataIterator.vue';
181
- import { isArray } from 'lodash';
212
+ import { cloneDeep, isArray } from 'lodash';
182
213
 
183
214
  import BaseCard from './BaseCard.vue';
184
- import BaseCardRow from './BaseCardRow.vue';
185
215
  import BaseTable from './BaseTable.vue';
186
216
  import BaseTableColumn from './BaseTableColumn.vue';
187
- import BaseDataTableToggleColumns from './BaseDataTableToggleColumns.vue';
188
- import { config } from '@/index';
217
+ import BaseDataIteratorSectionColumns from './BaseDataIteratorSectionColumns.vue';
218
+ import { BaseIcon, config } from '@/index';
189
219
  import BaseEmptyState from '../svg/BaseEmptyState.vue';
190
220
  import { RouteLocationRaw } from 'vue-router';
221
+ import BaseMenu from './BaseMenu.vue';
222
+ import BaseDataTableRowAction from './BaseDataTableRowAction.vue';
191
223
 
192
224
  const i18n = useI18n();
225
+ const router = useRouter();
193
226
 
194
227
  const http = config.http;
195
228
 
@@ -224,6 +257,16 @@ const props = defineProps({
224
257
  type: Object as PropType<DataTableQuery>,
225
258
  },
226
259
 
260
+ /**
261
+ * Show url for router link
262
+ */
263
+ showUrl: {
264
+ default: undefined,
265
+ type: Function as PropType<
266
+ ((row: CollectionItem) => RouteLocationRaw) | undefined
267
+ >,
268
+ },
269
+
227
270
  /**
228
271
  * Show/Hide edit button
229
272
  */
@@ -237,7 +280,9 @@ const props = defineProps({
237
280
  */
238
281
  editUrl: {
239
282
  default: undefined,
240
- type: Function as PropType<(row: CollectionItem) => RouteLocationRaw>,
283
+ type: Function as PropType<
284
+ ((row: CollectionItem) => RouteLocationRaw) | undefined
285
+ >,
241
286
  },
242
287
 
243
288
  /**
@@ -253,7 +298,7 @@ const props = defineProps({
253
298
  */
254
299
  deleteUrl: {
255
300
  default: undefined,
256
- type: Function as PropType<(row: CollectionItem) => string>,
301
+ type: Function as PropType<((row: CollectionItem) => string) | undefined>,
257
302
  },
258
303
 
259
304
  /**
@@ -349,15 +394,32 @@ const props = defineProps({
349
394
  default: undefined,
350
395
  type: Number,
351
396
  },
397
+
398
+ /**
399
+ * Layout type
400
+ */
401
+ layout: {
402
+ default: 'default',
403
+ type: String as PropType<'default' | 'compact'>,
404
+ },
405
+
406
+ sections: {
407
+ default: undefined,
408
+ type: Array as PropType<DataIteratorSection[]>,
409
+ },
410
+
411
+ rowActions: {
412
+ default: undefined,
413
+ type: Array as PropType<RowAction[]>,
414
+ },
415
+
416
+ numberOfVisibleRowActions: {
417
+ default: 2,
418
+ type: Number,
419
+ },
352
420
  });
353
421
 
354
- const emit = defineEmits([
355
- 'cell-click',
356
- 'delete',
357
- 'checkAll',
358
- 'update:checked-rows',
359
- 'check',
360
- ]);
422
+ const emit = defineEmits(['cell-click', 'delete', 'update:checked-rows']);
361
423
 
362
424
  const dataIterator = ref<null | InstanceType<typeof BaseDataIterator>>(null);
363
425
 
@@ -368,6 +430,9 @@ const dataIterator = ref<null | InstanceType<typeof BaseDataIterator>>(null);
368
430
  */
369
431
 
370
432
  function onCellClick(payload: CollectionItem) {
433
+ if (props.showUrl) {
434
+ router.push(props.showUrl(payload));
435
+ }
371
436
  emit('cell-click', payload);
372
437
  }
373
438
 
@@ -438,8 +503,6 @@ const onDelete = (row: CollectionItem) => {
438
503
  |--------------------------------------------------------------------------
439
504
  */
440
505
 
441
- const showColumnsDesktop = ref<boolean>(false);
442
-
443
506
  const visibleColumns = ref<number[]>([]);
444
507
 
445
508
  // Find visible columns in local storage
@@ -487,6 +550,103 @@ function onUpdateVisibleColumn() {
487
550
  );
488
551
  }
489
552
 
553
+ /*
554
+ |--------------------------------------------------------------------------
555
+ | Row Actions
556
+ |--------------------------------------------------------------------------
557
+ */
558
+
559
+ const rowActionsInternal = computed<RowAction[]>(() => {
560
+ const actions = cloneDeep(props.rowActions) ?? [];
561
+
562
+ if (props.editUrl && props.editButton) {
563
+ actions.push({
564
+ label: i18n.t('sui.edit'),
565
+ icon: 'heroicons:cog-6-tooth-solid',
566
+ to: (row: CollectionItem) => (props.editUrl ? props.editUrl(row) : ''),
567
+ disabled: (row: CollectionItem) => !canUpdate(row),
568
+ });
569
+ }
570
+
571
+ if (props.deleteUrl && props.deleteButton) {
572
+ actions.push({
573
+ label: i18n.t('sui.delete'),
574
+ icon: 'heroicons:trash-20-solid',
575
+ action: onDeleteClick,
576
+ disabled: (row: CollectionItem) => !canDelete(row),
577
+ });
578
+ }
579
+
580
+ return actions;
581
+ });
582
+
583
+ const visibleRowActions = computed<RowAction[]>(() => {
584
+ return rowActionsInternal.value.slice(0, props.numberOfVisibleRowActions);
585
+ });
586
+
587
+ const showRowActionMenu = computed<boolean>(() => {
588
+ return rowActionsInternal.value.length > props.numberOfVisibleRowActions;
589
+ });
590
+
591
+ function rowActionMenuItems(row: CollectionItem): MenuItemInterface[] {
592
+ return rowActionsInternal.value.map((action) => {
593
+ return {
594
+ label: action.label,
595
+ icon: action.icon,
596
+ disabled: action.disabled && action.disabled(row),
597
+ action: action.action
598
+ ? () => {
599
+ if (action.action) action.action(row);
600
+ }
601
+ : undefined,
602
+ to: action.to ? action.to(row) : undefined,
603
+ };
604
+ });
605
+ }
606
+
607
+ /*
608
+ |--------------------------------------------------------------------------
609
+ | Checkable
610
+ |--------------------------------------------------------------------------
611
+ */
612
+
613
+ const newCheckedRows = ref<Record<string, any>[]>([]);
614
+
615
+ watch(
616
+ () => props.checkedRows,
617
+ (checkedRows) => {
618
+ newCheckedRows.value = checkedRows;
619
+ }
620
+ );
621
+
622
+ function uncheckAll() {
623
+ table.value?.uncheckAll();
624
+ }
625
+
626
+ const sectionsInternal = computed<DataIteratorSection[]>(() => {
627
+ const sections = props.sections ?? [];
628
+
629
+ if (props.toggleable) {
630
+ return [
631
+ ...sections,
632
+ {
633
+ name: 'columns',
634
+ icon: 'heroicons:table-cells-20-solid',
635
+ title: i18n.t('sui.columns'),
636
+ closeText: i18n.t('sui.apply'),
637
+ opened: false,
638
+ },
639
+ ];
640
+ }
641
+
642
+ return sections;
643
+ });
644
+
645
+ function onCheckedRowsUpdate(checkedRows: Record<string, any>[]) {
646
+ newCheckedRows.value = checkedRows;
647
+ emit('update:checked-rows', checkedRows);
648
+ }
649
+
490
650
  /*
491
651
  |--------------------------------------------------------------------------
492
652
  | 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>
@@ -9,7 +9,7 @@ export default {
9
9
  (story) => ({
10
10
  components: { story, BaseForm },
11
11
  template: `
12
- <BaseForm method="post" url="https://api.com/todos/422" :data="{}">
12
+ <BaseForm method="post" url="https://faker.witify.io/api/todos/422" :data="{}">
13
13
  <story/>
14
14
  <button type="submit" class="btn btn-primary mt-5">Submit</button>
15
15
  </BaseForm>`,
@@ -17,7 +17,7 @@ export default {
17
17
  max: null,
18
18
  min: 2,
19
19
  acceptedExtensions: ['jpg', 'png'],
20
- uploadUrl: 'https://api.com/upload',
20
+ uploadUrl: 'https://faker.witify.io/upload',
21
21
  maxSize: 500 * 1024,
22
22
  currentMedia: [
23
23
  mediaModel,
@@ -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';