@a-vision-software/vue-input-components 1.4.19 → 1.4.21

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/package.json CHANGED
@@ -1,91 +1,91 @@
1
1
  {
2
- "name": "@a-vision-software/vue-input-components",
3
- "version": "1.4.19",
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"
2
+ "name": "@a-vision-software/vue-input-components",
3
+ "version": "1.4.21",
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"
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"
10
39
  },
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"
40
+ "./global": {
41
+ "types": "./dist/src/global.d.ts"
46
42
  },
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
- }
43
+ "./dist/*": "./dist/*",
44
+ "./styles.css": "./dist/vue-input-components.css",
45
+ "./styles": "./dist/vue-input-components.css"
46
+ },
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
+ }
@@ -96,7 +96,7 @@
96
96
  }"
97
97
  @click="handleSort(column)"
98
98
  >
99
- <div class="list__column-header">
99
+ <div class="list__column-header" :title="column.headerTooltip">
100
100
  <span>{{ column.label }}</span>
101
101
  <span
102
102
  v-if="column.sortable"
@@ -135,7 +135,7 @@
135
135
  v-for="column in columns"
136
136
  :key="column.key"
137
137
  class="list__cell"
138
- :class="`list__cell--${column.align || 'left'}`"
138
+ :class="`${getCellClasses(row, column)} list__cell--${column.align || 'left'}`"
139
139
  :style="{
140
140
  width: column.width,
141
141
  minWidth: column.minWidth,
@@ -219,7 +219,7 @@ import { ref, computed, watch } from 'vue'
219
219
  import TextInput from './TextInput.vue'
220
220
  import Action from './Action.vue'
221
221
  import Checkbox from './Checkbox.vue'
222
- import type { ListProps, ListEmits, ListColumn, ListAction } from '../types/list'
222
+ import type { ListProps, ListEmits, ListColumn, ListAction, ListRowData } from '../types/list'
223
223
  import { config } from '../config'
224
224
 
225
225
  const props = withDefaults(defineProps<ListProps>(), {
@@ -341,11 +341,13 @@ const filteredData = computed(() => {
341
341
  if (filterableColumns.length === 0) return props.data
342
342
 
343
343
  return props.data.filter((row) => {
344
+ // Always include rows excluded from filtering
345
+ if (row.excludeFromFilter) return true
346
+
344
347
  return filterableColumns.some((column) => {
345
348
  const value = row[column.key]
346
349
  if (value == null) return false
347
350
 
348
- const dateStr = formatDate(value)
349
351
  const checkboxValue = value?.modelValue ? 'yes' : 'no'
350
352
 
351
353
  switch (column.type) {
@@ -354,7 +356,7 @@ const filteredData = computed(() => {
354
356
  case 'number':
355
357
  return String(value).includes(effectiveFilterValue.value)
356
358
  case 'date':
357
- return dateStr.toLowerCase().includes(effectiveFilterValue.value)
359
+ return formatDate(value).toLowerCase().includes(effectiveFilterValue.value)
358
360
  case 'checkbox':
359
361
  return checkboxValue.includes(effectiveFilterValue.value)
360
362
  default:
@@ -365,36 +367,57 @@ const filteredData = computed(() => {
365
367
  })
366
368
 
367
369
  const sortedAndFilteredData = computed(() => {
368
- if (!sortColumn.value) return filteredData.value
369
-
370
- return [...filteredData.value].sort((a, b) => {
371
- const column = sortColumn.value!
372
- const aValue = a[column.key]
373
- const bValue = b[column.key]
374
- const sortOrder = sortDirection.value === 'asc' ? 1 : -1
375
-
376
- // Handle different data types
377
- if (column.type === 'date') {
378
- const dateA = new Date(aValue).getTime()
379
- const dateB = new Date(bValue).getTime()
380
- return (dateA - dateB) * sortOrder
370
+ // Separate fixed rows (excluded from sorting) from sortable rows
371
+ const fixedRows: ListRowData[] = []
372
+ const sortableRows: ListRowData[] = []
373
+
374
+ filteredData.value.forEach((row) => {
375
+ if (row.excludeFromSort) {
376
+ fixedRows.push(row)
377
+ } else {
378
+ sortableRows.push(row)
381
379
  }
380
+ })
382
381
 
383
- if (column.type === 'number') {
384
- return (aValue - bValue) * sortOrder
385
- }
382
+ // Sort only the sortable rows if sorting is active
383
+ let sortedRows = sortableRows
384
+ if (sortColumn.value) {
385
+ sortedRows = [...sortableRows].sort((a, b) => {
386
+ const column = sortColumn.value!
387
+ const aValue = a[column.key]
388
+ const bValue = b[column.key]
389
+ const sortOrder = sortDirection.value === 'asc' ? 1 : -1
390
+
391
+ // Handle different data types
392
+ if (column.type === 'date') {
393
+ const dateA = new Date(aValue).getTime()
394
+ const dateB = new Date(bValue).getTime()
395
+ return (dateA - dateB) * sortOrder
396
+ }
386
397
 
387
- if (column.type === 'checkbox') {
388
- const aChecked = aValue?.modelValue || false
389
- const bChecked = bValue?.modelValue || false
390
- return (aChecked - bChecked) * sortOrder
391
- }
398
+ if (column.type === 'number') {
399
+ return (aValue - bValue) * sortOrder
400
+ }
392
401
 
393
- // Default string comparison for text and other types
394
- const stringA = String(aValue || '').toLowerCase()
395
- const stringB = String(bValue || '').toLowerCase()
396
- return stringA.localeCompare(stringB) * sortOrder
397
- })
402
+ if (column.type === 'checkbox') {
403
+ const aChecked = aValue?.modelValue || false
404
+ const bChecked = bValue?.modelValue || false
405
+ return (aChecked - bChecked) * sortOrder
406
+ }
407
+
408
+ // Default string comparison for text and other types
409
+ const stringA = String(aValue || '').toLowerCase()
410
+ const stringB = String(bValue || '').toLowerCase()
411
+ return stringA.localeCompare(stringB) * sortOrder
412
+ })
413
+ }
414
+
415
+ // Separate fixed rows by their fixed position
416
+ const topFixedRows = fixedRows.filter((row) => row.fixed === 'top')
417
+ const bottomFixedRows = fixedRows.filter((row) => row.fixed === 'bottom')
418
+
419
+ // Return rows in order: top fixed, sorted, bottom fixed
420
+ return [...topFixedRows, ...sortedRows, ...bottomFixedRows]
398
421
  })
399
422
 
400
423
  defineExpose({
@@ -414,6 +437,16 @@ defineExpose({
414
437
  filterValue.value = ''
415
438
  },
416
439
  })
440
+
441
+ const getCellClasses = (row: any, column: ListColumn) => {
442
+ if (!column.cellClasses) return ''
443
+
444
+ return Object.entries(column.cellClasses)
445
+ .map(([key, value]) => {
446
+ return value(row[column.key]) ? key : ''
447
+ })
448
+ .join(' ')
449
+ }
417
450
  </script>
418
451
 
419
452
  <style scoped>
package/src/types/list.ts CHANGED
@@ -1,65 +1,89 @@
1
- import { ListActionProps } from './action';
1
+ import { ListActionProps } from './action'
2
2
 
3
- type ListPresentation = 'default' | 'minimal';
3
+ type ListPresentation = 'default' | 'minimal'
4
4
 
5
- type ListDataType = 'text' | 'number' | 'date' | 'action' | 'checkbox' | 'icon' | 'email' | 'datetime' | 'time';
5
+ type ListDataType =
6
+ | 'text'
7
+ | 'number'
8
+ | 'date'
9
+ | 'action'
10
+ | 'checkbox'
11
+ | 'icon'
12
+ | 'email'
13
+ | 'datetime'
14
+ | 'time'
6
15
 
7
16
  interface ListAction {
8
- id: string;
9
- label?: string;
10
- icon?: string;
11
- color?: string;
12
- href?: string;
13
- onClick?: (item: any) => void;
14
- onActionClick?: (item: any, action: any) => void;
17
+ id: string
18
+ label?: string
19
+ icon?: string
20
+ color?: string
21
+ href?: string
22
+ onClick?: (item: any) => void
23
+ onActionClick?: (item: any, action: any) => void
24
+ }
25
+
26
+ interface conditionalClassList {
27
+ [key: string]: (value: any) => boolean
15
28
  }
16
29
 
17
30
  interface ListColumn {
18
- key: string;
19
- label: string;
20
- type?: ListDataType;
21
- align?: 'left' | 'center' | 'right';
22
- sortable?: boolean;
23
- filterable?: boolean;
24
- width?: string;
25
- minWidth?: string;
26
- maxWidth?: string;
31
+ key: string
32
+ label: string
33
+ type?: ListDataType
34
+ align?: 'left' | 'center' | 'right'
35
+ sortable?: boolean
36
+ filterable?: boolean
37
+ width?: string
38
+ minWidth?: string
39
+ maxWidth?: string
40
+ cellClasses?: conditionalClassList
41
+ headerTooltip?: string
27
42
  }
28
43
 
29
44
  interface ListFilter {
30
- placeholder?: string;
31
- debounce?: number;
45
+ placeholder?: string
46
+ debounce?: number
32
47
  }
33
48
 
34
49
  interface ListProps {
35
- columns: ListColumn[];
36
- data: any[];
37
- actions?: ListActionProps[];
38
- CSVDownload?: string;
50
+ columns: ListColumn[]
51
+ data: ListRowData[]
52
+ actions?: ListActionProps[]
53
+ CSVDownload?: string
39
54
  filter?: {
40
- placeholder?: string;
41
- };
42
- loading?: boolean;
43
- emptyMessage?: string;
44
- presentation?: 'default' | 'minimal';
45
- width?: string;
55
+ placeholder?: string
56
+ }
57
+ loading?: boolean
58
+ emptyMessage?: string
59
+ presentation?: 'default' | 'minimal'
60
+ width?: string
46
61
  }
47
62
 
48
63
  interface ListEmits {
49
- (e: 'update:filter', value: string): void;
50
- (e: 'row-click', row: any, index: number): void;
51
- (e: 'row-dblclick', row: any, index: number): void;
64
+ (e: 'update:filter', value: string): void
65
+ (e: 'row-click', row: any, index: number): void
66
+ (e: 'row-dblclick', row: any, index: number): void
52
67
  }
53
68
 
54
69
  interface ListComponent {
55
- focus: () => void;
56
- blur: () => void;
57
- clearFilter: () => void;
70
+ focus: () => void
71
+ blur: () => void
72
+ clearFilter: () => void
58
73
  }
59
74
 
60
75
  interface ListIconProps {
61
- icon: string;
62
- color?: string;
76
+ icon: string
77
+ color?: string
78
+ }
79
+
80
+ interface ListRowData {
81
+ excludeFromSort?: boolean
82
+ excludeFromFilter?: boolean
83
+ fixed?: 'top' | 'bottom'
84
+ selected?: boolean
85
+ class?: string
86
+ [key: string]: any
63
87
  }
64
88
 
65
89
  export type {
@@ -71,4 +95,5 @@ export type {
71
95
  ListIconProps,
72
96
  ListColumn,
73
97
  ListFilter,
74
- };
98
+ ListRowData,
99
+ }