@stonecrop/atable 0.2.63 → 0.2.64
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 +3 -3
- package/dist/atable.js +1742 -779
- package/dist/atable.js.map +1 -1
- package/dist/atable.umd.cjs +12 -2
- package/dist/atable.umd.cjs.map +1 -1
- package/dist/index.js +5 -2
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/stores/table.d.ts +320 -0
- package/dist/src/stores/table.d.ts.map +1 -0
- package/dist/src/types/index.d.ts +3 -2
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/stores/table.js +174 -0
- package/package.json +5 -4
- package/src/components/ACell.vue +32 -63
- package/src/components/AExpansionRow.vue +9 -10
- package/src/components/ARow.vue +14 -33
- package/src/components/ATable.vue +47 -57
- package/src/components/ATableHeader.vue +10 -19
- package/src/components/ATableModal.vue +5 -8
- package/src/index.ts +6 -2
- package/src/stores/table.ts +208 -0
- package/src/types/index.ts +1 -3
- package/dist/components/index.js +0 -97
- package/dist/src/components/index.d.ts +0 -23
- package/dist/src/components/index.d.ts.map +0 -1
- package/src/components/index.ts +0 -120
package/src/components/ACell.vue
CHANGED
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
@blur="updateCellData"
|
|
14
14
|
@input="updateCellData"
|
|
15
15
|
@click="showModal"
|
|
16
|
-
@mousedown="showModal"
|
|
17
16
|
class="atable-cell"
|
|
18
|
-
:class="pinned ? 'sticky-column' : ''"
|
|
17
|
+
:class="pinned ? 'sticky-column' : ''"
|
|
18
|
+
v-on-click-outside="store.closeModal">
|
|
19
19
|
<component
|
|
20
20
|
v-if="column.cellComponent"
|
|
21
21
|
:is="column.cellComponent"
|
|
@@ -28,47 +28,46 @@
|
|
|
28
28
|
|
|
29
29
|
<script setup lang="ts">
|
|
30
30
|
import { KeypressHandlers, defaultKeypressHandlers, useKeyboardNav } from '@stonecrop/utilities'
|
|
31
|
+
import { vOnClickOutside } from '@vueuse/components'
|
|
31
32
|
import { useElementBounding } from '@vueuse/core'
|
|
32
|
-
import { computed, CSSProperties,
|
|
33
|
+
import { computed, CSSProperties, ref, useTemplateRef } from 'vue'
|
|
33
34
|
|
|
34
|
-
import
|
|
35
|
-
import type { CellContext } from '@/types'
|
|
35
|
+
import { createTableStore } from '@/stores/table'
|
|
36
36
|
import { isHtmlString } from '@/utils'
|
|
37
37
|
|
|
38
38
|
const {
|
|
39
39
|
colIndex,
|
|
40
40
|
rowIndex,
|
|
41
|
-
|
|
41
|
+
store,
|
|
42
42
|
addNavigation = true,
|
|
43
43
|
tabIndex = 0,
|
|
44
44
|
} = defineProps<{
|
|
45
45
|
colIndex: number
|
|
46
46
|
rowIndex: number
|
|
47
|
-
|
|
47
|
+
store: ReturnType<typeof createTableStore>
|
|
48
48
|
addNavigation?: boolean | KeypressHandlers
|
|
49
49
|
tabIndex?: number
|
|
50
50
|
pinned?: boolean
|
|
51
51
|
}>()
|
|
52
52
|
|
|
53
|
-
const tableData = inject<TableDataStore>(tableid)
|
|
54
53
|
const cellRef = useTemplateRef<HTMLTableCellElement>('cell')
|
|
55
54
|
const { bottom, left } = useElementBounding(cellRef)
|
|
56
55
|
|
|
57
56
|
// keep a shallow copy of the original cell value for comparison
|
|
58
|
-
const originalData =
|
|
57
|
+
const originalData = store.getCellData(colIndex, rowIndex)
|
|
58
|
+
const displayValue = store.getCellDisplayValue(colIndex, rowIndex)
|
|
59
59
|
const currentData = ref('')
|
|
60
60
|
const cellModified = ref(false)
|
|
61
61
|
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
const row = tableData.rows[rowIndex]
|
|
62
|
+
const column = store.columns[colIndex]
|
|
63
|
+
const row = store.rows[rowIndex]
|
|
65
64
|
|
|
66
65
|
const textAlign = column.align || 'center'
|
|
67
66
|
const cellWidth = column.width || '40ch'
|
|
68
67
|
|
|
69
68
|
const isHtmlValue = computed(() => {
|
|
70
69
|
// TODO: check if display value is a native DOM element
|
|
71
|
-
return typeof displayValue
|
|
70
|
+
return typeof displayValue === 'string' ? isHtmlString(displayValue) : false
|
|
72
71
|
})
|
|
73
72
|
|
|
74
73
|
const cellStyle = computed((): CSSProperties => {
|
|
@@ -77,34 +76,10 @@ const cellStyle = computed((): CSSProperties => {
|
|
|
77
76
|
width: cellWidth,
|
|
78
77
|
backgroundColor: !cellModified.value ? 'inherit' : 'var(--sc-cell-modified)',
|
|
79
78
|
fontWeight: !cellModified.value ? 'inherit' : 'bold',
|
|
80
|
-
paddingLeft: getIndent(colIndex,
|
|
79
|
+
paddingLeft: store.getIndent(colIndex, store.display[rowIndex]?.indent),
|
|
81
80
|
}
|
|
82
81
|
})
|
|
83
82
|
|
|
84
|
-
const displayValue = computed(() => {
|
|
85
|
-
const cellData = tableData.cellData<any>(colIndex, rowIndex)
|
|
86
|
-
return getFormattedValue(cellData)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
const getFormattedValue = (value: any) => {
|
|
90
|
-
const format = column.format
|
|
91
|
-
|
|
92
|
-
if (!format) {
|
|
93
|
-
return value
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (typeof format === 'function') {
|
|
97
|
-
return format(value, { table, row, column })
|
|
98
|
-
} else if (typeof format === 'string') {
|
|
99
|
-
// parse format function from string
|
|
100
|
-
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
101
|
-
const formatFn: (value: any, context?: CellContext) => string = Function(`"use strict";return (${format})`)()
|
|
102
|
-
return formatFn(value, { table, row, column })
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return value
|
|
106
|
-
}
|
|
107
|
-
|
|
108
83
|
const showModal = () => {
|
|
109
84
|
if (column.mask) {
|
|
110
85
|
// TODO: add masking to cell values
|
|
@@ -112,21 +87,23 @@ const showModal = () => {
|
|
|
112
87
|
}
|
|
113
88
|
|
|
114
89
|
if (column.modalComponent) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
90
|
+
store.$patch(state => {
|
|
91
|
+
state.modal.visible = true
|
|
92
|
+
state.modal.colIndex = colIndex
|
|
93
|
+
state.modal.rowIndex = rowIndex
|
|
94
|
+
state.modal.parent = cellRef.value
|
|
95
|
+
state.modal.top = bottom.value
|
|
96
|
+
state.modal.left = left.value
|
|
97
|
+
state.modal.width = cellWidth
|
|
98
|
+
|
|
99
|
+
if (typeof column.modalComponent === 'function') {
|
|
100
|
+
state.modal.component = column.modalComponent({ table: state.table, row, column })
|
|
101
|
+
} else {
|
|
102
|
+
state.modal.component = column.modalComponent
|
|
103
|
+
}
|
|
128
104
|
|
|
129
|
-
|
|
105
|
+
state.modal.componentProps = column.modalComponentExtraProps
|
|
106
|
+
})
|
|
130
107
|
}
|
|
131
108
|
}
|
|
132
109
|
|
|
@@ -161,7 +138,7 @@ if (addNavigation) {
|
|
|
161
138
|
// if (event) {
|
|
162
139
|
// // custom components need to handle their own updateData, this is the default
|
|
163
140
|
// if (!column.component) {
|
|
164
|
-
//
|
|
141
|
+
// store.setCellData(colIndex, rowIndex, cell.value.innerHTML)
|
|
165
142
|
// }
|
|
166
143
|
// cellModified.value = true
|
|
167
144
|
// }
|
|
@@ -177,7 +154,7 @@ const updateCellData = () => {
|
|
|
177
154
|
if (cellRef.value) {
|
|
178
155
|
// only apply changes if the cell value has changed after being mounted
|
|
179
156
|
if (column.format) {
|
|
180
|
-
cellModified.value = cellRef.value.textContent !== getFormattedValue(originalData)
|
|
157
|
+
cellModified.value = cellRef.value.textContent !== store.getFormattedValue(colIndex, rowIndex, originalData)
|
|
181
158
|
} else {
|
|
182
159
|
cellModified.value = cellRef.value.textContent !== originalData
|
|
183
160
|
}
|
|
@@ -187,19 +164,11 @@ const updateCellData = () => {
|
|
|
187
164
|
cellRef.value.dispatchEvent(new Event('change'))
|
|
188
165
|
if (!column.format) {
|
|
189
166
|
// TODO: need to setup reverse format function
|
|
190
|
-
|
|
167
|
+
store.setCellData(colIndex, rowIndex, currentData.value)
|
|
191
168
|
}
|
|
192
169
|
}
|
|
193
170
|
}
|
|
194
171
|
}
|
|
195
|
-
|
|
196
|
-
const getIndent = (colIndex: number, indentLevel?: number) => {
|
|
197
|
-
if (indentLevel && colIndex === 0 && indentLevel > 0) {
|
|
198
|
-
return `${indentLevel}ch`
|
|
199
|
-
} else {
|
|
200
|
-
return 'inherit'
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
172
|
</script>
|
|
204
173
|
|
|
205
174
|
<style>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<tr v-bind="$attrs" ref="rowEl" :tabindex="tabIndex" class="expandable-row">
|
|
3
|
-
<td :tabIndex="-1" @click="
|
|
3
|
+
<td :tabIndex="-1" @click="store.toggleRowExpand(rowIndex)" class="row-index">
|
|
4
4
|
{{ rowExpandSymbol }}
|
|
5
5
|
</td>
|
|
6
6
|
<slot name="row" />
|
|
7
7
|
</tr>
|
|
8
|
-
<tr v-if="
|
|
9
|
-
<td :tabIndex="-1" :colspan="
|
|
8
|
+
<tr v-if="store.display[rowIndex].expanded" ref="rowExpanded" :tabindex="tabIndex" class="expanded-row">
|
|
9
|
+
<td :tabIndex="-1" :colspan="store.columns.length + 1" class="expanded-row-content">
|
|
10
10
|
<slot name="content" />
|
|
11
11
|
</td>
|
|
12
12
|
</tr>
|
|
@@ -14,28 +14,27 @@
|
|
|
14
14
|
|
|
15
15
|
<script setup lang="ts">
|
|
16
16
|
import { type KeypressHandlers, useKeyboardNav } from '@stonecrop/utilities'
|
|
17
|
-
import { computed,
|
|
17
|
+
import { computed, useTemplateRef } from 'vue'
|
|
18
18
|
|
|
19
|
-
import
|
|
19
|
+
import { createTableStore } from '@/stores/table'
|
|
20
20
|
|
|
21
21
|
const {
|
|
22
22
|
rowIndex,
|
|
23
|
-
|
|
23
|
+
store,
|
|
24
24
|
tabIndex = -1,
|
|
25
25
|
addNavigation,
|
|
26
26
|
} = defineProps<{
|
|
27
27
|
rowIndex: number
|
|
28
|
-
|
|
28
|
+
store: ReturnType<typeof createTableStore>
|
|
29
29
|
tabIndex?: number
|
|
30
30
|
addNavigation?: boolean | KeypressHandlers
|
|
31
31
|
}>()
|
|
32
32
|
|
|
33
|
-
const tableData = inject<TableDataStore>(tableid)
|
|
34
33
|
const rowRef = useTemplateRef<HTMLTableRowElement>('rowEl')
|
|
35
34
|
// const expandedRowRef = useTemplateRef<HTMLDivElement>('rowExpanded')
|
|
36
35
|
|
|
37
36
|
const rowExpandSymbol = computed(() => {
|
|
38
|
-
return
|
|
37
|
+
return store.display[rowIndex].expanded ? '▼' : '►'
|
|
39
38
|
})
|
|
40
39
|
|
|
41
40
|
if (addNavigation) {
|
|
@@ -43,7 +42,7 @@ if (addNavigation) {
|
|
|
43
42
|
'keydown.control.g': (event: KeyboardEvent) => {
|
|
44
43
|
event.stopPropagation()
|
|
45
44
|
event.preventDefault()
|
|
46
|
-
|
|
45
|
+
store.toggleRowExpand(rowIndex)
|
|
47
46
|
},
|
|
48
47
|
}
|
|
49
48
|
|
package/src/components/ARow.vue
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<tr ref="rowEl" :tabindex="tabIndex" v-show="isRowVisible" class="table-row">
|
|
3
3
|
<!-- render numbered/tree view index; skip render for uncounted lists -->
|
|
4
|
-
<slot name="index" v-if="
|
|
4
|
+
<slot name="index" v-if="store.config.view !== 'uncounted'">
|
|
5
5
|
<td
|
|
6
|
-
v-if="
|
|
6
|
+
v-if="store.config.view === 'list'"
|
|
7
7
|
:tabIndex="-1"
|
|
8
8
|
class="list-index"
|
|
9
|
-
:class="hasPinnedColumns ? 'sticky-index' : ''">
|
|
9
|
+
:class="store.hasPinnedColumns ? 'sticky-index' : ''">
|
|
10
10
|
{{ rowIndex + 1 }}
|
|
11
11
|
</td>
|
|
12
12
|
<td
|
|
13
|
-
v-else-if="
|
|
13
|
+
v-else-if="store.config.view === 'tree'"
|
|
14
14
|
:tabIndex="-1"
|
|
15
15
|
class="tree-index"
|
|
16
|
-
:class="hasPinnedColumns ? 'sticky-index' : ''"
|
|
17
|
-
@click="toggleRowExpand(rowIndex)">
|
|
16
|
+
:class="store.hasPinnedColumns ? 'sticky-index' : ''"
|
|
17
|
+
@click="store.toggleRowExpand(rowIndex)">
|
|
18
18
|
{{ rowExpandSymbol }}
|
|
19
19
|
</td>
|
|
20
20
|
</slot>
|
|
@@ -26,46 +26,25 @@
|
|
|
26
26
|
|
|
27
27
|
<script setup lang="ts">
|
|
28
28
|
import { type KeypressHandlers, useKeyboardNav, defaultKeypressHandlers } from '@stonecrop/utilities'
|
|
29
|
-
import {
|
|
29
|
+
import { useTemplateRef } from 'vue'
|
|
30
30
|
|
|
31
|
-
import
|
|
31
|
+
import { createTableStore } from '@/stores/table'
|
|
32
32
|
|
|
33
33
|
const {
|
|
34
34
|
rowIndex,
|
|
35
|
-
|
|
35
|
+
store,
|
|
36
36
|
tabIndex = -1,
|
|
37
37
|
addNavigation = false, // default to allowing cell navigation
|
|
38
38
|
} = defineProps<{
|
|
39
39
|
rowIndex: number
|
|
40
|
-
|
|
40
|
+
store: ReturnType<typeof createTableStore>
|
|
41
41
|
tabIndex?: number
|
|
42
42
|
addNavigation?: boolean | KeypressHandlers
|
|
43
43
|
}>()
|
|
44
44
|
|
|
45
|
-
const tableData = inject<TableDataStore>(tableid)
|
|
46
45
|
const rowRef = useTemplateRef<HTMLTableRowElement>('rowEl')
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
const isRowVisible = computed(() => {
|
|
51
|
-
return tableData.config.view !== 'tree' || tableData.display[rowIndex].isRoot || tableData.display[rowIndex].open
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
const rowExpandSymbol = computed(() => {
|
|
55
|
-
if (tableData.config.view !== 'tree') {
|
|
56
|
-
return ''
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (tableData.display[rowIndex].isRoot || tableData.display[rowIndex].isParent) {
|
|
60
|
-
return tableData.display[rowIndex].childrenOpen ? '-' : '+'
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return ''
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
const toggleRowExpand = (rowIndex: number) => {
|
|
67
|
-
tableData.toggleRowExpand(rowIndex)
|
|
68
|
-
}
|
|
46
|
+
const isRowVisible = store.isRowVisible(rowIndex)
|
|
47
|
+
const rowExpandSymbol = store.getRowExpandSymbol(rowIndex)
|
|
69
48
|
|
|
70
49
|
if (addNavigation) {
|
|
71
50
|
let handlers = defaultKeypressHandlers
|
|
@@ -94,6 +73,7 @@ if (addNavigation) {
|
|
|
94
73
|
display: flex;
|
|
95
74
|
background-color: white;
|
|
96
75
|
}
|
|
76
|
+
|
|
97
77
|
.list-index {
|
|
98
78
|
color: var(--sc-header-text-color);
|
|
99
79
|
font-weight: bold;
|
|
@@ -108,6 +88,7 @@ if (addNavigation) {
|
|
|
108
88
|
padding-top: var(--sc-atable-row-padding);
|
|
109
89
|
padding-bottom: var(--sc-atable-row-padding);
|
|
110
90
|
}
|
|
91
|
+
|
|
111
92
|
.tree-index {
|
|
112
93
|
color: var(--sc-header-text-color);
|
|
113
94
|
font-weight: bold;
|
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<table
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
:style="{ width: tableData.config.fullWidth ? '100%' : 'auto' }"
|
|
6
|
-
v-on-click-outside="closeModal">
|
|
7
|
-
<slot name="header" :data="tableData">
|
|
8
|
-
<ATableHeader :columns="tableData.columns" :tableid="tableData.id" />
|
|
2
|
+
<table ref="table" class="atable" :style="{ width: store.config.fullWidth ? '100%' : 'auto' }">
|
|
3
|
+
<slot name="header" :data="store">
|
|
4
|
+
<ATableHeader :columns="store.columns" :store="store" />
|
|
9
5
|
</slot>
|
|
10
6
|
|
|
11
7
|
<tbody>
|
|
12
|
-
<slot name="body" :data="
|
|
13
|
-
<ARow
|
|
14
|
-
v-for="(row, rowIndex) in tableData.rows"
|
|
15
|
-
:key="row.id"
|
|
16
|
-
:row="row"
|
|
17
|
-
:rowIndex="rowIndex"
|
|
18
|
-
:tableid="tableData.id">
|
|
8
|
+
<slot name="body" :data="store">
|
|
9
|
+
<ARow v-for="(row, rowIndex) in store.rows" :key="row.id" :row="row" :rowIndex="rowIndex" :store="store">
|
|
19
10
|
<ACell
|
|
20
|
-
v-for="(col, colIndex) in
|
|
11
|
+
v-for="(col, colIndex) in store.columns"
|
|
21
12
|
:key="col.name"
|
|
22
|
-
:
|
|
13
|
+
:store="store"
|
|
23
14
|
:col="col"
|
|
24
15
|
spellcheck="false"
|
|
25
16
|
:pinned="col.pinned"
|
|
@@ -29,32 +20,32 @@
|
|
|
29
20
|
:style="{
|
|
30
21
|
textAlign: col?.align || 'center',
|
|
31
22
|
minWidth: col?.width || '40ch',
|
|
32
|
-
width:
|
|
23
|
+
width: store.config.fullWidth ? 'auto' : null,
|
|
33
24
|
}" />
|
|
34
25
|
</ARow>
|
|
35
26
|
</slot>
|
|
36
27
|
</tbody>
|
|
37
28
|
|
|
38
|
-
<slot name="footer" :data="
|
|
39
|
-
<slot name="modal" :data="
|
|
29
|
+
<slot name="footer" :data="store" />
|
|
30
|
+
<slot name="modal" :data="store">
|
|
40
31
|
<ATableModal
|
|
41
|
-
v-show="
|
|
42
|
-
:colIndex="
|
|
43
|
-
:rowIndex="
|
|
44
|
-
:
|
|
32
|
+
v-show="store.modal.visible"
|
|
33
|
+
:colIndex="store.modal.colIndex"
|
|
34
|
+
:rowIndex="store.modal.rowIndex"
|
|
35
|
+
:store="store"
|
|
45
36
|
:style="{
|
|
46
|
-
left:
|
|
47
|
-
top:
|
|
48
|
-
maxWidth:
|
|
37
|
+
left: store.modal.left + 'px',
|
|
38
|
+
top: store.modal.top + 'px',
|
|
39
|
+
maxWidth: store.modal.width + 'px',
|
|
49
40
|
}">
|
|
50
41
|
<template #default>
|
|
51
42
|
<component
|
|
52
|
-
:key="`${
|
|
53
|
-
:is="
|
|
54
|
-
:colIndex="
|
|
55
|
-
:rowIndex="
|
|
56
|
-
:
|
|
57
|
-
v-bind="
|
|
43
|
+
:key="`${store.modal.rowIndex}:${store.modal.colIndex}`"
|
|
44
|
+
:is="store.modal.component"
|
|
45
|
+
:colIndex="store.modal.colIndex"
|
|
46
|
+
:rowIndex="store.modal.rowIndex"
|
|
47
|
+
:store="store"
|
|
48
|
+
v-bind="store.modal.componentProps" />
|
|
58
49
|
</template>
|
|
59
50
|
</ATableModal>
|
|
60
51
|
</slot>
|
|
@@ -62,15 +53,14 @@
|
|
|
62
53
|
</template>
|
|
63
54
|
|
|
64
55
|
<script setup lang="ts">
|
|
65
|
-
import { vOnClickOutside } from '@vueuse/components'
|
|
66
56
|
import { useMutationObserver } from '@vueuse/core'
|
|
67
|
-
import { nextTick,
|
|
57
|
+
import { nextTick, watch, onMounted, useTemplateRef } from 'vue'
|
|
68
58
|
|
|
69
|
-
import TableDataStore from '.'
|
|
70
59
|
import ACell from '@/components/ACell.vue'
|
|
71
60
|
import ARow from '@/components/ARow.vue'
|
|
72
61
|
import ATableHeader from '@/components/ATableHeader.vue'
|
|
73
62
|
import ATableModal from '@/components/ATableModal.vue'
|
|
63
|
+
import { createTableStore } from '@/stores/table'
|
|
74
64
|
import type { TableColumn, TableConfig, TableRow } from '@/types'
|
|
75
65
|
|
|
76
66
|
const {
|
|
@@ -87,15 +77,25 @@ const {
|
|
|
87
77
|
config?: TableConfig
|
|
88
78
|
}>()
|
|
89
79
|
|
|
90
|
-
const emit = defineEmits
|
|
80
|
+
const emit = defineEmits<{
|
|
81
|
+
'update:modelValue': [value: TableRow[]]
|
|
82
|
+
cellUpdate: [colIndex: number, rowIndex: number, newCellValue: any, prevCellValue: any]
|
|
83
|
+
}>()
|
|
91
84
|
|
|
92
85
|
const tableRef = useTemplateRef<HTMLTableElement>('table')
|
|
93
86
|
const rowsValue = modelValue ? modelValue : rows
|
|
94
|
-
const
|
|
95
|
-
|
|
87
|
+
const store = createTableStore({ columns, rows: rowsValue, id, config })
|
|
88
|
+
|
|
89
|
+
store.$onAction(({ name, store, args }) => {
|
|
90
|
+
if (name === 'setCellData') {
|
|
91
|
+
const [colIndex, rowIndex, newCellValue] = args
|
|
92
|
+
const prevCellValue = store.getCellData(colIndex, rowIndex)
|
|
93
|
+
emit('cellUpdate', [colIndex, rowIndex, newCellValue, prevCellValue])
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
96
|
|
|
97
97
|
watch(
|
|
98
|
-
() =>
|
|
98
|
+
() => store.rows,
|
|
99
99
|
newValue => {
|
|
100
100
|
emit('update:modelValue', newValue)
|
|
101
101
|
},
|
|
@@ -107,7 +107,7 @@ onMounted(() => {
|
|
|
107
107
|
assignStickyCellWidths()
|
|
108
108
|
|
|
109
109
|
// in tree view, also add a mutation observer to capture and adjust expanded rows
|
|
110
|
-
if (
|
|
110
|
+
if (store.config.view === 'tree') {
|
|
111
111
|
useMutationObserver(tableRef, assignStickyCellWidths, { childList: true, subtree: true })
|
|
112
112
|
}
|
|
113
113
|
}
|
|
@@ -153,12 +153,12 @@ const assignStickyCellWidths = () => {
|
|
|
153
153
|
// if (event) {
|
|
154
154
|
// colIndex = target.cellIndex
|
|
155
155
|
// } else if (column && cellData) {
|
|
156
|
-
// colIndex =
|
|
156
|
+
// colIndex = store.columns.indexOf(column)
|
|
157
157
|
// }
|
|
158
158
|
|
|
159
|
-
// if (!column && 'format' in
|
|
159
|
+
// if (!column && 'format' in store.columns[colIndex]) {
|
|
160
160
|
// // TODO: (utils) create helper to extract format from string
|
|
161
|
-
// const format =
|
|
161
|
+
// const format = store.columns[colIndex].format
|
|
162
162
|
// if (typeof format === 'function') {
|
|
163
163
|
// return format(target.innerHTML)
|
|
164
164
|
// } else if (typeof format === 'string') {
|
|
@@ -195,23 +195,13 @@ const assignStickyCellWidths = () => {
|
|
|
195
195
|
// document.getSelection().collapseToEnd()
|
|
196
196
|
// }
|
|
197
197
|
|
|
198
|
-
const closeModal = (event: MouseEvent) => {
|
|
199
|
-
if (!(event.target instanceof Node)) {
|
|
200
|
-
// if the target is not a node, it's probably a custom click event to Document or Window
|
|
201
|
-
// err on the side of closing the modal in that case
|
|
202
|
-
if (tableData.modal.visible) tableData.modal.visible = false
|
|
203
|
-
} else if (!tableData.modal.parent?.contains(event.target)) {
|
|
204
|
-
if (tableData.modal.visible) tableData.modal.visible = false
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
198
|
window.addEventListener('keydown', (event: KeyboardEvent) => {
|
|
209
199
|
if (event.key === 'Escape') {
|
|
210
|
-
if (
|
|
211
|
-
|
|
200
|
+
if (store.modal.visible) {
|
|
201
|
+
store.modal.visible = false
|
|
212
202
|
|
|
213
203
|
// focus on the parent cell again
|
|
214
|
-
const $parent =
|
|
204
|
+
const $parent = store.modal.parent
|
|
215
205
|
if ($parent) {
|
|
216
206
|
// wait for the modal to close before focusing
|
|
217
207
|
void nextTick().then(() => {
|
|
@@ -222,7 +212,7 @@ window.addEventListener('keydown', (event: KeyboardEvent) => {
|
|
|
222
212
|
}
|
|
223
213
|
})
|
|
224
214
|
|
|
225
|
-
defineExpose({
|
|
215
|
+
defineExpose({ store })
|
|
226
216
|
</script>
|
|
227
217
|
|
|
228
218
|
<style>
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
<thead id="resizable" v-if="columns.length">
|
|
3
3
|
<tr class="atable-header-row" tabindex="-1">
|
|
4
4
|
<th
|
|
5
|
-
v-if="
|
|
5
|
+
v-if="store.zeroColumn"
|
|
6
6
|
id="header-index"
|
|
7
7
|
:class="[
|
|
8
|
-
hasPinnedColumns ? 'sticky-index' : '',
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
store.hasPinnedColumns ? 'sticky-index' : '',
|
|
9
|
+
store.config.view === 'tree' ? 'tree-index' : '',
|
|
10
|
+
store.config.view === 'list-expansion' ? 'list-expansion-index' : '',
|
|
11
11
|
]"
|
|
12
12
|
class="list-index" />
|
|
13
13
|
<th
|
|
14
14
|
v-for="(column, colKey) in columns"
|
|
15
15
|
:key="column.name"
|
|
16
16
|
tabindex="-1"
|
|
17
|
-
:style="getHeaderCellStyle(column)"
|
|
17
|
+
:style="store.getHeaderCellStyle(column)"
|
|
18
18
|
:class="column.pinned ? 'sticky-column' : ''">
|
|
19
19
|
<slot>{{ column.label || String.fromCharCode(colKey + 97).toUpperCase() }}</slot>
|
|
20
20
|
</th>
|
|
@@ -23,22 +23,13 @@
|
|
|
23
23
|
</template>
|
|
24
24
|
|
|
25
25
|
<script setup lang="ts">
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
import TableDataStore from '.'
|
|
26
|
+
import { createTableStore } from '@/stores/table'
|
|
29
27
|
import type { TableColumn } from '@/types'
|
|
30
28
|
|
|
31
|
-
const { columns,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const hasPinnedColumns = computed(() => tableData.columns.some(col => col.pinned))
|
|
36
|
-
|
|
37
|
-
const getHeaderCellStyle = (column: TableColumn): CSSProperties => ({
|
|
38
|
-
minWidth: column.width || '40ch',
|
|
39
|
-
textAlign: column.align || 'center',
|
|
40
|
-
width: tableData.config.fullWidth ? 'auto' : null,
|
|
41
|
-
})
|
|
29
|
+
const { columns, store } = defineProps<{
|
|
30
|
+
columns: TableColumn[]
|
|
31
|
+
store: ReturnType<typeof createTableStore>
|
|
32
|
+
}>()
|
|
42
33
|
</script>
|
|
43
34
|
|
|
44
35
|
<style>
|
|
@@ -5,20 +5,17 @@
|
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup lang="ts">
|
|
8
|
-
|
|
8
|
+
import { createTableStore } from '@/stores/table'
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/* const { colIndex, rowIndex, tableid } = */ defineProps<{
|
|
10
|
+
/* const { colIndex, rowIndex, store } = */ defineProps<{
|
|
13
11
|
colIndex?: number
|
|
14
12
|
rowIndex?: number
|
|
15
|
-
|
|
13
|
+
store?: ReturnType<typeof createTableStore>
|
|
16
14
|
}>()
|
|
17
15
|
|
|
18
|
-
// const tableData = inject<TableDataStore>(tableid)
|
|
19
16
|
// const cellBackgroundColor = computed(() => {
|
|
20
|
-
// if (
|
|
21
|
-
// let computedstyle = window.getComputedStyle(
|
|
17
|
+
// if (store.modal.parent) {
|
|
18
|
+
// let computedstyle = window.getComputedStyle(store.modal.parent)
|
|
22
19
|
// return 'blue'
|
|
23
20
|
// } else {
|
|
24
21
|
// return 'inherit'
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createPinia } from 'pinia'
|
|
1
2
|
import { App } from 'vue'
|
|
2
3
|
|
|
3
4
|
import ACell from '@/components/ACell.vue'
|
|
@@ -6,7 +7,7 @@ import ARow from '@/components/ARow.vue'
|
|
|
6
7
|
import ATable from '@/components/ATable.vue'
|
|
7
8
|
import ATableHeader from '@/components/ATableHeader.vue'
|
|
8
9
|
import ATableModal from '@/components/ATableModal.vue'
|
|
9
|
-
|
|
10
|
+
export { createTableStore } from '@/stores/table'
|
|
10
11
|
export type { CellContext, TableColumn, TableConfig, TableDisplay, TableRow, TableModal } from '@/types'
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -15,6 +16,9 @@ export type { CellContext, TableColumn, TableConfig, TableDisplay, TableRow, Tab
|
|
|
15
16
|
* @public
|
|
16
17
|
*/
|
|
17
18
|
function install(app: App /* options */) {
|
|
19
|
+
const pinia = createPinia()
|
|
20
|
+
app.use(pinia)
|
|
21
|
+
|
|
18
22
|
app.component('ACell', ACell)
|
|
19
23
|
app.component('AExpansionRow', AExpansionRow)
|
|
20
24
|
app.component('ARow', ARow)
|
|
@@ -23,4 +27,4 @@ function install(app: App /* options */) {
|
|
|
23
27
|
app.component('ATableModal', ATableModal)
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
export { install, ACell, AExpansionRow, ARow, ATable, ATableHeader, ATableModal
|
|
30
|
+
export { install, ACell, AExpansionRow, ARow, ATable, ATableHeader, ATableModal }
|