@a-vision-software/vue-input-components 1.4.16 → 1.4.17
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/src/types/list.d.ts +2 -1
- package/dist/vue-input-components.cjs.js +2 -1
- package/dist/vue-input-components.css +1 -1
- package/dist/vue-input-components.es.js +2684 -2526
- package/dist/vue-input-components.umd.js +2 -1
- package/package.json +88 -88
- package/src/components/List.vue +60 -11
- package/src/types/list.ts +2 -1
- package/src/views/ListTestView.vue +5 -3
package/package.json
CHANGED
|
@@ -1,91 +1,91 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
},
|
|
11
|
-
"homepage": "https://a-vision.github.io/vue-input-components/",
|
|
12
|
-
"keywords": [
|
|
13
|
-
"vue",
|
|
14
|
-
"vue3",
|
|
15
|
-
"components",
|
|
16
|
-
"input",
|
|
17
|
-
"form",
|
|
18
|
-
"typescript",
|
|
19
|
-
"file-upload",
|
|
20
|
-
"text-input",
|
|
21
|
-
"date-picker",
|
|
22
|
-
"dropdown",
|
|
23
|
-
"textarea"
|
|
24
|
-
],
|
|
25
|
-
"type": "module",
|
|
26
|
-
"files": [
|
|
27
|
-
"src",
|
|
28
|
-
"types",
|
|
29
|
-
"dist"
|
|
30
|
-
],
|
|
31
|
-
"main": "./dist/vue-input-components.cjs.js",
|
|
32
|
-
"module": "./dist/vue-input-components.es.js",
|
|
33
|
-
"types": "./dist/src/index.d.ts",
|
|
34
|
-
"exports": {
|
|
35
|
-
".": {
|
|
36
|
-
"types": "./dist/src/index.d.ts",
|
|
37
|
-
"import": "./dist/vue-input-components.es.js",
|
|
38
|
-
"require": "./dist/vue-input-components.cjs.js"
|
|
2
|
+
"name": "@a-vision-software/vue-input-components",
|
|
3
|
+
"version": "1.4.17",
|
|
4
|
+
"description": "A collection of reusable Vue 3 input components with TypeScript support",
|
|
5
|
+
"author": "A-Vision Software",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/a-vision/vue-input-components.git"
|
|
39
10
|
},
|
|
40
|
-
"
|
|
41
|
-
|
|
11
|
+
"homepage": "https://a-vision.github.io/vue-input-components/",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"vue",
|
|
14
|
+
"vue3",
|
|
15
|
+
"components",
|
|
16
|
+
"input",
|
|
17
|
+
"form",
|
|
18
|
+
"typescript",
|
|
19
|
+
"file-upload",
|
|
20
|
+
"text-input",
|
|
21
|
+
"date-picker",
|
|
22
|
+
"dropdown",
|
|
23
|
+
"textarea"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"files": [
|
|
27
|
+
"src",
|
|
28
|
+
"types",
|
|
29
|
+
"dist"
|
|
30
|
+
],
|
|
31
|
+
"main": "./dist/vue-input-components.cjs.js",
|
|
32
|
+
"module": "./dist/vue-input-components.es.js",
|
|
33
|
+
"types": "./dist/src/index.d.ts",
|
|
34
|
+
"exports": {
|
|
35
|
+
".": {
|
|
36
|
+
"types": "./dist/src/index.d.ts",
|
|
37
|
+
"import": "./dist/vue-input-components.es.js",
|
|
38
|
+
"require": "./dist/vue-input-components.cjs.js"
|
|
39
|
+
},
|
|
40
|
+
"./global": {
|
|
41
|
+
"types": "./dist/src/global.d.ts"
|
|
42
|
+
},
|
|
43
|
+
"./dist/*": "./dist/*",
|
|
44
|
+
"./styles.css": "./dist/vue-input-components.css",
|
|
45
|
+
"./styles": "./dist/vue-input-components.css"
|
|
42
46
|
},
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
"publishConfig": {
|
|
89
|
-
"access": "public"
|
|
90
|
-
}
|
|
91
|
-
}
|
|
47
|
+
"sideEffects": [
|
|
48
|
+
"**/*.css"
|
|
49
|
+
],
|
|
50
|
+
"scripts": {
|
|
51
|
+
"dev": "vite",
|
|
52
|
+
"build": "vite build",
|
|
53
|
+
"preview": "vite preview",
|
|
54
|
+
"test": "vitest"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"vue": "^3.5.0"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@fortawesome/fontawesome-svg-core": "^6.7.0",
|
|
61
|
+
"@fortawesome/free-regular-svg-icons": "^6.7.0",
|
|
62
|
+
"@fortawesome/free-solid-svg-icons": "^6.7.0",
|
|
63
|
+
"@fortawesome/vue-fontawesome": "^3.0.0",
|
|
64
|
+
"@vuepic/vue-datepicker": "^11.0.2"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@tsconfig/node20": "^20.1.2",
|
|
68
|
+
"@types/node": "^20.11.0",
|
|
69
|
+
"@vitejs/plugin-vue": "^5.0.0",
|
|
70
|
+
"@vue/eslint-config-prettier": "^9.0.0",
|
|
71
|
+
"@vue/eslint-config-typescript": "^12.0.0",
|
|
72
|
+
"@vue/test-utils": "^2.4.0",
|
|
73
|
+
"@vue/tsconfig": "^0.5.1",
|
|
74
|
+
"eslint": "^8.56.0",
|
|
75
|
+
"eslint-plugin-vue": "^9.21.0",
|
|
76
|
+
"npm-run-all": "^4.1.5",
|
|
77
|
+
"prettier": "^3.2.0",
|
|
78
|
+
"typescript": "~5.3.0",
|
|
79
|
+
"vite": "^5.0.0",
|
|
80
|
+
"vite-plugin-dts": "^3.7.0",
|
|
81
|
+
"vitest": "^1.2.0",
|
|
82
|
+
"vue-router": "^4.2.0",
|
|
83
|
+
"vue-tsc": "^1.8.0"
|
|
84
|
+
},
|
|
85
|
+
"engines": {
|
|
86
|
+
"node": ">=18.0.0"
|
|
87
|
+
},
|
|
88
|
+
"publishConfig": {
|
|
89
|
+
"access": "public"
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/components/List.vue
CHANGED
|
@@ -22,7 +22,16 @@
|
|
|
22
22
|
<!-- Actions -->
|
|
23
23
|
<div v-if="actions?.length" class="list__actions">
|
|
24
24
|
|
|
25
|
-
<Action v-for="(action, actionIndex) in
|
|
25
|
+
<Action v-for="(action, actionIndex) in [
|
|
26
|
+
...(props.CSVDownload !== undefined ? [{
|
|
27
|
+
id: 'csv-download',
|
|
28
|
+
label: 'Download',
|
|
29
|
+
icon: 'file-csv',
|
|
30
|
+
color: 'var(--primary-color)',
|
|
31
|
+
onActionClick: handleCSVDownload
|
|
32
|
+
}] : []),
|
|
33
|
+
...actions
|
|
34
|
+
]" :key="actionIndex" v-bind="action"
|
|
26
35
|
:href="presentation === 'minimal' && !action.href ? `#/${action.id ? action.id : action.label?.toLowerCase()}` : action.href"
|
|
27
36
|
@click.prevent="action.onActionClick ? action.onActionClick(undefined, action) : null"
|
|
28
37
|
:size="presentation === 'minimal' ? 'small' : 'regular'" />
|
|
@@ -85,6 +94,11 @@
|
|
|
85
94
|
<template v-if="column.type === 'text'">
|
|
86
95
|
{{ row[column.key] }}
|
|
87
96
|
</template>
|
|
97
|
+
<template v-else-if="column.type === 'email'">
|
|
98
|
+
<a v-if="row['name']" :href="`mailto:${row['name']} <${row[column.key]}>`" @click.stop>{{
|
|
99
|
+
row[column.key] }}</a>
|
|
100
|
+
<a v-else :href="`mailto:${row[column.key]}`" @click.stop>{{ row[column.key] }}</a>
|
|
101
|
+
</template>
|
|
88
102
|
<template v-else-if="column.type === 'number'">
|
|
89
103
|
{{ row[column.key] }}
|
|
90
104
|
</template>
|
|
@@ -154,6 +168,43 @@ watch(filterValue, (newValue) => {
|
|
|
154
168
|
return () => clearTimeout(timeout)
|
|
155
169
|
})
|
|
156
170
|
|
|
171
|
+
const handleCSVDownload = () => {
|
|
172
|
+
const csv = [];
|
|
173
|
+
const headerRow = [];
|
|
174
|
+
const headerKeys = []
|
|
175
|
+
for (const column of props.columns) {
|
|
176
|
+
const dataType = typeof props.data[0][column.key];
|
|
177
|
+
if (dataType !== 'object') {
|
|
178
|
+
const columnName = column.label || column.key;
|
|
179
|
+
headerRow.push(columnName);
|
|
180
|
+
headerKeys.push(column.key);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
csv.push(headerRow.join(','));
|
|
184
|
+
|
|
185
|
+
for (const row of props.data) {
|
|
186
|
+
const rowData: string[] = [];
|
|
187
|
+
headerKeys.forEach(key => {
|
|
188
|
+
const value = row[key];
|
|
189
|
+
if (value == null) {
|
|
190
|
+
rowData.push('');
|
|
191
|
+
} else {
|
|
192
|
+
rowData.push(value);
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
csv.push('"' + rowData.join('","') + '"');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const blob = new Blob([csv.join('\n')], { type: 'text/csv;charset=utf-8;' })
|
|
199
|
+
const url = URL.createObjectURL(blob)
|
|
200
|
+
const a = document.createElement('a')
|
|
201
|
+
a.href = url
|
|
202
|
+
const downloadName = props.CSVDownload || 'data';
|
|
203
|
+
a.download = downloadName.toLowerCase().endsWith('.csv') ? downloadName : downloadName + '.csv'
|
|
204
|
+
a.click()
|
|
205
|
+
URL.revokeObjectURL(url)
|
|
206
|
+
}
|
|
207
|
+
|
|
157
208
|
const handleFilter = () => {
|
|
158
209
|
// No need to do anything here as the watch handles the filtering
|
|
159
210
|
}
|
|
@@ -203,16 +254,17 @@ const filteredData = computed(() => {
|
|
|
203
254
|
const value = row[column.key]
|
|
204
255
|
if (value == null) return false
|
|
205
256
|
|
|
257
|
+
const dateStr = formatDate(value)
|
|
258
|
+
const checkboxValue = value?.modelValue ? 'yes' : 'no'
|
|
259
|
+
|
|
206
260
|
switch (column.type) {
|
|
207
261
|
case 'text':
|
|
208
262
|
return String(value).toLowerCase().includes(effectiveFilterValue.value)
|
|
209
263
|
case 'number':
|
|
210
264
|
return String(value).includes(effectiveFilterValue.value)
|
|
211
265
|
case 'date':
|
|
212
|
-
const dateStr = formatDate(value)
|
|
213
266
|
return dateStr.toLowerCase().includes(effectiveFilterValue.value)
|
|
214
267
|
case 'checkbox':
|
|
215
|
-
const checkboxValue = value?.modelValue ? 'yes' : 'no'
|
|
216
268
|
return checkboxValue.includes(effectiveFilterValue.value)
|
|
217
269
|
default:
|
|
218
270
|
return false
|
|
@@ -228,32 +280,29 @@ const sortedAndFilteredData = computed(() => {
|
|
|
228
280
|
const column = sortColumn.value!
|
|
229
281
|
const aValue = a[column.key]
|
|
230
282
|
const bValue = b[column.key]
|
|
283
|
+
const sortOrder = sortDirection.value === 'asc' ? 1 : -1
|
|
231
284
|
|
|
232
285
|
// Handle different data types
|
|
233
286
|
if (column.type === 'date') {
|
|
234
287
|
const dateA = new Date(aValue).getTime()
|
|
235
288
|
const dateB = new Date(bValue).getTime()
|
|
236
|
-
return
|
|
289
|
+
return (dateA - dateB) * sortOrder
|
|
237
290
|
}
|
|
238
291
|
|
|
239
292
|
if (column.type === 'number') {
|
|
240
|
-
return
|
|
293
|
+
return (aValue - bValue) * sortOrder
|
|
241
294
|
}
|
|
242
295
|
|
|
243
296
|
if (column.type === 'checkbox') {
|
|
244
297
|
const aChecked = aValue?.modelValue || false
|
|
245
298
|
const bChecked = bValue?.modelValue || false
|
|
246
|
-
return
|
|
247
|
-
? (aChecked === bChecked ? 0 : aChecked ? 1 : -1)
|
|
248
|
-
: (aChecked === bChecked ? 0 : aChecked ? -1 : 1)
|
|
299
|
+
return (aChecked - bChecked) * sortOrder
|
|
249
300
|
}
|
|
250
301
|
|
|
251
302
|
// Default string comparison for text and other types
|
|
252
303
|
const stringA = String(aValue || '').toLowerCase()
|
|
253
304
|
const stringB = String(bValue || '').toLowerCase()
|
|
254
|
-
return
|
|
255
|
-
? stringA.localeCompare(stringB)
|
|
256
|
-
: stringB.localeCompare(stringA)
|
|
305
|
+
return stringA.localeCompare(stringB) * sortOrder
|
|
257
306
|
})
|
|
258
307
|
})
|
|
259
308
|
|
package/src/types/list.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { ListActionProps } from './action'
|
|
|
2
2
|
|
|
3
3
|
type ListPresentation = 'default' | 'minimal'
|
|
4
4
|
|
|
5
|
-
type ListDataType = 'text' | 'number' | 'date' | 'action' | 'checkbox' | 'icon'
|
|
5
|
+
type ListDataType = 'text' | 'number' | 'date' | 'action' | 'checkbox' | 'icon' | 'email'
|
|
6
6
|
|
|
7
7
|
interface ListAction {
|
|
8
8
|
id: string
|
|
@@ -35,6 +35,7 @@ interface ListProps {
|
|
|
35
35
|
columns: ListColumn[]
|
|
36
36
|
data: any[]
|
|
37
37
|
actions?: ListActionProps[]
|
|
38
|
+
CSVDownload?: string
|
|
38
39
|
filter?: {
|
|
39
40
|
placeholder?: string
|
|
40
41
|
}
|
|
@@ -12,14 +12,15 @@
|
|
|
12
12
|
<section class="list-test__section">
|
|
13
13
|
<h2>Default Presentation</h2>
|
|
14
14
|
<List :actions="listActions" :columns="columns" :data="data" :filter="{ placeholder: 'Search users...' }"
|
|
15
|
-
@row-click="handleRowClick" @row-dblclick="handleRowDblClick" />
|
|
15
|
+
@row-click="handleRowClick" @row-dblclick="handleRowDblClick" :CSVDownload="'users'" />
|
|
16
16
|
</section>
|
|
17
17
|
|
|
18
18
|
<!-- Minimal Presentation -->
|
|
19
19
|
<section class="list-test__section">
|
|
20
20
|
<h2>Minimal Presentation</h2>
|
|
21
21
|
<List :actions="listActions" :columns="columns" :data="data" presentation="minimal" width="50em"
|
|
22
|
-
:filter="{ placeholder: 'Search users...' }" @row-click="handleRowClick" @row-dblclick="handleRowDblClick"
|
|
22
|
+
:filter="{ placeholder: 'Search users...' }" @row-click="handleRowClick" @row-dblclick="handleRowDblClick"
|
|
23
|
+
:CSVDownload="'user-list'" />
|
|
23
24
|
</section>
|
|
24
25
|
|
|
25
26
|
<!-- Loading State -->
|
|
@@ -115,7 +116,7 @@ const columns: ListColumn[] = [
|
|
|
115
116
|
{
|
|
116
117
|
key: 'email',
|
|
117
118
|
label: 'Email',
|
|
118
|
-
type: '
|
|
119
|
+
type: 'email',
|
|
119
120
|
sortable: true,
|
|
120
121
|
filterable: true
|
|
121
122
|
},
|
|
@@ -131,6 +132,7 @@ const columns: ListColumn[] = [
|
|
|
131
132
|
label: 'Active',
|
|
132
133
|
type: 'checkbox',
|
|
133
134
|
align: 'center',
|
|
135
|
+
sortable: true,
|
|
134
136
|
width: '4rem'
|
|
135
137
|
},
|
|
136
138
|
{
|