design-system-next 2.23.0 → 2.24.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.
Files changed (28) hide show
  1. package/dist/design-system-next.es.d.ts +28 -6
  2. package/dist/design-system-next.es.js +7544 -7332
  3. package/dist/design-system-next.es.js.gz +0 -0
  4. package/dist/design-system-next.umd.js +12 -12
  5. package/dist/design-system-next.umd.js.gz +0 -0
  6. package/dist/main.css +1 -1
  7. package/dist/main.css.gz +0 -0
  8. package/package.json +1 -1
  9. package/src/App.vue +89 -1
  10. package/src/components/date-picker/date-picker.vue +2 -2
  11. package/src/components/date-picker/use-date-picker.ts +41 -33
  12. package/src/components/dropdown/dropdown.ts +6 -2
  13. package/src/components/dropdown/dropdown.vue +8 -1
  14. package/src/components/dropdown/use-dropdown.ts +13 -0
  15. package/src/components/list/list-item/list-item.ts +60 -60
  16. package/src/components/radio-grouped/radio-grouped.ts +65 -65
  17. package/src/components/radio-grouped/use-radio-grouped.ts +62 -62
  18. package/src/components/sidepanel/sidepanel.ts +4 -0
  19. package/src/components/sidepanel/sidepanel.vue +3 -1
  20. package/src/components/sidepanel/use-sidepanel.ts +3 -2
  21. package/src/components/table/table-header-dropdown/table-header-dropdown.ts +48 -0
  22. package/src/components/table/table-header-dropdown/table-header-dropdown.vue +84 -0
  23. package/src/components/table/table-pagination/table-pagination.ts +4 -0
  24. package/src/components/table/table-pagination/table-pagination.vue +9 -1
  25. package/src/components/table/table-pagination/use-table-pagination.ts +4 -3
  26. package/src/components/table/table.ts +9 -1
  27. package/src/components/table/table.vue +17 -2
  28. package/src/components/table/use-table.ts +6 -1
@@ -104,6 +104,10 @@ export const sidepanelPropTypes = {
104
104
  isActivePanel: {
105
105
  type: Boolean,
106
106
  default: false
107
+ },
108
+ footerNoTopBorder: {
109
+ type: Boolean,
110
+ default: false,
107
111
  }
108
112
  };
109
113
 
@@ -17,6 +17,7 @@
17
17
  aria-labelledby="sidepanel-title"
18
18
  aria-describedby="sidepanel-content"
19
19
  :class="sidepanelClasses.sidepanelBaseClasses"
20
+ data-testid="sidepanel-dialog"
20
21
  :style="{ height: typeof height === 'number' ? `${height}px` : height }"
21
22
  >
22
23
  <template v-if="!props.hideHeader">
@@ -29,9 +30,10 @@
29
30
  v-if="props.isExpandable"
30
31
  :class="sidepanelClasses.sidepanelHeaderIconClasses"
31
32
  :icon="isExpanded ? 'ph:arrows-in-simple' : 'ph:arrows-out-simple'"
33
+ data-testid="expand-icon"
32
34
  @click="handlePanelExpansion"
33
35
  />
34
- <Icon :class="sidepanelClasses.sidepanelHeaderIconClasses" icon="ph:x" @click="handleClose" />
36
+ <Icon :class="sidepanelClasses.sidepanelHeaderIconClasses" icon="ph:x" data-testid="x-icon" @click="handleClose" />
35
37
  </div>
36
38
  </div>
37
39
  <div v-else>
@@ -19,7 +19,7 @@ interface SidepanelClasses {
19
19
  }
20
20
 
21
21
  export const useSidepanel = (props: SidepanelPropTypes, emit: SetupContext<SidepanelEmitTypes>['emit']) => {
22
- const { size, position, isStacking, footerNoPadding, isExpanded, isActivePanel } = toRefs(props);
22
+ const { size, position, isStacking, footerNoPadding, isExpanded, isActivePanel, footerNoTopBorder } = toRefs(props);
23
23
 
24
24
  const sidepanelClasses: ComputedRef<SidepanelClasses> = computed(() => {
25
25
  const sidepanelBaseClasses = classNames(
@@ -48,9 +48,10 @@ export const useSidepanel = (props: SidepanelPropTypes, emit: SetupContext<Sidep
48
48
  const sidepanelContentClasses = classNames('spr-h-full spr-overflow-y-auto');
49
49
 
50
50
  const sidepanelFooterClasses = classNames(
51
- 'spr-bottom-0 spr-left-0 spr-w-full spr-rounded-b-border-radius-xl spr-border-0 spr-border-t spr-border-solid spr-border-mushroom-200 spr-bg-white-50 ',
51
+ 'spr-bottom-0 spr-left-0 spr-w-full spr-rounded-b-border-radius-xl spr-border-0 spr-border-solid spr-border-mushroom-200 spr-bg-white-50 ',
52
52
  {
53
53
  'spr-py-3': !footerNoPadding.value,
54
+ 'spr-border-t': !footerNoTopBorder.value
54
55
  },
55
56
  );
56
57
 
@@ -0,0 +1,48 @@
1
+ import type { MenuListType } from '@/components/list/list';
2
+ import { type PropType, type ExtractPropTypes, ref } from 'vue';
3
+ import type { Header } from '../table';
4
+ export const definePropType = <T>(val: unknown): PropType<T> => val as PropType<T>;
5
+
6
+ const defaultSortOptions = ref([
7
+ { text: 'Sort Ascending', value: 'asc', icon: 'ph:sort-ascending', iconColor: 'spr-text-color-supporting' },
8
+ { text: 'Sort Descending', value: 'desc', icon: 'ph:sort-descending', iconColor: 'spr-text-color-supporting' },
9
+ ]);
10
+
11
+ export const tableHeaderDropdownPropTypes = {
12
+ id: {
13
+ type: String,
14
+ required: true,
15
+ },
16
+ header: {
17
+ type: Object as PropType<Header>,
18
+ default: () => ({}),
19
+ },
20
+ isSortable: {
21
+ type: Boolean,
22
+ default: true,
23
+ },
24
+ headerClasses: {
25
+ type: String,
26
+ default: '',
27
+ },
28
+ sortOptions: {
29
+ type: Array as PropType<MenuListType[]>,
30
+ default: () => defaultSortOptions.value,
31
+ },
32
+ };
33
+
34
+ export interface TableHeaderFilterType {
35
+ headerField: string;
36
+ sortBy: 'asc' | 'desc' | null;
37
+ appliedFilters: Record<string, string>;
38
+ };
39
+
40
+ export const tableHeaderDropdownEmitTypes = {
41
+ onApplyFilter: (filter: TableHeaderFilterType) => !!filter,
42
+ onSelectAll: () => true,
43
+ 'update:selectedSort': (selectedSort: MenuListType[]) => Array.isArray(selectedSort),
44
+ 'update:selectedFilters': (selectedFilters: MenuListType[]) => Array.isArray(selectedFilters),
45
+ };
46
+
47
+ export type TableHeaderDropdownPropTypes = ExtractPropTypes<typeof tableHeaderDropdownPropTypes>;
48
+ export type TableHeaderDropdownEmitTypes = typeof tableHeaderDropdownEmitTypes;
@@ -0,0 +1,84 @@
1
+ <template>
2
+ <spr-dropdown
3
+ :id="props.id"
4
+ ref="tableHeaderDropdown"
5
+ width="100%"
6
+ :triggers="[]"
7
+ :popper-triggers="['click']"
8
+ popper-width="448px"
9
+ no-padding
10
+ >
11
+ <div :class="props.headerClasses" @click="showDropdown">
12
+ <span> {{ props.header.name }} </span>
13
+ <span>
14
+ <Icon class="spr-text-[#4B685E] !spr-justify-normal" icon="ph:funnel-simple" height="20px" width="20px" />
15
+ </span>
16
+ </div>
17
+
18
+ <template #popper>
19
+ <spr-card class="spr-font-main" border-width="0px" :has-content-padding="false" show-header>
20
+ <template #header>
21
+ <div class="spr-w-full spr-border-0 spr-border-b spr-border-solid spr-border-color-weak spr-p-size-spacing-xs spr-flex spr-flex-row spr-justify-between spr-items-center">
22
+ <span class="spr-subheading-xs spr-capitalize">{{ props.header.name }}</span>
23
+ <spr-button size="small" variant="secondary" @click="selectAll">Select All</spr-button>
24
+ </div>
25
+ </template>
26
+ <template #content>
27
+ <div v-if="props.isSortable" class="spr-border-0 spr-border-b spr-border-solid spr-border-color-weak">
28
+ <spr-list v-model="selectedSort" class="spr-capitalize spr-body-sm-regular spr-text-color-strong [&_svg]:spr-w-[16px] [&_svg]:spr-h-[16px] [&_svg.spr-text-color-brand-base]:spr-hidden" :menu-list="props.sortOptions"/>
29
+ </div>
30
+ <div v-if="props.header.filterList && props.header.filterList.length > 0" >
31
+ <spr-list v-model="selectedFilters" class="spr-capitalize spr-body-sm-regular spr-text-color-strong [&_svg]:spr-w-[16px] [&_svg]:spr-h-[16px]" :menu-list="props.header.filterList" multi-select/>
32
+ </div>
33
+ </template>
34
+ <template #footer>
35
+ <div class="spr-ms-auto spr-flex spr-items-center spr-py-size-spacing-5xs">
36
+ <spr-button tone="success" @click="applyFilter">Apply Filter</spr-button>
37
+ </div>
38
+ </template>
39
+ </spr-card>
40
+ </template>
41
+ </spr-dropdown>
42
+ </template>
43
+
44
+ <script setup lang="ts">
45
+ import SprDropdown from '@/components/dropdown/dropdown.vue';
46
+ import SprCard from '@/components/card/card.vue';
47
+ import SprButton from '@/components/button/button.vue';
48
+ import SprList from '@/components/list/list.vue';
49
+ import Icon from '@/components/icon/icon.vue';
50
+ import {
51
+ tableHeaderDropdownEmitTypes,
52
+ tableHeaderDropdownPropTypes
53
+ } from './table-header-dropdown';
54
+ import { ref } from 'vue';
55
+ import { MenuListType } from '@/components/list/list';
56
+
57
+ const tableHeaderDropdown = ref<InstanceType<typeof SprDropdown> | null>(null);
58
+ const showDropdown = () => {
59
+ tableHeaderDropdown.value?.showDropdown();
60
+ };
61
+
62
+ const props = defineProps(tableHeaderDropdownPropTypes);
63
+ const emits = defineEmits(tableHeaderDropdownEmitTypes,);
64
+
65
+ const selectedSort = ref<MenuListType[]>([]);
66
+ const selectedFilters = ref<MenuListType[]>([]);
67
+
68
+ const applyFilter = () => {
69
+ emits('onApplyFilter', {
70
+ headerField: props.header.field,
71
+ sortBy: selectedSort.value[0] ? selectedSort.value[0].value as 'asc' | 'desc' | null : null,
72
+ appliedFilters: selectedFilters.value.reduce((acc, filter) => {
73
+ acc[filter.text] = filter.value as string;
74
+ return acc;
75
+ }, {} as Record<string, string>),
76
+ });
77
+ tableHeaderDropdown.value?.hideDropdown();
78
+ };
79
+
80
+ const selectAll = () => {
81
+ selectedFilters.value = props.header.filterList ? [...props.header.filterList] : [];
82
+ emits('onSelectAll');
83
+ };
84
+ </script>
@@ -58,6 +58,10 @@ export const tablePaginationPropTypes = {
58
58
  type: Boolean as PropType<boolean>,
59
59
  default: false,
60
60
  },
61
+ showNumberOfRowsDropdown: {
62
+ type: Boolean as PropType<boolean>,
63
+ default: true,
64
+ }
61
65
  };
62
66
 
63
67
  export const tablePaginationEmitTypes = {
@@ -1,6 +1,8 @@
1
1
  <template>
2
- <div :class="paginationClasses.baseClass">
2
+ <div :class="paginationClasses.baseClass" v-bind="$attrs">
3
+
3
4
  <spr-dropdown
5
+ v-if="showNumberOfRowsDropdown"
4
6
  :id="dropdownId"
5
7
  :menu-list="dropdownSelection"
6
8
  dropdown-type="single-select"
@@ -53,6 +55,9 @@
53
55
  </spr-button>
54
56
  </div>
55
57
  </div>
58
+ <div v-if="slots.actions" id="table_pagination_actions_slot">
59
+ <slot name="actions" />
60
+ </div>
56
61
  </div>
57
62
  </template>
58
63
 
@@ -65,8 +70,10 @@ import { useTablePagination } from './use-table-pagination';
65
70
  import SprInput from '@/components/input/input.vue';
66
71
  import SprButton from '@/components/button/button.vue';
67
72
  import SprDropdown from '@/components/dropdown/dropdown.vue';
73
+ import { useSlots } from 'vue';
68
74
 
69
75
  const emit = defineEmits(tablePaginationEmitTypes);
76
+ const slots = useSlots();
70
77
 
71
78
  const props = defineProps(tablePaginationPropTypes);
72
79
 
@@ -83,6 +90,7 @@ const {
83
90
  dropdownId,
84
91
  currentPage,
85
92
  totalPages,
93
+ showNumberOfRowsDropdown
86
94
  } = useTablePagination(props, emit);
87
95
  </script>
88
96
 
@@ -22,7 +22,7 @@ export const useTablePagination = (
22
22
  props: TablePaginationPropTypes,
23
23
  emit: SetupContext<TablePaginationEmitTypes>['emit'],
24
24
  ) => {
25
- const { selectedRowCount, totalItems, bordered, editableCurrentPage } = toRefs(props);
25
+ const { selectedRowCount, totalItems, bordered, editableCurrentPage, showNumberOfRowsDropdown } = toRefs(props);
26
26
 
27
27
  const currentPage = useVModel(props, 'currentPage', emit);
28
28
 
@@ -67,13 +67,13 @@ export const useTablePagination = (
67
67
  });
68
68
 
69
69
  const dropdownSelection = ref(props.dropdownSelection);
70
- const computeRowRange = computed(() => {
70
+ const computeRowRange = computed(() => {
71
71
  const startRow = (currentPage.value - 1) * selectedRowCount.value + 1;
72
72
  const endRow = Math.min(currentPage.value * selectedRowCount.value, totalItems.value);
73
73
  return `${startRow} - ${endRow} of ${totalItems.value}`;
74
74
  });
75
75
 
76
- const computeSelectedRowCount = computed(() => {
76
+ const computeSelectedRowCount = computed(() => {
77
77
  return `${selectedRowCount.value} Rows`;
78
78
  });
79
79
 
@@ -124,5 +124,6 @@ export const useTablePagination = (
124
124
  dropdownId,
125
125
  currentPage,
126
126
  totalPages,
127
+ showNumberOfRowsDropdown
127
128
  };
128
129
  };
@@ -2,6 +2,8 @@ import type { PropType, ExtractPropTypes } from 'vue';
2
2
  import type { ChipTitle } from '@/components/table/table-chips-title/table-chips-title';
3
3
  import type { LozengeTitle } from '@/components/table/table-lozenge-title/table-lozenge-title';
4
4
  import { type SortableEvent } from 'sortablejs';
5
+ import type { MenuListType } from '../list/list';
6
+ import type { TableHeaderFilterType } from './table-header-dropdown/table-header-dropdown';
5
7
  export const definePropType = <T>(val: unknown): PropType<T> => val as PropType<T>;
6
8
 
7
9
  export interface Header {
@@ -18,6 +20,7 @@ export interface Header {
18
20
  avatarVariant?: string;
19
21
  customTailwindClasses?: string;
20
22
  width?: string;
23
+ filterList?: MenuListType[]; // List of filter options for table header dropdown
21
24
  }
22
25
 
23
26
  export interface TableData {
@@ -183,6 +186,10 @@ export const tablePropTypes = {
183
186
  retainSelectionOnDataChange: {
184
187
  type: Boolean,
185
188
  default: false,
189
+ },
190
+ showHeaderFilter: {
191
+ type: Boolean,
192
+ default: false,
186
193
  }
187
194
  };
188
195
 
@@ -202,7 +209,8 @@ export const tableEmitTypes = {
202
209
  onDragAdd: (event: DragOnAddEvent): event is DragOnAddEvent =>
203
210
  event !== undefined && Array.isArray(event.updatedList),
204
211
  onDragRemove: (event: DragOnRemoveEvent): event is DragOnRemoveEvent =>
205
- event !== undefined && Array.isArray(event.updatedList),
212
+ event !== undefined && Array.isArray(event.updatedList),
213
+ onApplyFilter: (filter: TableHeaderFilterType) => !!filter,
206
214
  };
207
215
 
208
216
  export type TablePropTypes = ExtractPropTypes<typeof tablePropTypes>;
@@ -20,7 +20,7 @@
20
20
  <table
21
21
  :key="tableKey"
22
22
  aria-describedby="describe"
23
- class="spr-h-full spr-w-full spr-table-fixed"
23
+ class="spr-h-full spr-w-full"
24
24
  cellspacing="0"
25
25
  cellpadding="0"
26
26
  >
@@ -45,7 +45,18 @@
45
45
  :class="[getTableClasses.headerClasses(header)]"
46
46
  :style="{ width: header?.width }"
47
47
  >
48
- <div :class="getTableClasses.headerNameClass">
48
+ <!-- Header with Dropdown Filter -->
49
+ <spr-table-header-dropdown
50
+ v-if="props.showHeaderFilter"
51
+ :id="`th-dropdown-${keyHeader}`"
52
+ :header="header"
53
+ :is-sortable="true"
54
+ :header-classes="getTableClasses.headerNameClass"
55
+ :filter-options="header.filterList"
56
+ @on-apply-filter="(filters) => emit('onApplyFilter', filters)"
57
+ />
58
+ <!-- Default Header -->
59
+ <div v-else :class="getTableClasses.headerNameClass">
49
60
  <span :class="[{ 'spr-cursor-pointer': header.sort }]" @click="header.sort && sortData(header.field)">
50
61
  {{ header.name }}
51
62
  </span>
@@ -69,6 +80,9 @@
69
80
  :class="[{ 'spr-text-kangkong-700': sortField === header.field }]"
70
81
  />
71
82
  </span>
83
+ <span v-if="props.showHeaderFilter">
84
+ <Icon icon="ph:funnel-simple" height="20" width="20" class="spr-ml-size-spacing-5xs spr-text-[#4B685E]" />
85
+ </span>
72
86
  </div>
73
87
  </th>
74
88
 
@@ -213,6 +227,7 @@ import SprTableActions from '@/components/table/table-actions/table-actions.vue'
213
227
  import SprTableLozengeTitle from '@/components/table/table-lozenge-title/table-lozenge-title.vue';
214
228
  import SprTableChipsTitle from '@/components/table/table-chips-title/table-chips-title.vue';
215
229
  import SprCheckbox from '@/components/checkbox/checkbox.vue';
230
+ import SprTableHeaderDropdown from '@/components/table/table-header-dropdown/table-header-dropdown.vue';
216
231
 
217
232
  import { tablePropTypes, tableEmitTypes } from './table';
218
233
  import type { ChipTitle } from '@/components/table/table-chips-title/table-chips-title';
@@ -198,7 +198,11 @@ export const useTable = (props: TablePropTypes, emit: SetupContext<TableEmitType
198
198
 
199
199
  const getTableClasses = computed(() => {
200
200
  const tableWrapperClasses = classNames(
201
- 'spr-flex spr-flex-col spr-h-full spr-border-color-weak spr-w-full spr-overflow-hidden spr-rounded-border-radius-lg spr-border spr-border-solid spr-table-wrapper spr-relative spr-font-main',
201
+ 'spr-flex spr-flex-col spr-h-full spr-border-color-weak spr-w-full spr-overflow-auto spr-rounded-border-radius-lg spr-border spr-border-solid spr-table-wrapper spr-relative spr-font-main',
202
+ {
203
+ 'spr-overflow-hidden': isDraggable.value,
204
+ 'spr-overflow-auto': !isDraggable.value,
205
+ }
202
206
  );
203
207
  const tableFooterClasses = classNames('spr-w-full spr-bottom-0 spr-left-0', {
204
208
  'spr-background-color-surface': props.variant === 'surface',
@@ -219,6 +223,7 @@ export const useTable = (props: TablePropTypes, emit: SetupContext<TableEmitType
219
223
  'spr-border-color-weak spr-border-x-0 spr-border-y spr-border-solid',
220
224
  {
221
225
  'spr-border-t-0': !slots.default,
226
+ 'spr-cursor-pointer hover:spr-background-color-hover active:spr-background-color-pressed': props.showHeaderFilter,
222
227
  },
223
228
  headerBackground,
224
229
  );