mirror of
https://github.com/speatzle/nfsense.git
synced 2025-05-11 19:08:20 +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">
|
<script setup lang="ts">
|
||||||
import { useKeyModifier } from '@vueuse/core';
|
import { useKeyModifier } from '@vueuse/core';
|
||||||
|
import type { Component } from 'vue';
|
||||||
|
import { equals } from '~/util';
|
||||||
|
|
||||||
const shiftState = $(useKeyModifier('Shift'));
|
const shiftState = $(useKeyModifier('Shift'));
|
||||||
const ctrlState = $(useKeyModifier('Control'));
|
const ctrlState = $(useKeyModifier('Control'));
|
||||||
|
|
||||||
const props = defineModels<{
|
const props = withDefaults(defineProps<{
|
||||||
columns?: {
|
// Two-Way Bindings
|
||||||
heading: string,
|
|
||||||
path: string,
|
|
||||||
component?: string,
|
|
||||||
}[], // -
|
|
||||||
data?: Record<string, any>[],
|
data?: Record<string, any>[],
|
||||||
sort?: boolean,
|
sort?: boolean,
|
||||||
sortSelf?: boolean, // -
|
|
||||||
sortBy?: string,
|
sortBy?: string,
|
||||||
sortDesc?: boolean,
|
sortDesc?: boolean,
|
||||||
selection?: number[],
|
selection?: number[],
|
||||||
draggable?: boolean, // -
|
|
||||||
}>();
|
// One-Way Bindings
|
||||||
let { columns, data, sort, sortSelf, sortBy, sortDesc, selection, draggable } = $(props);
|
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<{
|
const emit = defineEmits<{
|
||||||
(event: 'rowAction', index: number): void,
|
(event: 'rowAction', index: number): void,
|
||||||
(event: 'selectionChanged'): void
|
(event: 'selectionChanged'): void
|
||||||
(event: 'draggedRow', draggedRow: number, draggedOverRow: number): 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> = {
|
// Hook up two-way bindings
|
||||||
"EnumDisplay": "data",
|
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(() => (props.sortSelf && sortBy !== '')
|
||||||
const displayData = $computed(() => (sortSelf && sortBy !== '')
|
? data?.sort((a, b) => { // TODO Determine whether sorting a copy is necessary
|
||||||
? data?.sort((a, b) => {
|
|
||||||
selection = [];
|
selection = [];
|
||||||
let result;
|
let result;
|
||||||
if (a[sortBy ?? ''] > b[sortBy ?? '']) result = 1;
|
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
|
} else if (ctrlState) // Toggle the presence of the row in the selection
|
||||||
selection = selection.includes(index)
|
selection = selection.includes(index)
|
||||||
? selection.filter(i => i !== 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
|
else selection = selection.includes(index) ? [] : [index]; // Toggle between selection of none and this row
|
||||||
emit('selectionChanged');
|
emit('selectionChanged');
|
||||||
}
|
}
|
||||||
|
@ -92,7 +122,7 @@ function dragDropRow() {
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<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">
|
<div class="flex-row">
|
||||||
{{ heading }}
|
{{ heading }}
|
||||||
<template v-if="sort">
|
<template v-if="sort">
|
||||||
|
@ -106,18 +136,18 @@ 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="() => toggleRowSelection(index)"
|
|
||||||
@dblclick="() => emit('rowAction', index)"
|
|
||||||
@dragstart="() => draggedRow = index"
|
|
||||||
@dragenter="() => draggedOverRow = index"
|
|
||||||
@dragend="() => dragDropRow()"
|
|
||||||
:class="{
|
:class="{
|
||||||
'selected': (selection ?? []).includes(index),
|
'selected': (selection ?? []).includes(index),
|
||||||
'dragged-over-before': index === draggedOverRow && draggedOverRow < draggedRow,
|
'dragged-over-before': index === draggedOverRow && draggedOverRow < draggedRow,
|
||||||
'dragged-over-after': 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">
|
<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>
|
<template v-else>{{ atPath(row, path) }}</template>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
Loading…
Add table
Reference in a new issue