Improve NiceTable component support

- Also vastly improved row selection logic
This commit is contained in:
adroslice 2023-11-13 20:06:31 +01:00
parent 3b0d4fcdaf
commit fdcc48f8be

View file

@ -8,15 +8,15 @@ const props = defineModels<{
columns?: { columns?: {
heading: string, heading: string,
path: string, path: string,
component?: Component, component?: string,
}[], }[], // -
data?: Record<string, any>[], data?: Record<string, any>[],
sort?: boolean, sort?: boolean,
sortSelf?: boolean, sortSelf?: boolean, // -
sortBy?: string, sortBy?: string,
sortDesc?: boolean, sortDesc?: boolean,
selection?: number[], selection?: number[],
draggable?: boolean, draggable?: boolean, // -
}>(); }>();
let { columns, data, sort, sortSelf, sortBy, sortDesc, selection, draggable } = $(props); let { columns, data, sort, sortSelf, sortBy, sortDesc, selection, draggable } = $(props);
@ -26,7 +26,10 @@ const emit = defineEmits<{
(event: 'draggedRow', draggedRow: number, draggedOverRow: number): void, (event: 'draggedRow', draggedRow: number, draggedOverRow: number): void,
}>(); }>();
if (!selection) selection = []; const componentProp: Record<string, string> = {
"EnumDisplay": "data",
};
const displayData = $computed(() => (sortSelf && sortBy !== '') const displayData = $computed(() => (sortSelf && sortBy !== '')
? data?.sort((a, b) => { ? data?.sort((a, b) => {
@ -44,52 +47,26 @@ const displayData = $computed(() => (sortSelf && sortBy !== '')
function toggleSorting(columnName: string) { function toggleSorting(columnName: string) {
if (!sort) return; if (!sort) return;
if (columnName === sortBy) sortDesc = !sortDesc; if (columnName === sortBy) sortDesc = !sortDesc;
else { else [sortDesc, sortBy] = [false, columnName];
sortDesc = false;
sortBy = columnName;
}
} }
function rowSelection(index: number) { function toggleRowSelection(index: number) {
if (!selection) selection = []; if (!selection || !selection.length) selection = [index];
if (shiftState) { else if (shiftState) { // Selection becomes a range including the highest, lowest and clicked row
if (!selection?.length) { const points = [Math.max(...selection), Math.min(...selection), index];
selection = [index]; const [max, min] = [Math.max(...points), Math.min(...points)];
} else { selection = Array.from({length: max - min + 1}, (_, i) => i + min);
let last = selection[selection.length-1]; } else if (ctrlState) // Toggle the presence of the row in the selection
let start = index; selection = selection.includes(index)
let end = last; ? selection.filter(i => i !== index)
if (last < start) { : selection = [...selection, index];
start = last; else selection = selection.includes(index) ? [] : [index]; // Toggle between selection of none and this row
end = index;
}
for (let i = start; i <= end; i++ ) {
if (!selection.includes(i)) {
selection = [...selection, i];
}
}
}
} else if (ctrlState) {
if (selection.includes(index)) {
// remove if already exists
selection.splice(selection.indexOf(index), 1);
} else {
selection = [...selection, index];
}
} else {
if (selection.includes(index)) {
selection = [];
} else {
selection = [index];
}
}
emit('selectionChanged'); emit('selectionChanged');
} }
function atPath(value: any, path: string): any { function atPath(value: any, path: string): any {
for (const segment of path.split('.')) { for (const segment of path.split('.'))
value = value[segment]; value = (value ?? {} as any)[segment];
}
return value; return value;
} }
@ -104,10 +81,9 @@ function dragDropRow() {
emit('draggedRow', draggedRow, draggedOverRow); emit('draggedRow', draggedRow, draggedOverRow);
} }
// Reset drag data // Reset Drag & Remove Selection
draggedRow = 0; draggedRow = 0;
draggedOverRow = 0; draggedOverRow = 0;
// Kill selection
selection = []; selection = [];
} }
</script> </script>
@ -130,7 +106,7 @@ function dragDropRow() {
<tbody> <tbody>
<tr v-for="(row, index) in displayData" :key="index" <tr v-for="(row, index) in displayData" :key="index"
:draggable="draggable" :draggable="draggable"
@click="() => rowSelection(index)" @click="() => toggleRowSelection(index)"
@dblclick="() => emit('rowAction', index)" @dblclick="() => emit('rowAction', index)"
@dragstart="() => draggedRow = index" @dragstart="() => draggedRow = index"
@dragenter="() => draggedOverRow = index" @dragenter="() => draggedOverRow = index"
@ -141,8 +117,8 @@ function dragDropRow() {
'dragged-over-after': index === draggedOverRow && draggedOverRow > draggedRow, 'dragged-over-after': index === draggedOverRow && draggedOverRow > draggedRow,
}"> }">
<td v-for="{path, component} of columns" :key="path"> <td v-for="{path, component} of columns" :key="path">
{{ component ? "" : atPath(row, path) }} <component v-if="component" :is="component" v-bind="{[componentProp[component]]: atPath(row, path)}"/>
<component v-if="component" :is="component"/> <template v-else>{{ atPath(row, path) }}</template>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -150,14 +126,8 @@ function dragDropRow() {
</template> </template>
<style scoped> <style scoped>
.dragged-over-before { .dragged-over-before { border-top: 0.25rem solid var(--cl-fg); }
border-top: 0.25rem solid var(--cl-fg); .dragged-over-after { border-bottom: 0.25rem solid var(--cl-fg); }
}
.dragged-over-after {
border-bottom: 0.25rem solid var(--cl-fg);
}
tr { tr { cursor: grab; }
cursor: grab;
}
</style> </style>