@stonecrop/atable 0.30.0 → 0.32.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/assets/index.css +804 -1
- package/dist/atable.js +2809 -1944
- package/dist/atable.js.map +1 -1
- package/dist/src/components/ACell.vue.d.ts +17 -0
- package/dist/src/components/ACell.vue.d.ts.map +1 -0
- package/dist/src/components/AGanttCell.vue.d.ts +34 -0
- package/dist/src/components/AGanttCell.vue.d.ts.map +1 -0
- package/dist/src/components/AGanttConnection.vue.d.ts +13 -0
- package/dist/src/components/AGanttConnection.vue.d.ts.map +1 -0
- package/dist/src/components/ARow.vue.d.ts +2693 -0
- package/dist/src/components/ARow.vue.d.ts.map +1 -0
- package/dist/src/components/ARowActions.vue.d.ts +16 -0
- package/dist/src/components/ARowActions.vue.d.ts.map +1 -0
- package/dist/src/components/ATable.vue.d.ts +13358 -0
- package/dist/src/components/ATable.vue.d.ts.map +1 -0
- package/dist/src/components/ATableColumnFilter.vue.d.ts +11 -0
- package/dist/src/components/ATableColumnFilter.vue.d.ts.map +1 -0
- package/dist/src/components/ATableHeader.vue.d.ts +20 -0
- package/dist/src/components/ATableHeader.vue.d.ts.map +1 -0
- package/dist/src/components/ATableLoading.vue.d.ts +14 -0
- package/dist/src/components/ATableLoading.vue.d.ts.map +1 -0
- package/dist/src/components/ATableLoadingBar.vue.d.ts +14 -0
- package/dist/src/components/ATableLoadingBar.vue.d.ts.map +1 -0
- package/dist/src/components/ATableModal.vue.d.ts +18 -0
- package/dist/src/components/ATableModal.vue.d.ts.map +1 -0
- package/dist/src/components/ATablePaginationFooter.vue.d.ts +17 -0
- package/dist/src/components/ATablePaginationFooter.vue.d.ts.map +1 -0
- package/dist/src/icons/index.d.ts +14 -7
- package/dist/src/icons/index.d.ts.map +1 -1
- package/dist/{tsdoc-metadata.json → src/tsdoc-metadata.json} +1 -1
- package/dist/src/types/index.d.ts.map +1 -1
- package/package.json +35 -29
- package/dist/atable.d.ts +0 -3560
- package/dist/atable.tsbuildinfo +0 -1
- package/dist/icons/stonecrop-ui-icon-add.svg +0 -5
- package/dist/icons/stonecrop-ui-icon-delete.svg +0 -5
- package/dist/icons/stonecrop-ui-icon-duplicate.svg +0 -5
- package/dist/icons/stonecrop-ui-icon-insert-above.svg +0 -15
- package/dist/icons/stonecrop-ui-icon-insert-below.svg +0 -15
- package/dist/icons/stonecrop-ui-icon-move.svg +0 -4
- package/dist/icons/stonecrop-ui-icon-open.svg +0 -5
- package/dist/src/composables/table-pagination.js +0 -108
- package/dist/src/icons/index.js +0 -32
- package/dist/src/index.js +0 -33
- package/dist/src/linkSearchableText.js +0 -44
- package/dist/src/resolveFilterType.js +0 -27
- package/dist/src/schemaToColumns.js +0 -59
- package/dist/src/stores/table.js +0 -833
- package/dist/src/types/index.js +0 -0
- package/dist/src/utils.js +0 -39
- package/src/components/ACell.vue +0 -410
- package/src/components/AGanttCell.vue +0 -638
- package/src/components/AGanttConnection.vue +0 -164
- package/src/components/ARow.vue +0 -251
- package/src/components/ARowActions.vue +0 -407
- package/src/components/ATable.vue +0 -538
- package/src/components/ATableColumnFilter.vue +0 -216
- package/src/components/ATableHeader.vue +0 -141
- package/src/components/ATableLoading.vue +0 -86
- package/src/components/ATableLoadingBar.vue +0 -81
- package/src/components/ATableModal.vue +0 -52
- package/src/components/ATablePaginationFooter.vue +0 -100
- package/src/composables/table-pagination.ts +0 -172
- package/src/icons/index.ts +0 -38
- package/src/icons/stonecrop-ui-icon-add.svg +0 -5
- package/src/icons/stonecrop-ui-icon-delete.svg +0 -5
- package/src/icons/stonecrop-ui-icon-duplicate.svg +0 -5
- package/src/icons/stonecrop-ui-icon-insert-above.svg +0 -15
- package/src/icons/stonecrop-ui-icon-insert-below.svg +0 -15
- package/src/icons/stonecrop-ui-icon-move.svg +0 -4
- package/src/icons/stonecrop-ui-icon-open.svg +0 -5
- package/src/index.ts +0 -62
- package/src/linkSearchableText.ts +0 -42
- package/src/resolveFilterType.ts +0 -32
- package/src/schemaToColumns.ts +0 -67
- package/src/shims-vue.d.ts +0 -10
- package/src/stores/table.ts +0 -978
- package/src/types/index.ts +0 -794
- package/src/utils.ts +0 -40
|
@@ -1,538 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="atable-container" style="position: relative">
|
|
3
|
-
<!-- Main table view -->
|
|
4
|
-
<table
|
|
5
|
-
ref="table"
|
|
6
|
-
v-on-click-outside="store.closeModal"
|
|
7
|
-
class="atable"
|
|
8
|
-
:style="{
|
|
9
|
-
width: store.config.fullWidth ? '100%' : 'auto',
|
|
10
|
-
}">
|
|
11
|
-
<slot name="header" :data="store">
|
|
12
|
-
<ATableHeader :columns="store.columns" :store="store" />
|
|
13
|
-
</slot>
|
|
14
|
-
<tbody>
|
|
15
|
-
<slot name="body" :data="store">
|
|
16
|
-
<ARow
|
|
17
|
-
v-for="(row, filteredIndex) in visibleRows"
|
|
18
|
-
:key="`${row.originalIndex}-${filteredIndex}`"
|
|
19
|
-
:row="row"
|
|
20
|
-
:row-index="row.originalIndex"
|
|
21
|
-
:store="store"
|
|
22
|
-
@row:action="handleRowAction"
|
|
23
|
-
@row:click="handleRowClick">
|
|
24
|
-
<template v-for="(column, colIndex) in getProcessedColumnsForRow(row)" :key="column.name">
|
|
25
|
-
<component
|
|
26
|
-
:is="column.ganttComponent || 'AGanttCell'"
|
|
27
|
-
v-if="column.isGantt"
|
|
28
|
-
:store="store"
|
|
29
|
-
:columns-count="store.columns.length - pinnedColumnCount"
|
|
30
|
-
:color="row.gantt?.color"
|
|
31
|
-
:start="row.gantt?.startIndex"
|
|
32
|
-
:end="row.gantt?.endIndex"
|
|
33
|
-
:colspan="column.colspan"
|
|
34
|
-
:pinned="column.pinned"
|
|
35
|
-
:row-index="row.originalIndex"
|
|
36
|
-
:col-index="column.originalIndex ?? colIndex"
|
|
37
|
-
:style="{
|
|
38
|
-
textAlign: column?.align || 'center',
|
|
39
|
-
minWidth: column?.width || '40ch',
|
|
40
|
-
width: store.config.fullWidth ? 'auto' : null,
|
|
41
|
-
}"
|
|
42
|
-
@connection:create="handleConnectionCreate" />
|
|
43
|
-
<component
|
|
44
|
-
:is="column.cellComponent || 'ACell'"
|
|
45
|
-
v-else
|
|
46
|
-
:store="store"
|
|
47
|
-
:pinned="column.pinned"
|
|
48
|
-
:row-index="row.originalIndex"
|
|
49
|
-
:col-index="colIndex"
|
|
50
|
-
:style="{
|
|
51
|
-
textAlign: column?.align || 'center',
|
|
52
|
-
width: store.config.fullWidth ? 'auto' : null,
|
|
53
|
-
}"
|
|
54
|
-
spellcheck="false" />
|
|
55
|
-
</template>
|
|
56
|
-
</ARow>
|
|
57
|
-
</slot>
|
|
58
|
-
</tbody>
|
|
59
|
-
|
|
60
|
-
<slot name="footer" :data="store" :page="pagination">
|
|
61
|
-
<ATablePaginationFooter
|
|
62
|
-
:column-count="footerColumnCount"
|
|
63
|
-
:show-footer="showFooter"
|
|
64
|
-
:has-more="hasMore"
|
|
65
|
-
:has-prev="hasPrev"
|
|
66
|
-
:has-next="hasNext"
|
|
67
|
-
:has-local-next="hasLocalNext"
|
|
68
|
-
:has-ever-had-more="hasEverHadMore"
|
|
69
|
-
:loaded-count="loadedCount"
|
|
70
|
-
:loading="paginationLoading"
|
|
71
|
-
:next="paginationNext"
|
|
72
|
-
:prev="paginationPrev" />
|
|
73
|
-
</slot>
|
|
74
|
-
|
|
75
|
-
<!-- Modal overlay -->
|
|
76
|
-
<slot name="modal" :data="store">
|
|
77
|
-
<ATableModal v-show="store.modal.visible" :store="store">
|
|
78
|
-
<template #default>
|
|
79
|
-
<component
|
|
80
|
-
:is="store.modal.component"
|
|
81
|
-
:key="`${store.modal.rowIndex}:${store.modal.colIndex}`"
|
|
82
|
-
:col-index="store.modal.colIndex"
|
|
83
|
-
:row-index="store.modal.rowIndex"
|
|
84
|
-
:store="store"
|
|
85
|
-
v-bind="store.modal.componentProps" />
|
|
86
|
-
</template>
|
|
87
|
-
</ATableModal>
|
|
88
|
-
</slot>
|
|
89
|
-
</table>
|
|
90
|
-
|
|
91
|
-
<!-- Connection overlay for gantt connections -->
|
|
92
|
-
<AGanttConnection
|
|
93
|
-
v-if="store.isGanttView && store.isDependencyGraphEnabled"
|
|
94
|
-
:store="store"
|
|
95
|
-
@connection:delete="handleConnectionDelete" />
|
|
96
|
-
</div>
|
|
97
|
-
</template>
|
|
98
|
-
|
|
99
|
-
<script setup lang="ts">
|
|
100
|
-
import { vOnClickOutside } from '@vueuse/components'
|
|
101
|
-
import { useMutationObserver } from '@vueuse/core'
|
|
102
|
-
import { computed, inject, nextTick, onMounted, useTemplateRef, watch } from 'vue'
|
|
103
|
-
|
|
104
|
-
import AGanttConnection from './AGanttConnection.vue'
|
|
105
|
-
import ARow from './ARow.vue'
|
|
106
|
-
import ATableHeader from './ATableHeader.vue'
|
|
107
|
-
import ATableModal from './ATableModal.vue'
|
|
108
|
-
import ATablePaginationFooter from './ATablePaginationFooter.vue'
|
|
109
|
-
import { useTablePagination } from '../composables/table-pagination'
|
|
110
|
-
import { createTableStore } from '../stores/table'
|
|
111
|
-
import type { ColumnSchema, GetRecordsOptions, GetRecordsResult } from '@stonecrop/schema'
|
|
112
|
-
|
|
113
|
-
import { schemaToColumns } from '../schemaToColumns'
|
|
114
|
-
import type {
|
|
115
|
-
ConnectionEvent,
|
|
116
|
-
ConnectionPath,
|
|
117
|
-
GanttDragEvent,
|
|
118
|
-
RowActionType,
|
|
119
|
-
RowAddEvent,
|
|
120
|
-
RowClickEvent,
|
|
121
|
-
RowDeleteEvent,
|
|
122
|
-
RowDuplicateEvent,
|
|
123
|
-
RowInsertEvent,
|
|
124
|
-
RowMoveEvent,
|
|
125
|
-
TableColumn,
|
|
126
|
-
TableConfig,
|
|
127
|
-
TableRow,
|
|
128
|
-
} from '../types'
|
|
129
|
-
|
|
130
|
-
const rows = defineModel<TableRow[]>('rows', { required: true })
|
|
131
|
-
// TODO: convert columns from defineModel to a regular prop
|
|
132
|
-
const columns = defineModel<TableColumn[]>('columns')
|
|
133
|
-
|
|
134
|
-
type LinkResolverFn = (doctype: string, id: string) => Promise<string | undefined>
|
|
135
|
-
|
|
136
|
-
const {
|
|
137
|
-
id = '',
|
|
138
|
-
config = new Object(),
|
|
139
|
-
schema = [],
|
|
140
|
-
linkResolver = undefined,
|
|
141
|
-
getRecords = undefined,
|
|
142
|
-
sourceKey = undefined,
|
|
143
|
-
} = defineProps<{
|
|
144
|
-
id?: string
|
|
145
|
-
config?: TableConfig
|
|
146
|
-
schema?: ColumnSchema[]
|
|
147
|
-
linkResolver?: LinkResolverFn
|
|
148
|
-
getRecords?: (options?: GetRecordsOptions) => Promise<GetRecordsResult>
|
|
149
|
-
sourceKey?: string
|
|
150
|
-
}>()
|
|
151
|
-
|
|
152
|
-
const emit = defineEmits<{
|
|
153
|
-
cellUpdate: [{ colIndex: number; rowIndex: number; newValue: any; oldValue: any }]
|
|
154
|
-
'gantt:drag': [event: GanttDragEvent]
|
|
155
|
-
'connection:event': [event: ConnectionEvent]
|
|
156
|
-
'columns:update': [columns: TableColumn[]]
|
|
157
|
-
'row:add': [event: RowAddEvent]
|
|
158
|
-
'row:click': [event: RowClickEvent]
|
|
159
|
-
'row:delete': [event: RowDeleteEvent]
|
|
160
|
-
'row:duplicate': [event: RowDuplicateEvent]
|
|
161
|
-
'row:insert-above': [event: RowInsertEvent]
|
|
162
|
-
'row:insert-below': [event: RowInsertEvent]
|
|
163
|
-
'row:move': [event: RowMoveEvent]
|
|
164
|
-
'row:open': [event: RowClickEvent]
|
|
165
|
-
}>()
|
|
166
|
-
|
|
167
|
-
const tableRef = useTemplateRef<HTMLTableElement>('table')
|
|
168
|
-
const resolvedColumns = columns.value?.length ? columns.value : schemaToColumns(schema ?? [])
|
|
169
|
-
const injectedLinkResolver = inject<LinkResolverFn | null>('aformLinkResolver', null)
|
|
170
|
-
const store = createTableStore({
|
|
171
|
-
columns: resolvedColumns,
|
|
172
|
-
rows: rows.value,
|
|
173
|
-
id,
|
|
174
|
-
config,
|
|
175
|
-
linkResolver: linkResolver ?? injectedLinkResolver,
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
const pagination = useTablePagination({
|
|
179
|
-
rows: () => store.filteredRows,
|
|
180
|
-
pageSize: () => store.config.pageSize,
|
|
181
|
-
getRecords,
|
|
182
|
-
sourceKey: () => sourceKey,
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
const {
|
|
186
|
-
visibleRows,
|
|
187
|
-
showFooter,
|
|
188
|
-
hasMore,
|
|
189
|
-
hasPrev,
|
|
190
|
-
hasNext,
|
|
191
|
-
hasLocalNext,
|
|
192
|
-
hasEverHadMore,
|
|
193
|
-
loadedCount,
|
|
194
|
-
loading: paginationLoading,
|
|
195
|
-
next: paginationNext,
|
|
196
|
-
prev: paginationPrev,
|
|
197
|
-
} = pagination
|
|
198
|
-
|
|
199
|
-
const footerColumnCount = computed(() => store.columns.length + (store.zeroColumn ? 1 : 0))
|
|
200
|
-
|
|
201
|
-
store.$onAction(({ name, store: storeInstance, args, after }) => {
|
|
202
|
-
if (name === 'setCellData' || name === 'setCellText') {
|
|
203
|
-
const [colIndex, rowIndex, newValue] = args
|
|
204
|
-
const oldValue = storeInstance.getCellData(colIndex, rowIndex)
|
|
205
|
-
after(() => {
|
|
206
|
-
// Update rows model to trigger update:rows event
|
|
207
|
-
rows.value = [...store.rows]
|
|
208
|
-
emit('cellUpdate', { colIndex, rowIndex, newValue, oldValue })
|
|
209
|
-
})
|
|
210
|
-
} else if (name === 'updateGanttBar') {
|
|
211
|
-
const [event] = args
|
|
212
|
-
let shouldEmit = false
|
|
213
|
-
if (event.type === 'resize') {
|
|
214
|
-
shouldEmit = event.oldColspan !== event.newColspan
|
|
215
|
-
} else if (event.type === 'bar') {
|
|
216
|
-
shouldEmit = event.oldStart !== event.newStart || event.oldEnd !== event.newEnd
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (shouldEmit) {
|
|
220
|
-
after(() => {
|
|
221
|
-
emit('gantt:drag', event)
|
|
222
|
-
})
|
|
223
|
-
}
|
|
224
|
-
} else if (name === 'resizeColumn') {
|
|
225
|
-
after(() => {
|
|
226
|
-
// Update columns model
|
|
227
|
-
columns.value = [...store.columns]
|
|
228
|
-
emit('columns:update', [...store.columns])
|
|
229
|
-
})
|
|
230
|
-
}
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
// Watch for external changes to rows and sync to store
|
|
234
|
-
watch(
|
|
235
|
-
() => rows.value,
|
|
236
|
-
newRows => {
|
|
237
|
-
// Only update if the rows have actually changed (avoid infinite loops)
|
|
238
|
-
if (JSON.stringify(newRows) !== JSON.stringify(store.rows)) {
|
|
239
|
-
store.rows = [...newRows]
|
|
240
|
-
}
|
|
241
|
-
},
|
|
242
|
-
{ deep: true }
|
|
243
|
-
)
|
|
244
|
-
|
|
245
|
-
// Watch for changes to columns and sync to store
|
|
246
|
-
watch(
|
|
247
|
-
columns,
|
|
248
|
-
newColumns => {
|
|
249
|
-
// The model is optional, so it can be absent — there is nothing to sync from, and the store
|
|
250
|
-
// keeps the columns it resolved from the schema.
|
|
251
|
-
if (!newColumns) return
|
|
252
|
-
// Only update if the columns have actually changed (avoid infinite loops)
|
|
253
|
-
if (JSON.stringify(newColumns) !== JSON.stringify(store.columns)) {
|
|
254
|
-
store.columns = [...newColumns]
|
|
255
|
-
emit('columns:update', [...newColumns])
|
|
256
|
-
}
|
|
257
|
-
},
|
|
258
|
-
{ deep: true }
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
onMounted(() => {
|
|
262
|
-
if (columns.value?.some(column => column.pinned)) {
|
|
263
|
-
assignStickyCellWidths()
|
|
264
|
-
|
|
265
|
-
// in tree views, also add a mutation observer to capture and adjust expanded rows
|
|
266
|
-
if (store.isTreeView) {
|
|
267
|
-
useMutationObserver(tableRef, assignStickyCellWidths, { childList: true, subtree: true })
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
const pinnedColumnCount = computed(() => {
|
|
273
|
-
return store.columns.filter(column => column.pinned).length
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
const assignStickyCellWidths = () => {
|
|
277
|
-
const table = tableRef.value
|
|
278
|
-
|
|
279
|
-
// set header cell width to match sticky cells' width
|
|
280
|
-
const headerRow = table?.rows[0]
|
|
281
|
-
const firstDataRow = table?.rows[1]
|
|
282
|
-
const headerCells = headerRow ? Array.from(headerRow.cells) : []
|
|
283
|
-
for (const [index, headerCell] of headerCells.entries()) {
|
|
284
|
-
const rowCell = firstDataRow?.cells[index]
|
|
285
|
-
if (rowCell) {
|
|
286
|
-
headerCell.style.width = `${rowCell.offsetWidth}px`
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// pin cells in row that are sticky
|
|
291
|
-
for (const row of table?.rows || []) {
|
|
292
|
-
let totalWidth = 0
|
|
293
|
-
const pinnedCells: HTMLTableCellElement[] = []
|
|
294
|
-
|
|
295
|
-
for (const column of row.cells) {
|
|
296
|
-
if (column.classList.contains('sticky-column') || column.classList.contains('sticky-index')) {
|
|
297
|
-
column.style.left = `${totalWidth}px`
|
|
298
|
-
totalWidth += column.offsetWidth
|
|
299
|
-
pinnedCells.push(column)
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (pinnedCells.length > 0) {
|
|
304
|
-
const lastColumn = pinnedCells[pinnedCells.length - 1]
|
|
305
|
-
lastColumn.classList.add('sticky-column-edge')
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
window.addEventListener('keydown', (event: KeyboardEvent) => {
|
|
311
|
-
if (event.key === 'Escape') {
|
|
312
|
-
if (store.modal.visible) {
|
|
313
|
-
store.modal.visible = false
|
|
314
|
-
|
|
315
|
-
// focus on the parent cell again
|
|
316
|
-
const $parent = store.modal.parent
|
|
317
|
-
if ($parent) {
|
|
318
|
-
// wait for the modal to close before focusing
|
|
319
|
-
void nextTick().then(() => {
|
|
320
|
-
return $parent.focus()
|
|
321
|
-
})
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
})
|
|
326
|
-
|
|
327
|
-
const getProcessedColumnsForRow = (row: TableRow) => {
|
|
328
|
-
if (!row.gantt || pinnedColumnCount.value === 0) {
|
|
329
|
-
return store.columns
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// For Gantt views, first add the pinned columns
|
|
333
|
-
const result: TableColumn[] = []
|
|
334
|
-
for (let i = 0; i < pinnedColumnCount.value; i++) {
|
|
335
|
-
const column = { ...store.columns[i] }
|
|
336
|
-
column.originalIndex = i // Preserve original index
|
|
337
|
-
result.push(column)
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Finally, add the Gantt bar column with either a provided colspan or default to full-width colspan
|
|
341
|
-
result.push({
|
|
342
|
-
...store.columns[pinnedColumnCount.value],
|
|
343
|
-
isGantt: true,
|
|
344
|
-
colspan: row.gantt?.colspan || store.columns.length - pinnedColumnCount.value,
|
|
345
|
-
originalIndex: pinnedColumnCount.value,
|
|
346
|
-
width: 'auto', // TODO: refactor to API that can detect when data exists in a cell. Might have be custom and not generalizable
|
|
347
|
-
})
|
|
348
|
-
|
|
349
|
-
return result
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const handleConnectionCreate = (connection: ConnectionPath) => {
|
|
353
|
-
emit('connection:event', { type: 'create', connection })
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
const handleConnectionDelete = (connection: ConnectionPath) => {
|
|
357
|
-
emit('connection:event', { type: 'delete', connection })
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Handle row click events from ARow components.
|
|
362
|
-
*/
|
|
363
|
-
const handleRowClick = (rowIndex: number, event: MouseEvent) => {
|
|
364
|
-
const row = store.rows[rowIndex]
|
|
365
|
-
emit('row:click', { row, rowIndex, event })
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Handle row action events from ARow components.
|
|
370
|
-
* Performs the default action and emits the appropriate event.
|
|
371
|
-
*/
|
|
372
|
-
const handleRowAction = (actionType: RowActionType, rowIndex: number, event?: MouseEvent) => {
|
|
373
|
-
switch (actionType) {
|
|
374
|
-
case 'add': {
|
|
375
|
-
// Add a new row after the current row
|
|
376
|
-
const newIndex = store.addRow({}, rowIndex + 1)
|
|
377
|
-
const newRow = store.rows[newIndex]
|
|
378
|
-
rows.value = [...store.rows]
|
|
379
|
-
emit('row:add', { rowIndex: newIndex, row: newRow })
|
|
380
|
-
break
|
|
381
|
-
}
|
|
382
|
-
case 'delete': {
|
|
383
|
-
const deletedRow = store.deleteRow(rowIndex)
|
|
384
|
-
if (deletedRow) {
|
|
385
|
-
rows.value = [...store.rows]
|
|
386
|
-
emit('row:delete', { rowIndex, row: deletedRow })
|
|
387
|
-
}
|
|
388
|
-
break
|
|
389
|
-
}
|
|
390
|
-
case 'duplicate': {
|
|
391
|
-
const newIndex = store.duplicateRow(rowIndex)
|
|
392
|
-
if (newIndex >= 0) {
|
|
393
|
-
const newRow = store.rows[newIndex]
|
|
394
|
-
rows.value = [...store.rows]
|
|
395
|
-
emit('row:duplicate', { sourceIndex: rowIndex, newIndex, row: newRow })
|
|
396
|
-
}
|
|
397
|
-
break
|
|
398
|
-
}
|
|
399
|
-
case 'insertAbove': {
|
|
400
|
-
const newIndex = store.insertRowAbove(rowIndex)
|
|
401
|
-
const newRow = store.rows[newIndex]
|
|
402
|
-
rows.value = [...store.rows]
|
|
403
|
-
emit('row:insert-above', { targetIndex: rowIndex, newIndex, row: newRow })
|
|
404
|
-
break
|
|
405
|
-
}
|
|
406
|
-
case 'insertBelow': {
|
|
407
|
-
const newIndex = store.insertRowBelow(rowIndex)
|
|
408
|
-
const newRow = store.rows[newIndex]
|
|
409
|
-
rows.value = [...store.rows]
|
|
410
|
-
emit('row:insert-below', { targetIndex: rowIndex, newIndex, row: newRow })
|
|
411
|
-
break
|
|
412
|
-
}
|
|
413
|
-
case 'move': {
|
|
414
|
-
// Move action requires a target index - for now, emit an event
|
|
415
|
-
// The consumer should handle showing a UI for selecting the target
|
|
416
|
-
emit('row:move', { fromIndex: rowIndex, toIndex: -1 })
|
|
417
|
-
break
|
|
418
|
-
}
|
|
419
|
-
case 'moveUp': {
|
|
420
|
-
if (rowIndex > 0 && store.moveRow(rowIndex, rowIndex - 1)) {
|
|
421
|
-
rows.value = [...store.rows]
|
|
422
|
-
emit('row:move', { fromIndex: rowIndex, toIndex: rowIndex - 1 })
|
|
423
|
-
}
|
|
424
|
-
break
|
|
425
|
-
}
|
|
426
|
-
case 'moveDown': {
|
|
427
|
-
if (rowIndex < store.rows.length - 1 && store.moveRow(rowIndex, rowIndex + 1)) {
|
|
428
|
-
rows.value = [...store.rows]
|
|
429
|
-
emit('row:move', { fromIndex: rowIndex, toIndex: rowIndex + 1 })
|
|
430
|
-
}
|
|
431
|
-
break
|
|
432
|
-
}
|
|
433
|
-
case 'open': {
|
|
434
|
-
const row = store.rows[rowIndex]
|
|
435
|
-
emit('row:open', { row, rowIndex, event })
|
|
436
|
-
break
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
defineExpose({
|
|
442
|
-
store,
|
|
443
|
-
pagination,
|
|
444
|
-
createConnection: store.createConnection,
|
|
445
|
-
deleteConnection: store.deleteConnection,
|
|
446
|
-
getConnectionsForBar: store.getConnectionsForBar,
|
|
447
|
-
getHandlesForBar: store.getHandlesForBar,
|
|
448
|
-
// Row action methods
|
|
449
|
-
addRow: store.addRow,
|
|
450
|
-
deleteRow: store.deleteRow,
|
|
451
|
-
duplicateRow: store.duplicateRow,
|
|
452
|
-
insertRowAbove: store.insertRowAbove,
|
|
453
|
-
insertRowBelow: store.insertRowBelow,
|
|
454
|
-
moveRow: store.moveRow,
|
|
455
|
-
})
|
|
456
|
-
</script>
|
|
457
|
-
|
|
458
|
-
<style>
|
|
459
|
-
.atable-container {
|
|
460
|
-
position: relative;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
.sticky-index {
|
|
464
|
-
position: sticky;
|
|
465
|
-
left: 0px;
|
|
466
|
-
z-index: 100;
|
|
467
|
-
order: 0;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
.sticky-column,
|
|
471
|
-
th.sticky-column,
|
|
472
|
-
td.sticky-column,
|
|
473
|
-
th.sticky-index,
|
|
474
|
-
td.sticky-index {
|
|
475
|
-
position: sticky;
|
|
476
|
-
z-index: 100;
|
|
477
|
-
order: 0;
|
|
478
|
-
background: white;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
.sticky-column-edge,
|
|
482
|
-
.atable th.sticky-column-edge {
|
|
483
|
-
border-right: 1px solid var(--sc-row-border-color);
|
|
484
|
-
}
|
|
485
|
-
</style>
|
|
486
|
-
|
|
487
|
-
<style scoped>
|
|
488
|
-
.atable {
|
|
489
|
-
position: relative;
|
|
490
|
-
font-family: var(--sc-atable-font-family);
|
|
491
|
-
-webkit-font-smoothing: antialiased;
|
|
492
|
-
-moz-osx-font-smoothing: grayscale;
|
|
493
|
-
font-size: var(--sc-table-font-size);
|
|
494
|
-
border-collapse: collapse;
|
|
495
|
-
box-sizing: border-box;
|
|
496
|
-
table-layout: auto;
|
|
497
|
-
width: auto;
|
|
498
|
-
overflow: clip;
|
|
499
|
-
height: 1px;
|
|
500
|
-
/* border-left:4px solid var(--sc-form-border); */
|
|
501
|
-
}
|
|
502
|
-
.atable th {
|
|
503
|
-
border-width: 0px;
|
|
504
|
-
border-style: solid;
|
|
505
|
-
border-radius: 0px;
|
|
506
|
-
padding-left: 0.5ch;
|
|
507
|
-
padding-right: 0.5ch;
|
|
508
|
-
padding-top: var(--sc-atable-row-padding);
|
|
509
|
-
padding-bottom: var(--sc-atable-row-padding);
|
|
510
|
-
color: var(--sc-gray-60);
|
|
511
|
-
height: var(--sc-atable-row-height);
|
|
512
|
-
font-weight: 300;
|
|
513
|
-
letter-spacing: 0.05rem;
|
|
514
|
-
order: 1;
|
|
515
|
-
box-sizing: border-box;
|
|
516
|
-
}
|
|
517
|
-
.atable th:focus {
|
|
518
|
-
outline: none;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/* Make sure the vertical indicator doesn't extend into the header */
|
|
522
|
-
.atable:tbody {
|
|
523
|
-
overflow: hidden; /* This ensures the indicator is clipped */
|
|
524
|
-
position: relative; /* Create a stacking context */
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
/* Ensure the indicator stays within the tbody */
|
|
528
|
-
.atable:tbody::before {
|
|
529
|
-
content: '';
|
|
530
|
-
position: absolute;
|
|
531
|
-
top: 0;
|
|
532
|
-
left: 0;
|
|
533
|
-
right: 0;
|
|
534
|
-
height: 1px;
|
|
535
|
-
background-color: transparent;
|
|
536
|
-
z-index: 100;
|
|
537
|
-
}
|
|
538
|
-
</style>
|