mirror of
https://github.com/speatzle/nfsense.git
synced 2025-05-10 18:38:22 +00:00
Move NiceTable away from defineModels
- Also improved display component support
This commit is contained in:
parent
8508309b2c
commit
f30b93d5dc
1 changed files with 55 additions and 25 deletions
|
@ -1,38 +1,68 @@
|
|||
<script setup lang="ts">
|
||||
import { useKeyModifier } from '@vueuse/core';
|
||||
import type { Component } from 'vue';
|
||||
import { equals } from '~/util';
|
||||
|
||||
const shiftState = $(useKeyModifier('Shift'));
|
||||
const ctrlState = $(useKeyModifier('Control'));
|
||||
|
||||
const props = defineModels<{
|
||||
columns?: {
|
||||
heading: string,
|
||||
path: string,
|
||||
component?: string,
|
||||
}[], // -
|
||||
const props = withDefaults(defineProps<{
|
||||
// Two-Way Bindings
|
||||
data?: Record<string, any>[],
|
||||
sort?: boolean,
|
||||
sortSelf?: boolean, // -
|
||||
sortBy?: string,
|
||||
sortDesc?: boolean,
|
||||
selection?: number[],
|
||||
draggable?: boolean, // -
|
||||
}>();
|
||||
let { columns, data, sort, sortSelf, sortBy, sortDesc, selection, draggable } = $(props);
|
||||
|
||||
// One-Way Bindings
|
||||
columns?: {
|
||||
heading: string,
|
||||
path: string,
|
||||
component: Component,
|
||||
}[],
|
||||
sortSelf?: boolean,
|
||||
draggable?: boolean,
|
||||
}>(), {
|
||||
columns: () => [],
|
||||
data: () => [],
|
||||
sort: false,
|
||||
sortSelf: false,
|
||||
sortBy: '',
|
||||
sortDesc: false,
|
||||
selection: () => [],
|
||||
draggable: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'rowAction', index: number): void,
|
||||
(event: 'selectionChanged'): void
|
||||
(event: 'draggedRow', draggedRow: number, draggedOverRow: number): void,
|
||||
(event: 'update:data', value: Record<string, any>[]): void,
|
||||
(event: 'update:sort', value: boolean): void,
|
||||
(event: 'update:sortBy', value: string): void,
|
||||
(event: 'update:sortDesc', value: boolean): void,
|
||||
(event: 'update:selection', value: number[]): void,
|
||||
}>();
|
||||
|
||||
const componentProp: Record<string, string> = {
|
||||
"EnumDisplay": "data",
|
||||
};
|
||||
// Hook up two-way bindings
|
||||
let data = $ref(props.data);
|
||||
watch(() => props.data, () => { if (!equals(props.data, data)) data = props.data; }, { deep: true });
|
||||
watch($$(data), () => { if (!equals(data, props.data)) emit('update:data', data); }, { deep: true });
|
||||
let sort = $ref(props.sort);
|
||||
watch(() => props.sort, () => { if (!equals(props.sort, sort)) sort = props.sort; });
|
||||
watch($$(sort), () => { if (!equals(sort, props.sort)) emit('update:sort', sort); });
|
||||
let sortBy = $ref(props.sortBy);
|
||||
watch(() => props.sortBy, () => { if (!equals(props.sortBy, sortBy)) sortBy = props.sortBy; });
|
||||
watch($$(sortBy), () => { if (!equals(sortBy, props.sortBy)) emit('update:sortBy', sortBy); });
|
||||
let sortDesc = $ref(props.sortDesc);
|
||||
watch(() => props.sortDesc, () => { if (!equals(props.sortDesc, sortDesc)) sortDesc = props.sortDesc; });
|
||||
watch($$(sortDesc), () => { if (!equals(sortDesc, props.sortDesc)) emit('update:sortDesc', sortDesc); });
|
||||
let selection = $ref(props.selection);
|
||||
watch(() => props.selection, () => { if (!equals(props.selection, selection)) selection = props.selection; }, { deep: true });
|
||||
watch($$(selection), () => { if (!equals(selection, props.selection)) emit('update:selection', selection); }, { deep: true });
|
||||
|
||||
|
||||
const displayData = $computed(() => (sortSelf && sortBy !== '')
|
||||
? data?.sort((a, b) => {
|
||||
const displayData = $computed(() => (props.sortSelf && sortBy !== '')
|
||||
? data?.sort((a, b) => { // TODO Determine whether sorting a copy is necessary
|
||||
selection = [];
|
||||
let result;
|
||||
if (a[sortBy ?? ''] > b[sortBy ?? '']) result = 1;
|
||||
|
@ -59,7 +89,7 @@ function toggleRowSelection(index: number) {
|
|||
} else if (ctrlState) // Toggle the presence of the row in the selection
|
||||
selection = selection.includes(index)
|
||||
? selection.filter(i => i !== index)
|
||||
: selection = [...selection, index];
|
||||
: [...selection, index];
|
||||
else selection = selection.includes(index) ? [] : [index]; // Toggle between selection of none and this row
|
||||
emit('selectionChanged');
|
||||
}
|
||||
|
@ -92,7 +122,7 @@ function dragDropRow() {
|
|||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="{heading, path} of columns" :key="path" @click="() => toggleSorting(path)">
|
||||
<th v-for="{heading, path} of props.columns" :key="path" @click="() => toggleSorting(path)">
|
||||
<div class="flex-row">
|
||||
{{ heading }}
|
||||
<template v-if="sort">
|
||||
|
@ -106,18 +136,18 @@ function dragDropRow() {
|
|||
<tbody>
|
||||
<tr v-for="(row, index) in displayData" :key="index"
|
||||
:draggable="draggable"
|
||||
@click="() => toggleRowSelection(index)"
|
||||
@dblclick="() => emit('rowAction', index)"
|
||||
@dragstart="() => draggedRow = index"
|
||||
@dragenter="() => draggedOverRow = index"
|
||||
@dragend="() => dragDropRow()"
|
||||
:class="{
|
||||
'selected': (selection ?? []).includes(index),
|
||||
'dragged-over-before': index === draggedOverRow && draggedOverRow < draggedRow,
|
||||
'dragged-over-after': index === draggedOverRow && draggedOverRow > draggedRow,
|
||||
}">
|
||||
}"
|
||||
@click="() => toggleRowSelection(index)"
|
||||
@dblclick="() => emit('rowAction', index)"
|
||||
@dragstart="() => draggedRow = index"
|
||||
@dragenter="() => draggedOverRow = index"
|
||||
@dragend="() => dragDropRow()">
|
||||
<td v-for="{path, component} of columns" :key="path">
|
||||
<component v-if="component" :is="component" v-bind="{[componentProp[component]]: atPath(row, path)}"/>
|
||||
<component :is="component" v-if="component" :data="atPath(row, path)"/>
|
||||
<template v-else>{{ atPath(row, path) }}</template>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
Loading…
Add table
Reference in a new issue