design-system-next 2.1.0 → 2.2.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.
- package/dist/design-system-next.js +5232 -7415
- package/dist/design-system-next.js.gz +0 -0
- package/dist/main.css +1 -1
- package/dist/main.css.gz +0 -0
- package/package.json +1 -2
- package/src/components/logo/logo.vue +3 -10
- package/src/components/logo/use-logo.ts +1 -1
- package/src/components/table/table.ts +22 -6
- package/src/components/table/table.vue +63 -45
- package/src/components/table/use-table.ts +63 -2
- package/src/components/tooltip/tooltip.ts +4 -0
- package/src/components/tooltip/tooltip.vue +1 -1
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
<table aria-describedby="describe" class="spr-w-full spr-table-fixed" cellspacing="0" cellpadding="0">
|
|
23
23
|
<thead>
|
|
24
24
|
<tr v-if="!(props.removeHeaderOnEmpty && sortedData.length <= 0)">
|
|
25
|
+
<th v-if="props.isMultiSelect" :class="[getTableClasses.multiselectClass, getTableClasses.headerClasses]">
|
|
26
|
+
<div class="spr-flex spr-justify-center spr-items-center">
|
|
27
|
+
<spr-checkbox label="" :checked="isAllSelected" @update:model-value="handleSelectAll"/>
|
|
28
|
+
</div>
|
|
29
|
+
</th>
|
|
25
30
|
<th v-for="(header, keyHeader) in headers" :key="keyHeader" :class="[getTableClasses.headerClasses]">
|
|
26
31
|
<div :class="getTableClasses.headerNameClass">
|
|
27
32
|
<span :class="[{ 'spr-cursor-pointer': header.sort }]" @click="header.sort && sortData(header.field)">
|
|
@@ -56,61 +61,69 @@
|
|
|
56
61
|
@mouseover="$emit('onHover', { active: true, data: item })"
|
|
57
62
|
@mouseleave="$emit('onHover', { active: false, data: item })"
|
|
58
63
|
>
|
|
64
|
+
<td v-if="props.isMultiSelect" :class="[getTableClasses.multiselectClass, getTableClasses.multiselectRowClass]">
|
|
65
|
+
<div class="spr-flex spr-justify-center spr-items-center">
|
|
66
|
+
<spr-checkbox label="" :checked="isRowSelected(item)" @update:modelValue="handleSelect(item)"/>
|
|
67
|
+
</div>
|
|
68
|
+
</td>
|
|
59
69
|
<td v-for="(column, headerKey) in headers" :key="headerKey" :class="getTableClasses.tableDataClasses">
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
class="spr-flex spr-items-center spr-rounded-full spr-bg-mushroom-200 spr-p-1"
|
|
72
|
-
>
|
|
73
|
-
<Icon :icon="sortedData[keyIndex][column.field].icon || ''" />
|
|
74
|
-
</div>
|
|
75
|
-
<div>
|
|
76
|
-
<!-- Array Title -->
|
|
70
|
+
<slot v-if="slots[column.field]" :name="column.field" :row="item[column.field]" />
|
|
71
|
+
<template v-else>
|
|
72
|
+
<div v-if="sortedData[keyIndex][column.field]" class="spr-flex spr-flex-row spr-items-center spr-gap-2">
|
|
73
|
+
<spr-avatar
|
|
74
|
+
v-if="column.hasAvatar"
|
|
75
|
+
size="lg"
|
|
76
|
+
:src="sortedData[keyIndex][column.field].image"
|
|
77
|
+
alt="User Avatar"
|
|
78
|
+
:variant="column.avatarVariant ? column.avatarVariant : 'initial'"
|
|
79
|
+
:initial="sortedData[keyIndex][column.field].title as string"
|
|
80
|
+
/>
|
|
77
81
|
<div
|
|
78
|
-
v-if="
|
|
79
|
-
class="spr-flex spr-
|
|
82
|
+
v-if="column.hasIcon"
|
|
83
|
+
class="spr-flex spr-items-center spr-rounded-full spr-bg-mushroom-200 spr-p-1"
|
|
80
84
|
>
|
|
81
|
-
<
|
|
85
|
+
<Icon :icon="sortedData[keyIndex][column.field].icon || ''" />
|
|
86
|
+
</div>
|
|
87
|
+
<div>
|
|
88
|
+
<!-- Array Title -->
|
|
89
|
+
<div
|
|
90
|
+
v-if="Array.isArray(sortedData[keyIndex][column.field].title)"
|
|
91
|
+
class="spr-flex spr-flex-wrap spr-gap-2"
|
|
92
|
+
>
|
|
93
|
+
<div v-for="(cell, index) in sortedData[keyIndex][column.field].title" :key="index">
|
|
94
|
+
<div v-if="column.hasLozengeTitle" class="spr-mt-1">
|
|
95
|
+
<spr-table-lozenge-title :cell="cell as LozengeTitle" />
|
|
96
|
+
</div>
|
|
97
|
+
<div v-else-if="column.hasChipTitle" class="spr-mt-1">
|
|
98
|
+
<spr-table-chips-title :cell="cell as ChipTitle" />
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<!-- Single Title Handling -->
|
|
104
|
+
<div v-else>
|
|
82
105
|
<div v-if="column.hasLozengeTitle" class="spr-mt-1">
|
|
83
|
-
|
|
106
|
+
<!-- Defining lozenge title in the title so it wont confuse the consumer; hence the title.title-->
|
|
107
|
+
<!-- Also this structure allows multiple instances -->
|
|
108
|
+
<spr-table-lozenge-title :cell="sortedData[keyIndex][column.field].title as LozengeTitle" />
|
|
84
109
|
</div>
|
|
110
|
+
<!-- Defining the chip title so it wont confuse the consumer; hence the title.title -->
|
|
111
|
+
<!-- Also this structure allows multiple instances -->
|
|
85
112
|
<div v-else-if="column.hasChipTitle" class="spr-mt-1">
|
|
86
|
-
<spr-table-chips-title :cell="
|
|
113
|
+
<spr-table-chips-title :cell="sortedData[keyIndex][column.field].title as ChipTitle" />
|
|
114
|
+
</div>
|
|
115
|
+
<div v-else class="spr-text-color-strong spr-font-size-200 spr-font-normal">
|
|
116
|
+
{{ sortedData[keyIndex][column.field].title }}
|
|
87
117
|
</div>
|
|
88
118
|
</div>
|
|
89
|
-
</div>
|
|
90
119
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
<!-- Defining lozenge title in the title so it wont confuse the consumer; hence the title.title-->
|
|
95
|
-
<!-- Also this structure allows multiple instances -->
|
|
96
|
-
<spr-table-lozenge-title :cell="sortedData[keyIndex][column.field].title as LozengeTitle" />
|
|
97
|
-
</div>
|
|
98
|
-
<!-- Defining the chip title so it wont confuse the consumer; hence the title.title -->
|
|
99
|
-
<!-- Also this structure allows multiple instances -->
|
|
100
|
-
<div v-else-if="column.hasChipTitle" class="spr-mt-1">
|
|
101
|
-
<spr-table-chips-title :cell="sortedData[keyIndex][column.field].title as ChipTitle" />
|
|
120
|
+
<!-- Subtitle -->
|
|
121
|
+
<div v-if="column.hasSubtext" class="spr-text-color-base spr-text-xs spr-font-normal">
|
|
122
|
+
{{ sortedData[keyIndex][column.field].subtext }}
|
|
102
123
|
</div>
|
|
103
|
-
<div v-else class="spr-text-color-strong spr-font-size-200 spr-font-normal">
|
|
104
|
-
{{ sortedData[keyIndex][column.field].title }}
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
|
-
|
|
108
|
-
<!-- Subtitle -->
|
|
109
|
-
<div v-if="column.hasSubtext" class="spr-text-color-base spr-text-xs spr-font-normal">
|
|
110
|
-
{{ sortedData[keyIndex][column.field].subtext }}
|
|
111
124
|
</div>
|
|
112
125
|
</div>
|
|
113
|
-
</
|
|
126
|
+
</template>
|
|
114
127
|
</td>
|
|
115
128
|
<td v-if="action" :class="getTableClasses.tableRowActionClasses">
|
|
116
129
|
<div class="spr-flex spr-items-center">
|
|
@@ -137,7 +150,7 @@
|
|
|
137
150
|
</tbody>
|
|
138
151
|
</table>
|
|
139
152
|
</div>
|
|
140
|
-
<div v-if="$slots.footer" :class="getTableClasses.tableFooterClasses">
|
|
153
|
+
<div v-if="$slots.footer" :class="getTableClasses.tableFooterClasses">
|
|
141
154
|
<slot name="footer" />
|
|
142
155
|
</div>
|
|
143
156
|
</div>
|
|
@@ -152,6 +165,7 @@ import SprBadge from '@/components/badge/badge.vue';
|
|
|
152
165
|
import SprTableActions from '@/components/table/table-actions/table-actions.vue';
|
|
153
166
|
import SprTableLozengeTitle from '@/components/table/table-lozenge-title/table-lozenge-title.vue';
|
|
154
167
|
import SprTableChipsTitle from '@/components/table/table-chips-title/table-chips-title.vue';
|
|
168
|
+
import SprCheckbox from '@/components/checkbox/checkbox.vue';
|
|
155
169
|
|
|
156
170
|
import { tablePropTypes, tableEmitTypes } from './table';
|
|
157
171
|
import type { ChipTitle } from '@/components/table/table-chips-title/table-chips-title';
|
|
@@ -169,9 +183,13 @@ const {
|
|
|
169
183
|
searchField,
|
|
170
184
|
getTableClasses,
|
|
171
185
|
getEmptyStateSize,
|
|
172
|
-
|
|
186
|
+
isAllSelected,
|
|
187
|
+
|
|
188
|
+
isRowSelected,
|
|
173
189
|
sortData,
|
|
174
190
|
updateSearchField,
|
|
175
191
|
handleRowClick,
|
|
192
|
+
handleSelect,
|
|
193
|
+
handleSelectAll
|
|
176
194
|
} = useTable(props, emit, slots);
|
|
177
195
|
</script>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref, computed, toRefs, Slots } from 'vue';
|
|
1
|
+
import { ref, computed, toRefs, Slots, watch } from 'vue';
|
|
2
2
|
|
|
3
3
|
import type { TablePropTypes, TableEmitTypes, TABLE_SORT, TableData } from './table';
|
|
4
4
|
import type { SetupContext } from 'vue';
|
|
@@ -6,10 +6,18 @@ import type { SetupContext } from 'vue';
|
|
|
6
6
|
import classNames from 'classnames';
|
|
7
7
|
|
|
8
8
|
export const useTable = (props: TablePropTypes, emit: SetupContext<TableEmitTypes>['emit'], slots: Slots) => {
|
|
9
|
-
const { dataTable, action, headers, sortOrder, fullHeight } =
|
|
9
|
+
const { dataTable, action, headers, sortOrder, fullHeight, selectedKeyId, returnCompleteSelectedProperties } =
|
|
10
|
+
toRefs(props);
|
|
10
11
|
const sortField = ref('');
|
|
11
12
|
const searchField = ref(props.searchModel);
|
|
12
13
|
const tableSortOrder = ref<TABLE_SORT>(sortOrder.value || 'asc');
|
|
14
|
+
const selectAll = ref(false);
|
|
15
|
+
const selectedData = ref<TableData[]>([]);
|
|
16
|
+
|
|
17
|
+
const isAllSelected = computed(() => {
|
|
18
|
+
if (selectedData.value.length === 0) return false;
|
|
19
|
+
return selectedData.value.length === sortedData.value.length;
|
|
20
|
+
});
|
|
13
21
|
|
|
14
22
|
const sortedData = computed(() => {
|
|
15
23
|
if (!sortField.value || sortOrder.value) return dataTable.value;
|
|
@@ -121,6 +129,12 @@ export const useTable = (props: TablePropTypes, emit: SetupContext<TableEmitType
|
|
|
121
129
|
'spr-h-[360px]': !fullHeight.value && !slots.footer,
|
|
122
130
|
});
|
|
123
131
|
|
|
132
|
+
const multiselectRowClass = classNames(
|
|
133
|
+
'spr-border-color-weak spr-border-x-0 spr-border-b spr-border-t-0 spr-border-solid',
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const multiselectClass = classNames('spr-px-size-spacing-2xs spr-py-size-spacing-3xs spr-w-[44px] ');
|
|
137
|
+
|
|
124
138
|
return {
|
|
125
139
|
headerClasses,
|
|
126
140
|
tableWrapperClasses,
|
|
@@ -128,6 +142,8 @@ export const useTable = (props: TablePropTypes, emit: SetupContext<TableEmitType
|
|
|
128
142
|
tableHeaderActionsClasses,
|
|
129
143
|
headerNameClass,
|
|
130
144
|
tableCellSlotClasses,
|
|
145
|
+
multiselectRowClass,
|
|
146
|
+
multiselectClass,
|
|
131
147
|
|
|
132
148
|
tableRowClasses,
|
|
133
149
|
tableDataClasses,
|
|
@@ -139,15 +155,60 @@ export const useTable = (props: TablePropTypes, emit: SetupContext<TableEmitType
|
|
|
139
155
|
};
|
|
140
156
|
});
|
|
141
157
|
|
|
158
|
+
const handleSelect = (item: TableData) => {
|
|
159
|
+
if (!selectedKeyId.value || !(selectedKeyId.value in item)) return;
|
|
160
|
+
|
|
161
|
+
const selectedIndex = selectedData.value.findIndex(
|
|
162
|
+
(data) => data[selectedKeyId.value].title === item[selectedKeyId.value].title,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
if (selectedIndex !== -1) {
|
|
166
|
+
selectedData.value.splice(selectedIndex, 1);
|
|
167
|
+
} else {
|
|
168
|
+
selectedData.value.push(item);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const handleSelectAll = () => {
|
|
173
|
+
if (isAllSelected.value) {
|
|
174
|
+
selectedData.value = [];
|
|
175
|
+
} else {
|
|
176
|
+
selectedData.value = sortedData.value;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const isRowSelected = (item: TableData) => {
|
|
181
|
+
if (!selectedKeyId.value || !(selectedKeyId.value in item)) return false;
|
|
182
|
+
return selectedData.value.some((data) => data[selectedKeyId.value].title === item[selectedKeyId.value].title);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
watch(
|
|
186
|
+
() => selectedData.value.length,
|
|
187
|
+
() => {
|
|
188
|
+
if (returnCompleteSelectedProperties.value) {
|
|
189
|
+
emit('update:selectedData', selectedData.value);
|
|
190
|
+
} else {
|
|
191
|
+
const mappedData = selectedData.value.map((item) => ({ ...item[selectedKeyId.value] }));
|
|
192
|
+
emit('update:selectedData', mappedData);
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
);
|
|
196
|
+
|
|
142
197
|
return {
|
|
143
198
|
sortData,
|
|
144
199
|
updateSearchField,
|
|
145
200
|
handleRowClick,
|
|
201
|
+
handleSelect,
|
|
202
|
+
handleSelectAll,
|
|
146
203
|
sortedData,
|
|
147
204
|
getHeaderCount,
|
|
148
205
|
hasTableActions,
|
|
149
206
|
searchField,
|
|
150
207
|
getTableClasses,
|
|
151
208
|
getEmptyStateSize,
|
|
209
|
+
selectAll,
|
|
210
|
+
selectedData,
|
|
211
|
+
isAllSelected,
|
|
212
|
+
isRowSelected,
|
|
152
213
|
};
|
|
153
214
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<template v-if="props.text || slots['popper-content']">
|
|
3
3
|
<Tooltip
|
|
4
|
-
class="spr-w-fit"
|
|
4
|
+
:class="[ props.fitContent ? 'spr-w-fit' : 'spr-w-full' ]"
|
|
5
5
|
:aria-id="props.hasMaxWidth ? 'tooltip-full-width-wrapper' : 'tooltip-wrapper'"
|
|
6
6
|
:placement="placement"
|
|
7
7
|
>
|