nuance-ui 0.1.28 → 0.1.30
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/module.json +1 -1
- package/dist/runtime/components/breadcrumbs.d.vue.ts +1 -2
- package/dist/runtime/components/breadcrumbs.vue +2 -3
- package/dist/runtime/components/breadcrumbs.vue.d.ts +1 -2
- package/dist/runtime/components/input/ui/input-inline.vue +5 -1
- package/dist/runtime/components/table/lib.d.ts +6 -1
- package/dist/runtime/components/table/lib.js +31 -0
- package/dist/runtime/components/table/table.vue +52 -68
- package/dist/runtime/components/tree/_ui/tree-item.vue +3 -1
- package/dist/runtime/components/tree/_ui/tree-root.d.vue.ts +2 -1
- package/dist/runtime/components/tree/_ui/tree-root.vue +5 -2
- package/dist/runtime/components/tree/_ui/tree-root.vue.d.ts +2 -1
- package/dist/runtime/components/tree/lib/context.d.ts +2 -1
- package/dist/runtime/components/tree/lib/filter-tree-items.d.ts +2 -0
- package/dist/runtime/components/tree/lib/filter-tree-items.js +7 -0
- package/dist/runtime/components/tree/lib/item-handlers.js +0 -2
- package/dist/runtime/components/tree/model.d.ts +1 -0
- package/dist/runtime/components/tree/tree.vue +7 -2
- package/package.json +1 -1
- package/dist/runtime/components/table/_ui/table-row.d.vue.ts +0 -35
- package/dist/runtime/components/table/_ui/table-row.vue +0 -74
- package/dist/runtime/components/table/_ui/table-row.vue.d.ts +0 -35
- package/dist/runtime/components/tree/lib/get-default.d.ts +0 -7
- package/dist/runtime/components/tree/lib/get-default.js +0 -10
package/dist/module.json
CHANGED
|
@@ -4,6 +4,7 @@ import type { BoxProps } from './box.vue.js';
|
|
|
4
4
|
import type { LinkProps } from './link/index.js';
|
|
5
5
|
import type { TextProps } from './text.vue.js';
|
|
6
6
|
export interface BreadcrumbsItem extends Omit<LinkProps, 'mod'> {
|
|
7
|
+
active?: boolean;
|
|
7
8
|
label: string;
|
|
8
9
|
icon?: string;
|
|
9
10
|
class?: string;
|
|
@@ -16,8 +17,6 @@ export interface BreadcrumbsProps extends BoxProps {
|
|
|
16
17
|
separator?: string;
|
|
17
18
|
/** Controls spacing between separator and breadcrumb @default `'xs'` */
|
|
18
19
|
spacing?: NuanceSpacing;
|
|
19
|
-
/** Function to determine if an item is active */
|
|
20
|
-
activeItem?: (item: BreadcrumbsItem) => boolean;
|
|
21
20
|
color?: NuanceColor;
|
|
22
21
|
size?: TextProps['fz'];
|
|
23
22
|
}
|
|
@@ -17,7 +17,6 @@ const {
|
|
|
17
17
|
items: { type: null, required: false },
|
|
18
18
|
separator: { type: String, required: false },
|
|
19
19
|
spacing: { type: [String, Number], required: false },
|
|
20
|
-
activeItem: { type: Function, required: false },
|
|
21
20
|
color: { type: null, required: false },
|
|
22
21
|
size: { type: null, required: false },
|
|
23
22
|
is: { type: null, required: false },
|
|
@@ -44,13 +43,13 @@ const style = computed(() => ({
|
|
|
44
43
|
:name='item.slot ?? "item"'
|
|
45
44
|
:item='item'
|
|
46
45
|
:ix='ix'
|
|
47
|
-
:active='
|
|
46
|
+
:active='item?.active ?? isActive'
|
|
48
47
|
>
|
|
49
48
|
<Link
|
|
50
49
|
v-bind='pickLinkProps(item).link'
|
|
51
50
|
inherit
|
|
52
51
|
:class='$style.item'
|
|
53
|
-
:mod='{ active:
|
|
52
|
+
:mod='{ active: item?.active ?? isActive }'
|
|
54
53
|
>
|
|
55
54
|
<Icon v-if='item?.icon' :name='item.icon' :class='$style.icon' />
|
|
56
55
|
<Text is='span' inherit truncate>
|
|
@@ -4,6 +4,7 @@ import type { BoxProps } from './box.vue.js';
|
|
|
4
4
|
import type { LinkProps } from './link/index.js';
|
|
5
5
|
import type { TextProps } from './text.vue.js';
|
|
6
6
|
export interface BreadcrumbsItem extends Omit<LinkProps, 'mod'> {
|
|
7
|
+
active?: boolean;
|
|
7
8
|
label: string;
|
|
8
9
|
icon?: string;
|
|
9
10
|
class?: string;
|
|
@@ -16,8 +17,6 @@ export interface BreadcrumbsProps extends BoxProps {
|
|
|
16
17
|
separator?: string;
|
|
17
18
|
/** Controls spacing between separator and breadcrumb @default `'xs'` */
|
|
18
19
|
spacing?: NuanceSpacing;
|
|
19
|
-
/** Function to determine if an item is active */
|
|
20
|
-
activeItem?: (item: BreadcrumbsItem) => boolean;
|
|
21
20
|
color?: NuanceColor;
|
|
22
21
|
size?: TextProps['fz'];
|
|
23
22
|
}
|
|
@@ -38,7 +38,7 @@ const mod = computed(() => [
|
|
|
38
38
|
<slot />
|
|
39
39
|
|
|
40
40
|
<div :class='$style.wrapper'>
|
|
41
|
-
<Box is='label' :class='$style.label' :for='id' :mod='{ disabled }'>
|
|
41
|
+
<Box is='label' v-if='label || $slots.label' :class='$style.label' :for='id' :mod='{ disabled }'>
|
|
42
42
|
<slot name='label'>
|
|
43
43
|
{{ label }}
|
|
44
44
|
</slot>
|
|
@@ -104,6 +104,10 @@ const mod = computed(() => [
|
|
|
104
104
|
&[data-disabled] {
|
|
105
105
|
--label-cursor: not-allowed;
|
|
106
106
|
}
|
|
107
|
+
|
|
108
|
+
&:empty {
|
|
109
|
+
display: none;
|
|
110
|
+
}
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
.label {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { Updater } from '@tanstack/vue-table';
|
|
2
2
|
import type { Ref } from 'vue';
|
|
3
|
-
import type { TableColumn, TableData } from './model.js';
|
|
3
|
+
import type { TableColumn, TableData, TableProps, TableRow } from './model.js';
|
|
4
4
|
export declare function processColumns<T extends TableData>(columns: TableColumn<T>[]): TableColumn<T>[];
|
|
5
5
|
export declare function valueUpdater<T extends Updater<any>>(updaterOrValue: T, ref: Ref): void;
|
|
6
6
|
export declare function resolveValue<T, A = undefined>(prop: T | ((arg: A) => T), arg?: A): T | undefined;
|
|
7
|
+
export declare function createRowHandlers<T extends TableData>(props: TableProps<T>): {
|
|
8
|
+
onRowSelect: (e: Event, row: TableRow<T>) => void;
|
|
9
|
+
onRowHover: (e: Event, row: TableRow<T> | null) => void;
|
|
10
|
+
onRowContextmenu: (e: Event, row: TableRow<T>) => void;
|
|
11
|
+
};
|
|
@@ -22,3 +22,34 @@ export function resolveValue(prop, arg) {
|
|
|
22
22
|
return prop(arg);
|
|
23
23
|
return prop;
|
|
24
24
|
}
|
|
25
|
+
export function createRowHandlers(props) {
|
|
26
|
+
function onRowSelect(e, row) {
|
|
27
|
+
if (!props?.onSelect)
|
|
28
|
+
return;
|
|
29
|
+
const target = e.target;
|
|
30
|
+
const isInteractive = target.closest("button") || target.closest("a");
|
|
31
|
+
if (isInteractive)
|
|
32
|
+
return;
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
e.stopPropagation();
|
|
35
|
+
props.onSelect(e, row);
|
|
36
|
+
}
|
|
37
|
+
function onRowHover(e, row) {
|
|
38
|
+
if (!props?.onHover)
|
|
39
|
+
return;
|
|
40
|
+
props.onHover(e, row);
|
|
41
|
+
}
|
|
42
|
+
function onRowContextmenu(e, row) {
|
|
43
|
+
if (!props?.onContextmenu)
|
|
44
|
+
return;
|
|
45
|
+
if (Array.isArray(props.onContextmenu))
|
|
46
|
+
props.onContextmenu.forEach((fn) => fn(e, row));
|
|
47
|
+
else
|
|
48
|
+
props.onContextmenu(e, row);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
onRowSelect,
|
|
52
|
+
onRowHover,
|
|
53
|
+
onRowContextmenu
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -7,15 +7,12 @@ import {
|
|
|
7
7
|
getSortedRowModel,
|
|
8
8
|
useVueTable
|
|
9
9
|
} from "@tanstack/vue-table";
|
|
10
|
-
import { useVirtualizer } from "@tanstack/vue-virtual";
|
|
11
10
|
import { reactivePick, unrefElement } from "@vueuse/core";
|
|
12
11
|
import { useStyleResolver } from "#imports";
|
|
13
|
-
import
|
|
14
|
-
import { computed, ref, toRef, useTemplateRef, watch } from "vue";
|
|
12
|
+
import { computed, ref, useTemplateRef, watch } from "vue";
|
|
15
13
|
import { getThemeColor } from "../../utils";
|
|
16
14
|
import Box from "../box.vue";
|
|
17
|
-
import
|
|
18
|
-
import { processColumns, resolveValue, valueUpdater } from "./lib";
|
|
15
|
+
import { createRowHandlers, processColumns, resolveValue, valueUpdater } from "./lib";
|
|
19
16
|
defineOptions({ inheritAttrs: false });
|
|
20
17
|
const props = defineProps({
|
|
21
18
|
data: { type: Array, required: false },
|
|
@@ -204,33 +201,11 @@ const rows = computed(() => table.getRowModel().rows);
|
|
|
204
201
|
watch(() => props.data, () => {
|
|
205
202
|
data.value = props.data ? [...props.data] : [];
|
|
206
203
|
}, props.watchOptions);
|
|
207
|
-
const virtualizerProps = toRef(() => defu(typeof props.virtualize === "boolean" ? {} : props.virtualize, {
|
|
208
|
-
estimateSize: 65,
|
|
209
|
-
overscan: 12
|
|
210
|
-
}));
|
|
211
|
-
const virtualizer = !!props.virtualize && useVirtualizer({
|
|
212
|
-
...virtualizerProps.value,
|
|
213
|
-
get count() {
|
|
214
|
-
return rows.value.length;
|
|
215
|
-
},
|
|
216
|
-
getScrollElement: () => unrefElement(rootRef),
|
|
217
|
-
estimateSize: (index) => {
|
|
218
|
-
const estimate = virtualizerProps.value.estimateSize;
|
|
219
|
-
return typeof estimate === "function" ? estimate(index) : estimate;
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
const renderedSize = computed(() => {
|
|
223
|
-
if (!virtualizer)
|
|
224
|
-
return 0;
|
|
225
|
-
const virtualItems = virtualizer.value.getVirtualItems();
|
|
226
|
-
if (!virtualItems?.length)
|
|
227
|
-
return 0;
|
|
228
|
-
return virtualItems.reduce((sum, item) => sum + item.size, 0);
|
|
229
|
-
});
|
|
230
204
|
const style = computed(() => useStyleResolver((theme) => ({
|
|
231
205
|
"--table-loader-color": props.loadingColor ? getThemeColor(props.loadingColor, theme) : void 0,
|
|
232
206
|
"--vertical-align": props.verticalAlign
|
|
233
207
|
})));
|
|
208
|
+
const { onRowContextmenu, onRowHover, onRowSelect } = createRowHandlers(props);
|
|
234
209
|
defineExpose({
|
|
235
210
|
get $el() {
|
|
236
211
|
return unrefElement(rootRef);
|
|
@@ -241,15 +216,7 @@ defineExpose({
|
|
|
241
216
|
</script>
|
|
242
217
|
|
|
243
218
|
<template>
|
|
244
|
-
<Box
|
|
245
|
-
ref='rootRef'
|
|
246
|
-
:class='[$style.root, props.classes?.root]'
|
|
247
|
-
:style='[
|
|
248
|
-
virtualizer ? { height: `${virtualizer.getTotalSize()}px` } : void 0,
|
|
249
|
-
style
|
|
250
|
-
]'
|
|
251
|
-
:mod='{ virtualize: !!virtualizer }'
|
|
252
|
-
>
|
|
219
|
+
<Box ref='rootRef' :class='[$style.root, props.classes?.root]' :style>
|
|
253
220
|
<table ref='tableRef' :class='[$style.table, props.classes?.table]'>
|
|
254
221
|
<caption v-if='caption || $slots.caption' :class='props.classes?.caption'>
|
|
255
222
|
<slot name='caption'>
|
|
@@ -274,8 +241,15 @@ defineExpose({
|
|
|
274
241
|
:scope="header.colSpan > 1 ? 'colgroup' : 'col'"
|
|
275
242
|
:colspan='header.colSpan > 1 ? header.colSpan : void 0'
|
|
276
243
|
:rowspan='header.rowSpan > 1 ? header.rowSpan : void 0'
|
|
277
|
-
:class='[
|
|
278
|
-
|
|
244
|
+
:class='[
|
|
245
|
+
$style.th,
|
|
246
|
+
props.classes?.th,
|
|
247
|
+
resolveValue(header.column.columnDef.meta?.class?.th, header)
|
|
248
|
+
]'
|
|
249
|
+
:style='[
|
|
250
|
+
{ width: header.getSize() !== 150 ? `${header.getSize()}px` : void 0 },
|
|
251
|
+
resolveValue(header.column.columnDef.meta?.style?.th, header)
|
|
252
|
+
]'
|
|
279
253
|
>
|
|
280
254
|
<slot :name='`${header.id}-header`' v-bind='header.getContext()'>
|
|
281
255
|
<FlexRender
|
|
@@ -294,36 +268,47 @@ defineExpose({
|
|
|
294
268
|
<slot name='body-top' />
|
|
295
269
|
|
|
296
270
|
<template v-if='rows.length'>
|
|
297
|
-
<template v-
|
|
298
|
-
<
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
resolveValue(table.options.meta?.style?.tr, virtualRow)
|
|
308
|
-
]'
|
|
309
|
-
:on-select='props?.onSelect'
|
|
310
|
-
:on-hover='props?.onHover'
|
|
311
|
-
:on-contextmenu='props?.onContextmenu'
|
|
312
|
-
/>
|
|
313
|
-
</template>
|
|
314
|
-
</template>
|
|
315
|
-
|
|
316
|
-
<template v-else>
|
|
317
|
-
<TableRow
|
|
318
|
-
v-for='row in rows'
|
|
319
|
-
:key='row.id'
|
|
320
|
-
:row='row'
|
|
271
|
+
<template v-for='row in rows' :key='row.id'>
|
|
272
|
+
<Box
|
|
273
|
+
is='tr'
|
|
274
|
+
:mod='{
|
|
275
|
+
selected: row.getIsSelected(),
|
|
276
|
+
expanded: row.getIsExpanded(),
|
|
277
|
+
selectable: !!onSelect || !!onHover || !!onContextmenu
|
|
278
|
+
}'
|
|
279
|
+
:role="onSelect ? 'button' : void 0"
|
|
280
|
+
:tabindex='onSelect ? 0 : void 0'
|
|
321
281
|
:class='[$style.tr, props.classes?.tr, resolveValue(table.options.meta?.class?.tr, row)]'
|
|
322
282
|
:style='resolveValue(table.options.meta?.style?.tr, row)'
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
283
|
+
@click='onRowSelect($event, row)'
|
|
284
|
+
@pointerenter='onRowHover($event, row)'
|
|
285
|
+
@pointerleave='onRowHover($event, null)'
|
|
286
|
+
@contextmenu='onRowContextmenu($event, row)'
|
|
287
|
+
>
|
|
288
|
+
<Box
|
|
289
|
+
is='td'
|
|
290
|
+
v-for='cell in row.getVisibleCells()'
|
|
291
|
+
:key='cell.id'
|
|
292
|
+
:mod='{ pinned: cell.column.getIsPinned() }'
|
|
293
|
+
:colspan='resolveValue(cell.column.columnDef.meta?.colspan?.td, cell)'
|
|
294
|
+
:rowspan='resolveValue(cell.column.columnDef.meta?.rowspan?.td, cell)'
|
|
295
|
+
:class='resolveValue(cell.column.columnDef.meta?.class?.td, cell)'
|
|
296
|
+
:style='[
|
|
297
|
+
{ width: cell.column.getSize() !== 150 ? `${cell.column.getSize()}px` : void 0 },
|
|
298
|
+
resolveValue(cell.column.columnDef.meta?.style?.td, cell)
|
|
299
|
+
]'
|
|
300
|
+
>
|
|
301
|
+
<slot :name='`${cell.column.id}-cell`' v-bind='cell.getContext()'>
|
|
302
|
+
<FlexRender :render='cell.column.columnDef.cell' :props='cell.getContext()' />
|
|
303
|
+
</slot>
|
|
304
|
+
</Box>
|
|
305
|
+
</Box>
|
|
306
|
+
|
|
307
|
+
<tr v-if='row.getIsExpanded()'>
|
|
308
|
+
<td :colspan='row.getAllCells().length'>
|
|
309
|
+
<slot name='expanded' :row='row' />
|
|
310
|
+
</td>
|
|
311
|
+
</tr>
|
|
327
312
|
</template>
|
|
328
313
|
</template>
|
|
329
314
|
|
|
@@ -348,7 +333,6 @@ defineExpose({
|
|
|
348
333
|
is='tfoot'
|
|
349
334
|
v-if='hasFooter'
|
|
350
335
|
:class='[$style.tfoot, props.classes?.tfoot]'
|
|
351
|
-
:style='virtualizer ? { transform: `translateY(${virtualizer.getTotalSize() - renderedSize}px)` } : void 0'
|
|
352
336
|
:mod='{ sticky: props.sticky === "footer" || props.sticky === true }'
|
|
353
337
|
>
|
|
354
338
|
<tr :class='[$style.separator, props.classes?.separator]' />
|
|
@@ -8,6 +8,7 @@ import Loader from "../../loader/loader.vue";
|
|
|
8
8
|
import RovingFocusItem from "../../roving-focus/roving-focus-item.vue";
|
|
9
9
|
import UTransition from "../../transition/transition.vue";
|
|
10
10
|
import { useTreeState } from "../lib/context";
|
|
11
|
+
import { filterTreeItems } from "../lib/filter-tree-items";
|
|
11
12
|
import { useTreeItemHandlers } from "../lib/item-handlers";
|
|
12
13
|
const {
|
|
13
14
|
type = "file",
|
|
@@ -33,7 +34,8 @@ const ctx = useTreeState();
|
|
|
33
34
|
const selected = computed(() => ctx.selected.value.includes(path));
|
|
34
35
|
const expanded = computed(() => ctx.expanded.value.includes(path));
|
|
35
36
|
const active = computed(() => ctx.active.value === path);
|
|
36
|
-
const { data, pending, execute } = ctx.loadBranch(path);
|
|
37
|
+
const { data: state, pending, execute } = ctx.loadBranch(path);
|
|
38
|
+
const data = computed(() => filterTreeItems(state.value, ctx.filter));
|
|
37
39
|
watch(expanded, (expanded2) => {
|
|
38
40
|
if (expanded2) {
|
|
39
41
|
try {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { ButtonProps } from '@nui/components';
|
|
2
2
|
import type { RovingFocusProps } from '../../roving-focus/roving-focus.vue.js';
|
|
3
|
-
import type { TreeIconResolver, TreeLoader, TreeModels } from '../model.js';
|
|
3
|
+
import type { TreeFilter, TreeIconResolver, TreeLoader, TreeModels } from '../model.js';
|
|
4
4
|
export type TreeRootProps = RovingFocusProps & {
|
|
5
5
|
iconResolver?: TreeIconResolver;
|
|
6
6
|
removable?: boolean;
|
|
7
7
|
selectable?: boolean;
|
|
8
8
|
loadBranch: TreeLoader;
|
|
9
|
+
filter?: TreeFilter;
|
|
9
10
|
variant?: ButtonProps['variant'];
|
|
10
11
|
color?: ButtonProps['color'];
|
|
11
12
|
size?: ButtonProps['size'];
|
|
@@ -16,7 +16,8 @@ const {
|
|
|
16
16
|
iconResolver = () => ({ icon: "gravity-ui:file" }),
|
|
17
17
|
removable = false,
|
|
18
18
|
selectable = false,
|
|
19
|
-
loadBranch
|
|
19
|
+
loadBranch,
|
|
20
|
+
filter
|
|
20
21
|
} = defineProps({
|
|
21
22
|
loop: { type: Boolean, required: false },
|
|
22
23
|
orientation: { type: String, required: false },
|
|
@@ -25,6 +26,7 @@ const {
|
|
|
25
26
|
removable: { type: Boolean, required: false },
|
|
26
27
|
selectable: { type: Boolean, required: false },
|
|
27
28
|
loadBranch: { type: Function, required: true },
|
|
29
|
+
filter: { type: [String, null, Function], required: false },
|
|
28
30
|
variant: { type: String, required: false },
|
|
29
31
|
color: { type: null, required: false },
|
|
30
32
|
size: { type: null, required: false }
|
|
@@ -48,7 +50,8 @@ useProvideTreeState({
|
|
|
48
50
|
color,
|
|
49
51
|
variant,
|
|
50
52
|
selectable,
|
|
51
|
-
loadBranch
|
|
53
|
+
loadBranch,
|
|
54
|
+
filter
|
|
52
55
|
});
|
|
53
56
|
if (removable) {
|
|
54
57
|
useEventListener(root, "keydown", (event) => {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { ButtonProps } from '@nui/components';
|
|
2
2
|
import type { RovingFocusProps } from '../../roving-focus/roving-focus.vue.js';
|
|
3
|
-
import type { TreeIconResolver, TreeLoader, TreeModels } from '../model.js';
|
|
3
|
+
import type { TreeFilter, TreeIconResolver, TreeLoader, TreeModels } from '../model.js';
|
|
4
4
|
export type TreeRootProps = RovingFocusProps & {
|
|
5
5
|
iconResolver?: TreeIconResolver;
|
|
6
6
|
removable?: boolean;
|
|
7
7
|
selectable?: boolean;
|
|
8
8
|
loadBranch: TreeLoader;
|
|
9
|
+
filter?: TreeFilter;
|
|
9
10
|
variant?: ButtonProps['variant'];
|
|
10
11
|
color?: ButtonProps['color'];
|
|
11
12
|
size?: ButtonProps['size'];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ButtonProps } from '@nui/components';
|
|
2
2
|
import type { ModelRef, ShallowRef } from 'vue';
|
|
3
|
-
import type { TreeIconResolver, TreeLoader } from '../model.js';
|
|
3
|
+
import type { TreeFilter, TreeIconResolver, TreeLoader } from '../model.js';
|
|
4
4
|
type EventType = 'select' | 'expand';
|
|
5
5
|
type SelectMode = 'single' | 'multiple' | 'range';
|
|
6
6
|
export interface TreeContext {
|
|
@@ -10,6 +10,7 @@ export interface TreeContext {
|
|
|
10
10
|
expanded: ModelRef<string[]>;
|
|
11
11
|
iconResolver: TreeIconResolver;
|
|
12
12
|
loadBranch: TreeLoader;
|
|
13
|
+
filter?: TreeFilter;
|
|
13
14
|
selectable: boolean;
|
|
14
15
|
variant: ButtonProps['variant'];
|
|
15
16
|
color: ButtonProps['color'];
|
|
@@ -10,8 +10,6 @@ export function useTreeItemHandlers(path, isFolder, expanded) {
|
|
|
10
10
|
ctx.toggle("select", path, "multiple");
|
|
11
11
|
else
|
|
12
12
|
ctx.toggle("select", path, "single");
|
|
13
|
-
if (isFolder.value && !event.ctrlKey && !event.metaKey && !event.shiftKey)
|
|
14
|
-
ctx.toggle("expand", path);
|
|
15
13
|
}
|
|
16
14
|
function handleKeyDown(event) {
|
|
17
15
|
switch (event.key) {
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { onMounted } from "vue";
|
|
2
|
+
import { computed, onMounted } from "vue";
|
|
3
3
|
import UTreeItem from "./_ui/tree-item.vue";
|
|
4
4
|
import TreeRoot from "./_ui/tree-root.vue";
|
|
5
|
+
import { filterTreeItems } from "./lib/filter-tree-items";
|
|
5
6
|
const {
|
|
6
7
|
color,
|
|
7
8
|
variant = "subtle",
|
|
8
9
|
size = "compact-sm",
|
|
9
10
|
loadBranch,
|
|
11
|
+
filter = "directory",
|
|
10
12
|
...props
|
|
11
13
|
} = defineProps({
|
|
12
14
|
loop: { type: Boolean, required: false },
|
|
@@ -16,6 +18,7 @@ const {
|
|
|
16
18
|
removable: { type: Boolean, required: false },
|
|
17
19
|
selectable: { type: Boolean, required: false },
|
|
18
20
|
loadBranch: { type: Function, required: true },
|
|
21
|
+
filter: { type: [String, null, Function], required: false },
|
|
19
22
|
variant: { type: String, required: false },
|
|
20
23
|
color: { type: null, required: false },
|
|
21
24
|
size: { type: null, required: false }
|
|
@@ -24,7 +27,8 @@ defineEmits(["delete"]);
|
|
|
24
27
|
const active = defineModel("active", { type: [String, null], ...{ default: null } });
|
|
25
28
|
const selected = defineModel("selected", { type: Array, ...{ default: [] } });
|
|
26
29
|
const expanded = defineModel("expanded", { type: Array, ...{ default: [] } });
|
|
27
|
-
const { data:
|
|
30
|
+
const { data: state, execute } = loadBranch("/");
|
|
31
|
+
const root = computed(() => filterTreeItems(state.value, filter));
|
|
28
32
|
onMounted(execute);
|
|
29
33
|
</script>
|
|
30
34
|
|
|
@@ -38,6 +42,7 @@ onMounted(execute);
|
|
|
38
42
|
:size
|
|
39
43
|
:color
|
|
40
44
|
:variant
|
|
45
|
+
:filter
|
|
41
46
|
@delete='(path) => $emit("delete", path)'
|
|
42
47
|
>
|
|
43
48
|
<UTreeItem
|
package/package.json
CHANGED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { Row } from '@tanstack/vue-table';
|
|
2
|
-
import type { TableData, TableRow } from '../model.js';
|
|
3
|
-
export interface TableRowProps<T extends TableData> {
|
|
4
|
-
row: Row<T>;
|
|
5
|
-
onSelect?: (e: Event, row: TableRow<T>) => void;
|
|
6
|
-
onHover?: (e: Event, row: TableRow<T> | null) => void;
|
|
7
|
-
onContextmenu?: ((e: Event, row: TableRow<T>) => void) | Array<((e: Event, row: TableRow<T>) => void)>;
|
|
8
|
-
}
|
|
9
|
-
declare const __VLS_export: <T extends TableData>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
10
|
-
props: __VLS_PrettifyLocal<TableRowProps<T>> & import("vue").PublicProps;
|
|
11
|
-
expose: (exposed: {}) => void;
|
|
12
|
-
attrs: any;
|
|
13
|
-
slots: {
|
|
14
|
-
[x: `${string}-cell`]: ((props: {
|
|
15
|
-
cell: import("@tanstack/table-core").Cell<T, unknown>;
|
|
16
|
-
column: import("@tanstack/table-core").Column<T, unknown>;
|
|
17
|
-
getValue: import("@tanstack/table-core").Getter<unknown>;
|
|
18
|
-
renderValue: import("@tanstack/table-core").Getter<unknown>;
|
|
19
|
-
row: Row<T>;
|
|
20
|
-
table: import("@tanstack/table-core").Table<T>;
|
|
21
|
-
}) => any) | undefined;
|
|
22
|
-
} & {
|
|
23
|
-
expanded?: (props: {
|
|
24
|
-
row: Row<T>;
|
|
25
|
-
}) => any;
|
|
26
|
-
};
|
|
27
|
-
emit: {};
|
|
28
|
-
}>) => import("vue").VNode & {
|
|
29
|
-
__ctx?: Awaited<typeof __VLS_setup>;
|
|
30
|
-
};
|
|
31
|
-
declare const _default: typeof __VLS_export;
|
|
32
|
-
export default _default;
|
|
33
|
-
type __VLS_PrettifyLocal<T> = {
|
|
34
|
-
[K in keyof T as K]: T[K];
|
|
35
|
-
} & {};
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { FlexRender } from "@tanstack/vue-table";
|
|
3
|
-
import Box from "../../box.vue";
|
|
4
|
-
import { resolveValue } from "../lib";
|
|
5
|
-
const { row, onSelect, onHover, onContextmenu } = defineProps({
|
|
6
|
-
row: { type: Object, required: true },
|
|
7
|
-
onSelect: { type: Function, required: false },
|
|
8
|
-
onHover: { type: Function, required: false },
|
|
9
|
-
onContextmenu: { type: [Function, Array], required: false }
|
|
10
|
-
});
|
|
11
|
-
function onRowSelect(e, row2) {
|
|
12
|
-
if (!onSelect)
|
|
13
|
-
return;
|
|
14
|
-
const target = e.target;
|
|
15
|
-
const isInteractive = target.closest("button") || target.closest("a");
|
|
16
|
-
if (isInteractive)
|
|
17
|
-
return;
|
|
18
|
-
e.preventDefault();
|
|
19
|
-
e.stopPropagation();
|
|
20
|
-
onSelect(e, row2);
|
|
21
|
-
}
|
|
22
|
-
function onRowHover(e, row2) {
|
|
23
|
-
if (!onHover)
|
|
24
|
-
return;
|
|
25
|
-
onHover(e, row2);
|
|
26
|
-
}
|
|
27
|
-
function onRowContextmenu(e, row2) {
|
|
28
|
-
if (!onContextmenu)
|
|
29
|
-
return;
|
|
30
|
-
if (Array.isArray(onContextmenu))
|
|
31
|
-
onContextmenu.forEach((fn) => fn(e, row2));
|
|
32
|
-
else
|
|
33
|
-
onContextmenu(e, row2);
|
|
34
|
-
}
|
|
35
|
-
</script>
|
|
36
|
-
|
|
37
|
-
<template>
|
|
38
|
-
<Box
|
|
39
|
-
is='tr'
|
|
40
|
-
v-bind='$attrs'
|
|
41
|
-
:mod='{
|
|
42
|
-
selected: row.getIsSelected(),
|
|
43
|
-
expanded: row.getIsExpanded(),
|
|
44
|
-
selectable: !!onSelect || !!onHover || !!onContextmenu
|
|
45
|
-
}'
|
|
46
|
-
:role="onSelect ? 'button' : void 0"
|
|
47
|
-
:tabindex='onSelect ? 0 : void 0'
|
|
48
|
-
@click='onRowSelect($event, row)'
|
|
49
|
-
@pointerenter='onRowHover($event, row)'
|
|
50
|
-
@pointerleave='onRowHover($event, null)'
|
|
51
|
-
@contextmenu='onRowContextmenu($event, row)'
|
|
52
|
-
>
|
|
53
|
-
<Box
|
|
54
|
-
is='td'
|
|
55
|
-
v-for='cell in row.getVisibleCells()'
|
|
56
|
-
:key='cell.id'
|
|
57
|
-
:mod='{ pinned: cell.column.getIsPinned() }'
|
|
58
|
-
:colspan='resolveValue(cell.column.columnDef.meta?.colspan?.td, cell)'
|
|
59
|
-
:rowspan='resolveValue(cell.column.columnDef.meta?.rowspan?.td, cell)'
|
|
60
|
-
:class='resolveValue(cell.column.columnDef.meta?.class?.td, cell)'
|
|
61
|
-
:style='resolveValue(cell.column.columnDef.meta?.style?.td, cell)'
|
|
62
|
-
>
|
|
63
|
-
<slot :name='`${cell.column.id}-cell`' v-bind='cell.getContext()'>
|
|
64
|
-
<FlexRender :render='cell.column.columnDef.cell' :props='cell.getContext()' />
|
|
65
|
-
</slot>
|
|
66
|
-
</Box>
|
|
67
|
-
</Box>
|
|
68
|
-
|
|
69
|
-
<tr v-if='row.getIsExpanded()'>
|
|
70
|
-
<td :colspan='row.getAllCells().length'>
|
|
71
|
-
<slot name='expanded' :row='row' />
|
|
72
|
-
</td>
|
|
73
|
-
</tr>
|
|
74
|
-
</template>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { Row } from '@tanstack/vue-table';
|
|
2
|
-
import type { TableData, TableRow } from '../model.js';
|
|
3
|
-
export interface TableRowProps<T extends TableData> {
|
|
4
|
-
row: Row<T>;
|
|
5
|
-
onSelect?: (e: Event, row: TableRow<T>) => void;
|
|
6
|
-
onHover?: (e: Event, row: TableRow<T> | null) => void;
|
|
7
|
-
onContextmenu?: ((e: Event, row: TableRow<T>) => void) | Array<((e: Event, row: TableRow<T>) => void)>;
|
|
8
|
-
}
|
|
9
|
-
declare const __VLS_export: <T extends TableData>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
10
|
-
props: __VLS_PrettifyLocal<TableRowProps<T>> & import("vue").PublicProps;
|
|
11
|
-
expose: (exposed: {}) => void;
|
|
12
|
-
attrs: any;
|
|
13
|
-
slots: {
|
|
14
|
-
[x: `${string}-cell`]: ((props: {
|
|
15
|
-
cell: import("@tanstack/table-core").Cell<T, unknown>;
|
|
16
|
-
column: import("@tanstack/table-core").Column<T, unknown>;
|
|
17
|
-
getValue: import("@tanstack/table-core").Getter<unknown>;
|
|
18
|
-
renderValue: import("@tanstack/table-core").Getter<unknown>;
|
|
19
|
-
row: Row<T>;
|
|
20
|
-
table: import("@tanstack/table-core").Table<T>;
|
|
21
|
-
}) => any) | undefined;
|
|
22
|
-
} & {
|
|
23
|
-
expanded?: (props: {
|
|
24
|
-
row: Row<T>;
|
|
25
|
-
}) => any;
|
|
26
|
-
};
|
|
27
|
-
emit: {};
|
|
28
|
-
}>) => import("vue").VNode & {
|
|
29
|
-
__ctx?: Awaited<typeof __VLS_setup>;
|
|
30
|
-
};
|
|
31
|
-
declare const _default: typeof __VLS_export;
|
|
32
|
-
export default _default;
|
|
33
|
-
type __VLS_PrettifyLocal<T> = {
|
|
34
|
-
[K in keyof T as K]: T[K];
|
|
35
|
-
} & {};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { TreeItem } from '../model.js';
|
|
2
|
-
/**
|
|
3
|
-
* Получает все элементы дерева с expanded: true
|
|
4
|
-
* @param items - массив элементов дерева
|
|
5
|
-
* @returns массив value элементов с expanded: true
|
|
6
|
-
*/
|
|
7
|
-
export declare function getExpandedItems<T extends string = string>(items: TreeItem<T>[]): T[];
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export function getExpandedItems(items) {
|
|
2
|
-
const result = [];
|
|
3
|
-
for (const item of items) {
|
|
4
|
-
if (item.expanded === true)
|
|
5
|
-
result.push(item.value);
|
|
6
|
-
if (item.children && item.children.length > 0)
|
|
7
|
-
result.push(...getExpandedItems(item.children));
|
|
8
|
-
}
|
|
9
|
-
return result;
|
|
10
|
-
}
|