@stonecrop/atable 0.13.3 → 0.13.5
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/assets/index.css +1 -1
- package/dist/atable.d.ts +8 -6
- package/dist/atable.js +1401 -1384
- package/dist/atable.js.map +1 -1
- package/dist/src/icons/index.d.ts.map +1 -1
- package/dist/src/icons/index.js +0 -6
- package/dist/src/schemaToColumns.d.ts.map +1 -1
- package/dist/src/schemaToColumns.js +2 -3
- package/dist/src/stores/table.d.ts +8 -6
- package/dist/src/stores/table.d.ts.map +1 -1
- package/dist/src/stores/table.js +97 -98
- package/package.json +11 -14
- package/src/components/ACell.vue +7 -8
- package/src/components/AGanttCell.vue +2 -2
- package/src/components/ATable.vue +7 -7
- package/src/components/ATableColumnFilter.vue +3 -3
- package/src/components/ATableModal.vue +1 -1
- package/src/icons/index.ts +6 -12
- package/src/schemaToColumns.ts +2 -3
- package/src/shims-vue.d.ts +5 -0
- package/src/stores/table.ts +108 -108
package/src/stores/table.ts
CHANGED
|
@@ -34,6 +34,107 @@ export interface FilterState {
|
|
|
34
34
|
*/
|
|
35
35
|
export type FilterStateRecord = Record<number, FilterState>
|
|
36
36
|
|
|
37
|
+
function isNodeOpen(rowIndex: number, treeDisplay: TableDisplay[]): boolean {
|
|
38
|
+
const row = treeDisplay[rowIndex]
|
|
39
|
+
if (row.isRoot) {
|
|
40
|
+
return true // Root nodes are always open
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (row.parent === null || row.parent === undefined) {
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const parentIndex = row.parent
|
|
48
|
+
if (parentIndex < 0 || parentIndex >= treeDisplay.length) {
|
|
49
|
+
return false
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const parent = treeDisplay[parentIndex]
|
|
53
|
+
// Node is open if parent's children are open AND parent itself is open
|
|
54
|
+
return (parent.childrenOpen || false) && isNodeOpen(parentIndex, treeDisplay)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function applyFilter(cellValue: any, filter: FilterState, column: TableColumn): boolean {
|
|
58
|
+
const filterType = column.filterType || 'text'
|
|
59
|
+
const value = filter.value
|
|
60
|
+
|
|
61
|
+
if (!value && filterType !== 'dateRange' && filterType !== 'checkbox') return true
|
|
62
|
+
|
|
63
|
+
switch (filterType) {
|
|
64
|
+
case 'text': {
|
|
65
|
+
const searchableText =
|
|
66
|
+
typeof cellValue === 'object' && cellValue !== null
|
|
67
|
+
? Object.values(cellValue).join(' ')
|
|
68
|
+
: String(cellValue || '')
|
|
69
|
+
return searchableText.toLowerCase().includes(String(value).toLowerCase())
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
case 'number': {
|
|
73
|
+
const numValue = Number(cellValue)
|
|
74
|
+
const filterNum = Number(value)
|
|
75
|
+
return !isNaN(numValue) && !isNaN(filterNum) && numValue === filterNum
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
case 'select':
|
|
79
|
+
return cellValue === value
|
|
80
|
+
|
|
81
|
+
case 'checkbox':
|
|
82
|
+
// For checkbox filter, if checked (true), show only truthy values
|
|
83
|
+
// If unchecked (false/undefined), show all values
|
|
84
|
+
if (value === true) {
|
|
85
|
+
return !!cellValue
|
|
86
|
+
}
|
|
87
|
+
return true
|
|
88
|
+
|
|
89
|
+
case 'date': {
|
|
90
|
+
// Handle both timestamp numbers and date strings
|
|
91
|
+
let cellDate: Date
|
|
92
|
+
if (typeof cellValue === 'number') {
|
|
93
|
+
// Apply the same year transformation as in the format function
|
|
94
|
+
const originalDate = new Date(cellValue)
|
|
95
|
+
const currentYear = new Date().getFullYear()
|
|
96
|
+
cellDate = new Date(currentYear, originalDate.getMonth(), originalDate.getDate())
|
|
97
|
+
} else {
|
|
98
|
+
cellDate = new Date(String(cellValue))
|
|
99
|
+
}
|
|
100
|
+
const filterDate = new Date(String(value))
|
|
101
|
+
return cellDate.toDateString() === filterDate.toDateString()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
case 'dateRange': {
|
|
105
|
+
const startValue = filter.startValue
|
|
106
|
+
const endValue = filter.endValue
|
|
107
|
+
if (!startValue && !endValue) return true
|
|
108
|
+
|
|
109
|
+
// Handle both timestamp numbers and date strings
|
|
110
|
+
let cellDateRange: Date
|
|
111
|
+
if (typeof cellValue === 'number') {
|
|
112
|
+
// Apply the same year transformation as in the format function
|
|
113
|
+
const originalDate = new Date(cellValue)
|
|
114
|
+
const currentYear = new Date().getFullYear()
|
|
115
|
+
cellDateRange = new Date(currentYear, originalDate.getMonth(), originalDate.getDate())
|
|
116
|
+
} else {
|
|
117
|
+
cellDateRange = new Date(String(cellValue))
|
|
118
|
+
}
|
|
119
|
+
if (startValue && cellDateRange < new Date(String(startValue))) return false
|
|
120
|
+
if (endValue && cellDateRange > new Date(String(endValue))) return false
|
|
121
|
+
|
|
122
|
+
return true
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
default:
|
|
126
|
+
return true
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function getIndent(colIndex: number, indentLevel?: number): string {
|
|
131
|
+
if (indentLevel && colIndex === 0 && indentLevel > 0) {
|
|
132
|
+
return `${indentLevel}ch`
|
|
133
|
+
} else {
|
|
134
|
+
return 'inherit'
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
37
138
|
/**
|
|
38
139
|
* Create a table store
|
|
39
140
|
* @param initData - Initial data for the table store
|
|
@@ -133,13 +234,13 @@ export const createTableStore = (initData: {
|
|
|
133
234
|
const rowExpandStates = ref<Record<number, { childrenOpen?: boolean; expanded?: boolean }>>({})
|
|
134
235
|
|
|
135
236
|
const table = computed(() => {
|
|
136
|
-
const
|
|
237
|
+
const tableData: Record<string, any> = {}
|
|
137
238
|
for (const [colIndex, column] of columns.value.entries()) {
|
|
138
239
|
for (const [rowIndex, row] of rows.value.entries()) {
|
|
139
|
-
|
|
240
|
+
tableData[`${colIndex}:${rowIndex}`] = row[column.name]
|
|
140
241
|
}
|
|
141
242
|
}
|
|
142
|
-
return
|
|
243
|
+
return tableData
|
|
143
244
|
})
|
|
144
245
|
|
|
145
246
|
const display = computed({
|
|
@@ -164,25 +265,6 @@ export const createTableStore = (initData: {
|
|
|
164
265
|
// Calculate 'open' property for tree view based on parent's childrenOpen state
|
|
165
266
|
if (isTreeView.value) {
|
|
166
267
|
// Helper function to check if all ancestors are open
|
|
167
|
-
const isNodeOpen = (rowIndex: number, display: TableDisplay[]): boolean => {
|
|
168
|
-
const row = display[rowIndex]
|
|
169
|
-
if (row.isRoot) {
|
|
170
|
-
return true // Root nodes are always open
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (row.parent === null || row.parent === undefined) {
|
|
174
|
-
return true
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const parentIndex = row.parent
|
|
178
|
-
if (parentIndex < 0 || parentIndex >= display.length) {
|
|
179
|
-
return false
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const parent = display[parentIndex]
|
|
183
|
-
// Node is open if parent's children are open AND parent itself is open
|
|
184
|
-
return (parent.childrenOpen || false) && isNodeOpen(parentIndex, display)
|
|
185
|
-
}
|
|
186
268
|
|
|
187
269
|
for (let i = 0; i < baseDisplay.length; i++) {
|
|
188
270
|
const row = baseDisplay[i]
|
|
@@ -291,7 +373,7 @@ export const createTableStore = (initData: {
|
|
|
291
373
|
})
|
|
292
374
|
|
|
293
375
|
// actions
|
|
294
|
-
const getCellData =
|
|
376
|
+
const getCellData = (colIndex: number, rowIndex: number): any => table.value[`${colIndex}:${rowIndex}`]
|
|
295
377
|
const setCellData = (colIndex: number, rowIndex: number, value: any) => {
|
|
296
378
|
const index = `${colIndex}:${rowIndex}`
|
|
297
379
|
const col = columns.value[colIndex]
|
|
@@ -431,9 +513,9 @@ export const createTableStore = (initData: {
|
|
|
431
513
|
case 'Check':
|
|
432
514
|
return value ? '✓' : '✗'
|
|
433
515
|
case 'Date':
|
|
434
|
-
return value != null ? new Date(value
|
|
516
|
+
return value != null ? new Date(String(value)).toLocaleDateString() : value
|
|
435
517
|
case 'Datetime':
|
|
436
|
-
return value != null ? new Date(value
|
|
518
|
+
return value != null ? new Date(String(value)).toLocaleString() : value
|
|
437
519
|
default:
|
|
438
520
|
return value
|
|
439
521
|
}
|
|
@@ -443,7 +525,7 @@ export const createTableStore = (initData: {
|
|
|
443
525
|
return format(value, { table: table.value, row, column })
|
|
444
526
|
} else if (typeof format === 'string') {
|
|
445
527
|
// parse format function from string
|
|
446
|
-
//
|
|
528
|
+
// oxlint-disable-next-line @typescript-eslint/no-implied-eval
|
|
447
529
|
const formatFn: (value: any, context?: CellContext) => string = Function(`"use strict";return (${format})`)()
|
|
448
530
|
return formatFn(value, { table: table.value, row, column })
|
|
449
531
|
}
|
|
@@ -461,14 +543,6 @@ export const createTableStore = (initData: {
|
|
|
461
543
|
}
|
|
462
544
|
}
|
|
463
545
|
|
|
464
|
-
const getIndent = (colIndex: number, indentLevel?: number) => {
|
|
465
|
-
if (indentLevel && colIndex === 0 && indentLevel > 0) {
|
|
466
|
-
return `${indentLevel}ch`
|
|
467
|
-
} else {
|
|
468
|
-
return 'inherit'
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
546
|
const updateGanttBar = (event: GanttDragEvent) => {
|
|
473
547
|
// update the local gantt bar cache
|
|
474
548
|
const ganttBar = rows.value[event.rowIndex]?.gantt
|
|
@@ -536,7 +610,6 @@ export const createTableStore = (initData: {
|
|
|
536
610
|
const toHandle = connectionHandles.value.find(h => h.id === toHandleId)
|
|
537
611
|
|
|
538
612
|
if (!fromHandle || !toHandle) {
|
|
539
|
-
// eslint-disable-next-line no-console
|
|
540
613
|
console.warn('Cannot create connection: handle not found')
|
|
541
614
|
return null
|
|
542
615
|
}
|
|
@@ -598,79 +671,6 @@ export const createTableStore = (initData: {
|
|
|
598
671
|
// This ensures that sorting works on filtered data without modifying the original rows
|
|
599
672
|
}
|
|
600
673
|
|
|
601
|
-
const applyFilter = (cellValue: any, filter: FilterState, column: TableColumn): boolean => {
|
|
602
|
-
const filterType = column.filterType || 'text'
|
|
603
|
-
const value = filter.value
|
|
604
|
-
|
|
605
|
-
if (!value && filterType !== 'dateRange' && filterType !== 'checkbox') return true
|
|
606
|
-
|
|
607
|
-
switch (filterType) {
|
|
608
|
-
case 'text': {
|
|
609
|
-
const searchableText =
|
|
610
|
-
typeof cellValue === 'object' && cellValue !== null
|
|
611
|
-
? Object.values(cellValue as Record<string, unknown>).join(' ')
|
|
612
|
-
: String(cellValue || '')
|
|
613
|
-
return searchableText.toLowerCase().includes(String(value).toLowerCase())
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
case 'number': {
|
|
617
|
-
const numValue = Number(cellValue)
|
|
618
|
-
const filterNum = Number(value)
|
|
619
|
-
return !isNaN(numValue) && !isNaN(filterNum) && numValue === filterNum
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
case 'select':
|
|
623
|
-
return cellValue === value
|
|
624
|
-
|
|
625
|
-
case 'checkbox':
|
|
626
|
-
// For checkbox filter, if checked (true), show only truthy values
|
|
627
|
-
// If unchecked (false/undefined), show all values
|
|
628
|
-
if (value === true) {
|
|
629
|
-
return !!cellValue
|
|
630
|
-
}
|
|
631
|
-
return true
|
|
632
|
-
|
|
633
|
-
case 'date': {
|
|
634
|
-
// Handle both timestamp numbers and date strings
|
|
635
|
-
let cellDate: Date
|
|
636
|
-
if (typeof cellValue === 'number') {
|
|
637
|
-
// Apply the same year transformation as in the format function
|
|
638
|
-
const originalDate = new Date(cellValue)
|
|
639
|
-
const currentYear = new Date().getFullYear()
|
|
640
|
-
cellDate = new Date(currentYear, originalDate.getMonth(), originalDate.getDate())
|
|
641
|
-
} else {
|
|
642
|
-
cellDate = new Date(String(cellValue))
|
|
643
|
-
}
|
|
644
|
-
const filterDate = new Date(String(value))
|
|
645
|
-
return cellDate.toDateString() === filterDate.toDateString()
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
case 'dateRange': {
|
|
649
|
-
const startValue = filter.startValue
|
|
650
|
-
const endValue = filter.endValue
|
|
651
|
-
if (!startValue && !endValue) return true
|
|
652
|
-
|
|
653
|
-
// Handle both timestamp numbers and date strings
|
|
654
|
-
let cellDateRange: Date
|
|
655
|
-
if (typeof cellValue === 'number') {
|
|
656
|
-
// Apply the same year transformation as in the format function
|
|
657
|
-
const originalDate = new Date(cellValue)
|
|
658
|
-
const currentYear = new Date().getFullYear()
|
|
659
|
-
cellDateRange = new Date(currentYear, originalDate.getMonth(), originalDate.getDate())
|
|
660
|
-
} else {
|
|
661
|
-
cellDateRange = new Date(String(cellValue))
|
|
662
|
-
}
|
|
663
|
-
if (startValue && cellDateRange < new Date(String(startValue))) return false
|
|
664
|
-
if (endValue && cellDateRange > new Date(String(endValue))) return false
|
|
665
|
-
|
|
666
|
-
return true
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
default:
|
|
670
|
-
return true
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
|
|
674
674
|
const setFilter = (colIndex: number, filter: FilterState) => {
|
|
675
675
|
if (!filter.value && !filter.startValue && !filter.endValue) {
|
|
676
676
|
// Remove filter if empty
|