nuance-ui 0.1.7 → 0.1.9
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/module.mjs +1 -20
- package/dist/runtime/components/action-icon/action-icon.d.vue.ts +1 -0
- package/dist/runtime/components/action-icon/action-icon.vue.d.ts +1 -0
- package/dist/runtime/components/alert.d.vue.ts +48 -0
- package/dist/runtime/components/alert.vue +178 -0
- package/dist/runtime/components/alert.vue.d.ts +48 -0
- package/dist/runtime/components/app-shell/app-shell-main.vue +1 -0
- package/dist/runtime/components/box.d.vue.ts +1 -1
- package/dist/runtime/components/box.vue +10 -2
- package/dist/runtime/components/box.vue.d.ts +1 -1
- package/dist/runtime/components/button/button.d.vue.ts +1 -0
- package/dist/runtime/components/button/button.vue +3 -3
- package/dist/runtime/components/button/button.vue.d.ts +1 -0
- package/dist/runtime/components/checkbox/checkbox-card.d.vue.ts +1 -1
- package/dist/runtime/components/checkbox/checkbox-card.vue.d.ts +1 -1
- package/dist/runtime/components/index.d.ts +3 -0
- package/dist/runtime/components/index.js +3 -0
- package/dist/runtime/components/input/number-input.vue +12 -16
- package/dist/runtime/components/input/ui/input-base.d.vue.ts +3 -3
- package/dist/runtime/components/input/ui/input-base.vue +2 -2
- package/dist/runtime/components/input/ui/input-base.vue.d.ts +3 -3
- package/dist/runtime/components/link/lib.d.ts +2 -2
- package/dist/runtime/components/nav-link/nav-link.vue +10 -10
- package/dist/runtime/components/progress/index.d.ts +3 -0
- package/dist/runtime/components/progress/index.js +0 -0
- package/dist/runtime/components/progress/progress-label.d.vue.ts +14 -0
- package/dist/runtime/components/progress/progress-label.vue +14 -0
- package/dist/runtime/components/progress/progress-label.vue.d.ts +14 -0
- package/dist/runtime/components/progress/progress-root.d.vue.ts +25 -0
- package/dist/runtime/components/progress/progress-root.vue +31 -0
- package/dist/runtime/components/progress/progress-root.vue.d.ts +25 -0
- package/dist/runtime/components/progress/progress-section.d.vue.ts +25 -0
- package/dist/runtime/components/progress/progress-section.vue +42 -0
- package/dist/runtime/components/progress/progress-section.vue.d.ts +25 -0
- package/dist/runtime/components/progress/progress.d.vue.ts +16 -0
- package/dist/runtime/components/progress/progress.module.css +1 -0
- package/dist/runtime/components/progress/progress.vue +39 -0
- package/dist/runtime/components/progress/progress.vue.d.ts +16 -0
- package/dist/runtime/components/roving-focus/_lib/context.d.ts +51 -0
- package/dist/runtime/components/roving-focus/_lib/context.js +90 -0
- package/dist/runtime/components/roving-focus/index.d.ts +1 -0
- package/dist/runtime/components/roving-focus/index.js +1 -0
- package/dist/runtime/components/roving-focus/roving-focus-item.d.vue.ts +13 -0
- package/dist/runtime/components/roving-focus/roving-focus-item.vue +32 -0
- package/dist/runtime/components/roving-focus/roving-focus-item.vue.d.ts +13 -0
- package/dist/runtime/components/roving-focus/roving-focus.d.vue.ts +21 -0
- package/dist/runtime/components/roving-focus/roving-focus.vue +23 -0
- package/dist/runtime/components/roving-focus/roving-focus.vue.d.ts +21 -0
- package/dist/runtime/components/select/select.d.vue.ts +2 -2
- package/dist/runtime/components/select/select.vue.d.ts +2 -2
- package/dist/runtime/components/tabs/tabs-tab.d.vue.ts +1 -1
- package/dist/runtime/components/tabs/tabs-tab.vue.d.ts +1 -1
- package/dist/runtime/components/tree/_ui/tree-item.d.vue.ts +0 -0
- package/dist/runtime/components/tree/_ui/tree-item.vue +172 -0
- package/dist/runtime/components/tree/_ui/tree-item.vue.d.ts +0 -0
- package/dist/runtime/components/tree/_ui/tree-root.d.vue.ts +39 -0
- package/dist/runtime/components/tree/_ui/tree-root.vue +87 -0
- package/dist/runtime/components/tree/_ui/tree-root.vue.d.ts +39 -0
- package/dist/runtime/components/tree/index.d.ts +1 -0
- package/dist/runtime/components/tree/index.js +1 -0
- package/dist/runtime/components/tree/lib/context.d.ts +32 -0
- package/dist/runtime/components/tree/lib/context.js +103 -0
- package/dist/runtime/components/tree/lib/get-default.d.ts +7 -0
- package/dist/runtime/components/tree/lib/get-default.js +10 -0
- package/dist/runtime/components/tree/model.d.ts +33 -0
- package/dist/runtime/components/tree/model.js +0 -0
- package/dist/runtime/components/tree/tree.d.vue.ts +23 -0
- package/dist/runtime/components/tree/tree.vue +46 -0
- package/dist/runtime/components/tree/tree.vue.d.ts +23 -0
- package/dist/runtime/composals/index.d.ts +0 -1
- package/dist/runtime/composals/index.js +0 -1
- package/dist/runtime/styles/colors.css +1 -1
- package/dist/runtime/styles/light-theme.css +1 -1
- package/dist/runtime/utils/get-mod.d.ts +2 -0
- package/dist/runtime/{composals/use-mod.js → utils/get-mod.js} +2 -13
- package/dist/runtime/utils/index.d.ts +2 -0
- package/dist/runtime/utils/index.js +2 -0
- package/dist/runtime/utils/tree.d.ts +107 -0
- package/dist/runtime/utils/tree.js +85 -0
- package/package.json +1 -1
- package/dist/runtime/composals/use-mod.d.ts +0 -2
|
File without changes
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useTheme } from "@nui/composals";
|
|
3
|
+
import { getThemeColor, isFalsy } from "@nui/utils";
|
|
4
|
+
import { computed } from "vue";
|
|
5
|
+
import Button from "../../button/button.vue";
|
|
6
|
+
import { useRovingFocus } from "../../roving-focus";
|
|
7
|
+
import RovingFocusItem from "../../roving-focus/roving-focus-item.vue";
|
|
8
|
+
import { useTreeState } from "../lib/context";
|
|
9
|
+
const { item, level } = defineProps({
|
|
10
|
+
item: { type: Object, required: true },
|
|
11
|
+
level: { type: Number, required: true }
|
|
12
|
+
});
|
|
13
|
+
const {
|
|
14
|
+
icon = "gravity-ui:folder",
|
|
15
|
+
trailingIcon = "gravity-ui:folder-open",
|
|
16
|
+
value,
|
|
17
|
+
label,
|
|
18
|
+
children,
|
|
19
|
+
disabled
|
|
20
|
+
} = item;
|
|
21
|
+
const { value: theme } = useTheme();
|
|
22
|
+
const isFolder = computed(() => !isFalsy(children));
|
|
23
|
+
const ctx = useTreeState();
|
|
24
|
+
const selected = computed(() => ctx.selected.value.includes(value));
|
|
25
|
+
const expanded = computed(() => ctx.expanded.value.includes(value));
|
|
26
|
+
const active = computed(() => ctx.active.value === value);
|
|
27
|
+
const { icon: fileIcon, color } = ctx.iconResolver(item);
|
|
28
|
+
const { focus } = useRovingFocus();
|
|
29
|
+
function handleClick(event) {
|
|
30
|
+
if (event.shiftKey)
|
|
31
|
+
ctx.toggle("select", value, "range");
|
|
32
|
+
else if (event.ctrlKey || event.metaKey)
|
|
33
|
+
ctx.toggle("select", value, "multiple");
|
|
34
|
+
else
|
|
35
|
+
ctx.toggle("select", value, "single");
|
|
36
|
+
if (isFolder.value && !event.ctrlKey && !event.metaKey && !event.shiftKey)
|
|
37
|
+
ctx.toggle("expand", value);
|
|
38
|
+
}
|
|
39
|
+
function handleKeyDown(event) {
|
|
40
|
+
switch (event.key) {
|
|
41
|
+
// Arrow Left - закрыть папку или перейти к родителю
|
|
42
|
+
case "ArrowLeft": {
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
if (isFolder.value && expanded.value)
|
|
45
|
+
return ctx.off("expand", value);
|
|
46
|
+
else
|
|
47
|
+
return focus("prev", event.currentTarget);
|
|
48
|
+
}
|
|
49
|
+
// Arrow Right - открыть папку или перейти к первому ребенку
|
|
50
|
+
case "ArrowRight": {
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
if (isFolder.value && !expanded.value)
|
|
53
|
+
return ctx.on("expand", value);
|
|
54
|
+
else if (expanded.value)
|
|
55
|
+
return focus("next", event.currentTarget);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
// Enter/Space - выбор элемента
|
|
59
|
+
case "Enter": {
|
|
60
|
+
ctx.on("select", value);
|
|
61
|
+
return ctx.setActive(value);
|
|
62
|
+
}
|
|
63
|
+
case " ": {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
if (event.shiftKey)
|
|
66
|
+
return ctx.toggle("select", value, "range");
|
|
67
|
+
else if (event.ctrlKey || event.metaKey)
|
|
68
|
+
return ctx.toggle("select", value, "multiple");
|
|
69
|
+
return ctx.toggle("select", value, "single");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<template>
|
|
76
|
+
<li :class='$style.root' role='presentation'>
|
|
77
|
+
<RovingFocusItem>
|
|
78
|
+
<Button
|
|
79
|
+
:size='ctx.size'
|
|
80
|
+
:color='ctx.color'
|
|
81
|
+
:variant='ctx.variant'
|
|
82
|
+
:disabled
|
|
83
|
+
role='treeitem'
|
|
84
|
+
:classes='{
|
|
85
|
+
root: $style.button,
|
|
86
|
+
label: $style.label,
|
|
87
|
+
inner: $style.inner,
|
|
88
|
+
section: $style.section
|
|
89
|
+
}'
|
|
90
|
+
:aria-level='level'
|
|
91
|
+
:aria-selected='selected'
|
|
92
|
+
:mod='{ active, selected, level }'
|
|
93
|
+
@click.prevent='handleClick'
|
|
94
|
+
@keydown.prevent='handleKeyDown'
|
|
95
|
+
>
|
|
96
|
+
<template v-if='isFolder' #leftSection>
|
|
97
|
+
<Icon v-if='expanded' :class='$style.icon' :name='trailingIcon' />
|
|
98
|
+
<Icon v-else :class='$style.icon' :name='icon' />
|
|
99
|
+
</template>
|
|
100
|
+
<template v-else #leftSection>
|
|
101
|
+
<Icon
|
|
102
|
+
:class='$style.icon'
|
|
103
|
+
:name='fileIcon'
|
|
104
|
+
:style='{ color: color && getThemeColor(color, theme) }'
|
|
105
|
+
/>
|
|
106
|
+
</template>
|
|
107
|
+
{{ label ?? value }}
|
|
108
|
+
</Button>
|
|
109
|
+
</RovingFocusItem>
|
|
110
|
+
|
|
111
|
+
<ul
|
|
112
|
+
v-if='expanded && item.children && item.children.length > 0'
|
|
113
|
+
:class='$style.list'
|
|
114
|
+
role='group'
|
|
115
|
+
>
|
|
116
|
+
<TreeItem
|
|
117
|
+
v-for='child in item.children'
|
|
118
|
+
:key='child.value'
|
|
119
|
+
:item='child'
|
|
120
|
+
:level='level + 1'
|
|
121
|
+
/>
|
|
122
|
+
</ul>
|
|
123
|
+
</li>
|
|
124
|
+
</template>
|
|
125
|
+
|
|
126
|
+
<style module lang="postcss">
|
|
127
|
+
.root {
|
|
128
|
+
display: grid;
|
|
129
|
+
gap: .25rem;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.button {
|
|
133
|
+
.inner {
|
|
134
|
+
display: grid;
|
|
135
|
+
grid-template-columns: auto 1fr auto;
|
|
136
|
+
|
|
137
|
+
color: var(--color-text);
|
|
138
|
+
|
|
139
|
+
.label {
|
|
140
|
+
font-weight: 500;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
&[data-active],
|
|
145
|
+
&[data-selected] {
|
|
146
|
+
.inner {
|
|
147
|
+
color: var(--button-color);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
&[data-selected] {
|
|
152
|
+
background: alpha(var(--button-color), .1);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.icon {
|
|
157
|
+
width: var(--tree-icon-size);
|
|
158
|
+
height: var(--tree-icon-size);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.list {
|
|
162
|
+
display: grid;
|
|
163
|
+
gap: .25rem;
|
|
164
|
+
|
|
165
|
+
margin-inline-start: 1rem;
|
|
166
|
+
|
|
167
|
+
padding-inline-start: .75rem;
|
|
168
|
+
border-left: 1px solid var(--color-gray-4);
|
|
169
|
+
|
|
170
|
+
list-style: none;
|
|
171
|
+
}
|
|
172
|
+
</style>
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ButtonProps } from '@nui/components';
|
|
2
|
+
import type { RovingFocusProps } from '../../roving-focus/roving-focus.vue.js';
|
|
3
|
+
import type { TreeIconResolver, TreeModels } from '../model.js';
|
|
4
|
+
export type TreeRootProps<T extends string = string> = RovingFocusProps & {
|
|
5
|
+
iconResolver?: TreeIconResolver<T>;
|
|
6
|
+
removable?: boolean;
|
|
7
|
+
selectable?: boolean;
|
|
8
|
+
variant?: ButtonProps['variant'];
|
|
9
|
+
color?: ButtonProps['color'];
|
|
10
|
+
size?: ButtonProps['size'];
|
|
11
|
+
};
|
|
12
|
+
declare const __VLS_export: <T extends string = string>(__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<{
|
|
13
|
+
props: __VLS_PrettifyLocal<(RovingFocusProps & {
|
|
14
|
+
iconResolver?: TreeIconResolver<T> | undefined;
|
|
15
|
+
removable?: boolean;
|
|
16
|
+
selectable?: boolean;
|
|
17
|
+
variant?: ButtonProps["variant"];
|
|
18
|
+
color?: ButtonProps["color"];
|
|
19
|
+
size?: ButtonProps["size"];
|
|
20
|
+
} & {
|
|
21
|
+
tree: TreeModels<T>["tree"];
|
|
22
|
+
active?: TreeModels<T>["active"];
|
|
23
|
+
selected?: TreeModels<T>["selected"];
|
|
24
|
+
expanded?: TreeModels<T>["expanded"];
|
|
25
|
+
}) & __VLS_EmitsToProps<__VLS_NormalizeEmits<((evt: "update:tree", value: import("@nui/components").TreeItem<T>[]) => void) & ((evt: "update:active", value: T | null) => void) & ((evt: "update:selected", value: T[]) => void) & ((evt: "update:expanded", value: T[]) => void)>>> & import("vue").PublicProps;
|
|
26
|
+
expose: (exposed: {}) => void;
|
|
27
|
+
attrs: any;
|
|
28
|
+
slots: {
|
|
29
|
+
default?: (props: {}) => any;
|
|
30
|
+
};
|
|
31
|
+
emit: ((evt: "update:tree", value: import("@nui/components").TreeItem<T>[]) => void) & ((evt: "update:active", value: T | null) => void) & ((evt: "update:selected", value: T[]) => void) & ((evt: "update:expanded", value: T[]) => void);
|
|
32
|
+
}>) => import("vue").VNode & {
|
|
33
|
+
__ctx?: Awaited<typeof __VLS_setup>;
|
|
34
|
+
};
|
|
35
|
+
declare const _default: typeof __VLS_export;
|
|
36
|
+
export default _default;
|
|
37
|
+
type __VLS_PrettifyLocal<T> = {
|
|
38
|
+
[K in keyof T as K]: T[K];
|
|
39
|
+
} & {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useStyleResolver } from "@nui/composals";
|
|
3
|
+
import { getSize, removeTreeNodes } from "@nui/utils";
|
|
4
|
+
import { onClickOutside, useEventListener } from "@vueuse/core";
|
|
5
|
+
import { useTemplateRef } from "vue";
|
|
6
|
+
import Box from "../../box.vue";
|
|
7
|
+
import RovingFocus from "../../roving-focus/roving-focus.vue";
|
|
8
|
+
import { useProvideTreeState } from "../lib/context";
|
|
9
|
+
const {
|
|
10
|
+
color,
|
|
11
|
+
attr,
|
|
12
|
+
loop,
|
|
13
|
+
orientation,
|
|
14
|
+
variant = "subtle",
|
|
15
|
+
size = "compact-sm",
|
|
16
|
+
iconResolver = () => ({ icon: "gravity-ui:file" }),
|
|
17
|
+
removable = false,
|
|
18
|
+
selectable = false
|
|
19
|
+
} = defineProps({
|
|
20
|
+
loop: { type: Boolean, required: false },
|
|
21
|
+
orientation: { type: String, required: false },
|
|
22
|
+
attr: { type: String, required: false },
|
|
23
|
+
iconResolver: { type: Function, required: false },
|
|
24
|
+
removable: { type: Boolean, required: false },
|
|
25
|
+
selectable: { type: Boolean, required: false },
|
|
26
|
+
variant: { type: String, required: false },
|
|
27
|
+
color: { type: null, required: false },
|
|
28
|
+
size: { type: null, required: false }
|
|
29
|
+
});
|
|
30
|
+
const tree = defineModel("tree", { type: Array, ...{ required: true } });
|
|
31
|
+
const active = defineModel("active", { type: null, ...{ default: null } });
|
|
32
|
+
const selected = defineModel("selected", { type: Array, ...{ default: [] } });
|
|
33
|
+
const expanded = defineModel("expanded", { type: Array, ...{ default: [] } });
|
|
34
|
+
const style = useStyleResolver(() => ({
|
|
35
|
+
"--icon-size": getSize(size)
|
|
36
|
+
}));
|
|
37
|
+
const root = useTemplateRef("parent");
|
|
38
|
+
onClickOutside(root, () => selected.value = []);
|
|
39
|
+
useProvideTreeState({
|
|
40
|
+
tree,
|
|
41
|
+
active,
|
|
42
|
+
selected,
|
|
43
|
+
expanded,
|
|
44
|
+
iconResolver,
|
|
45
|
+
size,
|
|
46
|
+
color,
|
|
47
|
+
variant,
|
|
48
|
+
selectable
|
|
49
|
+
});
|
|
50
|
+
if (removable) {
|
|
51
|
+
useEventListener(root, "keydown", (event) => {
|
|
52
|
+
if (event.key === "Delete") {
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
return tree.value = removeTreeNodes(tree.value, selected.value);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<RovingFocus :attr :loop :orientation>
|
|
62
|
+
<Box
|
|
63
|
+
is='ul'
|
|
64
|
+
ref='parent'
|
|
65
|
+
role='tree'
|
|
66
|
+
:style
|
|
67
|
+
:class='$style.root'
|
|
68
|
+
@keydown.esc.prevent='selected.value = []'
|
|
69
|
+
>
|
|
70
|
+
<slot />
|
|
71
|
+
</Box>
|
|
72
|
+
</RovingFocus>
|
|
73
|
+
</template>
|
|
74
|
+
|
|
75
|
+
<style module lang="postcss">
|
|
76
|
+
.root {
|
|
77
|
+
--tree-icon-size: var(--spacing-md);
|
|
78
|
+
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
gap: .25rem;
|
|
82
|
+
|
|
83
|
+
padding-inline-start: 0;
|
|
84
|
+
|
|
85
|
+
list-style: none;
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ButtonProps } from '@nui/components';
|
|
2
|
+
import type { RovingFocusProps } from '../../roving-focus/roving-focus.vue.js';
|
|
3
|
+
import type { TreeIconResolver, TreeModels } from '../model.js';
|
|
4
|
+
export type TreeRootProps<T extends string = string> = RovingFocusProps & {
|
|
5
|
+
iconResolver?: TreeIconResolver<T>;
|
|
6
|
+
removable?: boolean;
|
|
7
|
+
selectable?: boolean;
|
|
8
|
+
variant?: ButtonProps['variant'];
|
|
9
|
+
color?: ButtonProps['color'];
|
|
10
|
+
size?: ButtonProps['size'];
|
|
11
|
+
};
|
|
12
|
+
declare const __VLS_export: <T extends string = string>(__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<{
|
|
13
|
+
props: __VLS_PrettifyLocal<(RovingFocusProps & {
|
|
14
|
+
iconResolver?: TreeIconResolver<T> | undefined;
|
|
15
|
+
removable?: boolean;
|
|
16
|
+
selectable?: boolean;
|
|
17
|
+
variant?: ButtonProps["variant"];
|
|
18
|
+
color?: ButtonProps["color"];
|
|
19
|
+
size?: ButtonProps["size"];
|
|
20
|
+
} & {
|
|
21
|
+
tree: TreeModels<T>["tree"];
|
|
22
|
+
active?: TreeModels<T>["active"];
|
|
23
|
+
selected?: TreeModels<T>["selected"];
|
|
24
|
+
expanded?: TreeModels<T>["expanded"];
|
|
25
|
+
}) & __VLS_EmitsToProps<__VLS_NormalizeEmits<((evt: "update:tree", value: import("@nui/components").TreeItem<T>[]) => void) & ((evt: "update:active", value: T | null) => void) & ((evt: "update:selected", value: T[]) => void) & ((evt: "update:expanded", value: T[]) => void)>>> & import("vue").PublicProps;
|
|
26
|
+
expose: (exposed: {}) => void;
|
|
27
|
+
attrs: any;
|
|
28
|
+
slots: {
|
|
29
|
+
default?: (props: {}) => any;
|
|
30
|
+
};
|
|
31
|
+
emit: ((evt: "update:tree", value: import("@nui/components").TreeItem<T>[]) => void) & ((evt: "update:active", value: T | null) => void) & ((evt: "update:selected", value: T[]) => void) & ((evt: "update:expanded", value: T[]) => void);
|
|
32
|
+
}>) => import("vue").VNode & {
|
|
33
|
+
__ctx?: Awaited<typeof __VLS_setup>;
|
|
34
|
+
};
|
|
35
|
+
declare const _default: typeof __VLS_export;
|
|
36
|
+
export default _default;
|
|
37
|
+
type __VLS_PrettifyLocal<T> = {
|
|
38
|
+
[K in keyof T as K]: T[K];
|
|
39
|
+
} & {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './model.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./model.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ButtonProps, TreeIconResolver, TreeItem } from '@nui/components';
|
|
2
|
+
import type { ModelRef } from 'vue';
|
|
3
|
+
type EventType = 'select' | 'expand';
|
|
4
|
+
type SelectMode = 'single' | 'multiple' | 'range';
|
|
5
|
+
export interface TreeContext<T extends string = string> {
|
|
6
|
+
tree: ModelRef<TreeItem<T>[]>;
|
|
7
|
+
active: ModelRef<T | null>;
|
|
8
|
+
selected: ModelRef<T[]>;
|
|
9
|
+
expanded: ModelRef<T[]>;
|
|
10
|
+
iconResolver: TreeIconResolver<T>;
|
|
11
|
+
selectable: boolean;
|
|
12
|
+
variant: ButtonProps['variant'];
|
|
13
|
+
color: ButtonProps['color'];
|
|
14
|
+
size: ButtonProps['size'];
|
|
15
|
+
}
|
|
16
|
+
export interface TreeState<T extends string = string> {
|
|
17
|
+
active: ModelRef<T | null>;
|
|
18
|
+
selected: ModelRef<T[]>;
|
|
19
|
+
expanded: ModelRef<T[]>;
|
|
20
|
+
iconResolver: TreeIconResolver<T>;
|
|
21
|
+
toggle: (type: EventType, value: T, mode?: SelectMode) => void;
|
|
22
|
+
on: ((type: 'expand', value: T) => void) & ((type: 'select', value: T, mode?: SelectMode) => void);
|
|
23
|
+
off: (type: EventType, value: T) => void;
|
|
24
|
+
setActive: (value: T | null) => void;
|
|
25
|
+
selectable: boolean;
|
|
26
|
+
variant: ButtonProps['variant'];
|
|
27
|
+
color: ButtonProps['color'];
|
|
28
|
+
size: ButtonProps['size'];
|
|
29
|
+
}
|
|
30
|
+
export declare function useProvideTreeState<T extends string = string>(ctx: TreeContext<T>): TreeState<T>;
|
|
31
|
+
export declare function useTreeState<T extends string = string>(): TreeState<T>;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createStrictInjection } from "@nui/helpers";
|
|
2
|
+
import { getBranchChildren, getTreeItemsBetween } from "@nui/utils";
|
|
3
|
+
const injectionKey = Symbol("nui-tree");
|
|
4
|
+
const [useProvide, useState] = createStrictInjection(({
|
|
5
|
+
tree,
|
|
6
|
+
active,
|
|
7
|
+
selected,
|
|
8
|
+
expanded,
|
|
9
|
+
iconResolver,
|
|
10
|
+
selectable,
|
|
11
|
+
...rest
|
|
12
|
+
}) => {
|
|
13
|
+
const setActive = (value) => active.value = value;
|
|
14
|
+
function on(type, value, mode) {
|
|
15
|
+
if (type === "select") {
|
|
16
|
+
setActive(value);
|
|
17
|
+
if (!selectable)
|
|
18
|
+
return;
|
|
19
|
+
switch (mode) {
|
|
20
|
+
case "single":
|
|
21
|
+
return selected.value = [value];
|
|
22
|
+
case "multiple": {
|
|
23
|
+
const exist = selected.value.includes(value);
|
|
24
|
+
if (!exist)
|
|
25
|
+
selected.value = [...selected.value, value];
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
case "range": {
|
|
29
|
+
if (!active.value || active.value === value)
|
|
30
|
+
return;
|
|
31
|
+
const range = getTreeItemsBetween(tree.value, active.value, value);
|
|
32
|
+
return selected.value = [.../* @__PURE__ */ new Set([...selected.value, ...range])];
|
|
33
|
+
}
|
|
34
|
+
default:
|
|
35
|
+
return selected.value = [value];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (type === "expand") {
|
|
39
|
+
const exist = expanded.value.includes(value);
|
|
40
|
+
if (!exist)
|
|
41
|
+
expanded.value = [...expanded.value, value];
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
return console.warn(`Unknown target type in NuiTree: ${type}`);
|
|
45
|
+
}
|
|
46
|
+
const off = (type, value) => {
|
|
47
|
+
switch (type) {
|
|
48
|
+
case "select": {
|
|
49
|
+
selected.value = selected.value.filter((i) => i !== value);
|
|
50
|
+
if (active.value === value)
|
|
51
|
+
active.value = selected.value[0] ?? null;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
case "expand": {
|
|
55
|
+
const children = new Set(getBranchChildren(tree.value, value));
|
|
56
|
+
return expanded.value = expanded.value.filter((v) => v !== value && !children.has(v));
|
|
57
|
+
}
|
|
58
|
+
default:
|
|
59
|
+
return console.warn(`Unknown target type in NuiTree: ${type}`);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const toggle = (type, value, mode = "single") => {
|
|
63
|
+
switch (type) {
|
|
64
|
+
case "select": {
|
|
65
|
+
const isSelected = selected.value.includes(value);
|
|
66
|
+
if (mode === "single")
|
|
67
|
+
return on(type, value, mode);
|
|
68
|
+
if (mode === "multiple")
|
|
69
|
+
return isSelected ? off(type, value) : on(type, value, mode);
|
|
70
|
+
if (mode === "range")
|
|
71
|
+
return on(type, value, mode);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
case "expand": {
|
|
75
|
+
const isExpanded = expanded.value.includes(value);
|
|
76
|
+
return isExpanded ? off(type, value) : on(type, value);
|
|
77
|
+
}
|
|
78
|
+
default:
|
|
79
|
+
console.warn(`Unknown target type in NuiTree: ${type}`);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
on,
|
|
84
|
+
off,
|
|
85
|
+
toggle,
|
|
86
|
+
setActive,
|
|
87
|
+
active,
|
|
88
|
+
selected,
|
|
89
|
+
expanded,
|
|
90
|
+
iconResolver,
|
|
91
|
+
selectable,
|
|
92
|
+
...rest
|
|
93
|
+
};
|
|
94
|
+
}, {
|
|
95
|
+
injectionKey,
|
|
96
|
+
name: "TreeState"
|
|
97
|
+
});
|
|
98
|
+
export function useProvideTreeState(ctx) {
|
|
99
|
+
return useProvide(ctx);
|
|
100
|
+
}
|
|
101
|
+
export function useTreeState() {
|
|
102
|
+
return useState();
|
|
103
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
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[];
|
|
@@ -0,0 +1,10 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { NuanceColor } from '@nui/types';
|
|
2
|
+
export interface TreeModels<T extends string = string> {
|
|
3
|
+
active: T | null;
|
|
4
|
+
tree: TreeItem<T>[];
|
|
5
|
+
selected: T[];
|
|
6
|
+
expanded: T[];
|
|
7
|
+
}
|
|
8
|
+
export interface TreeItem<T extends string = string> {
|
|
9
|
+
/** @IconifyIcon */
|
|
10
|
+
icon?: string;
|
|
11
|
+
/** Value given to this item */
|
|
12
|
+
value: T;
|
|
13
|
+
/** Item label */
|
|
14
|
+
label?: string;
|
|
15
|
+
/** @IconifyIcon */
|
|
16
|
+
trailingIcon?: string;
|
|
17
|
+
/** Item default expanded */
|
|
18
|
+
expanded?: boolean;
|
|
19
|
+
/** Item disabled state */
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
/** Slot name */
|
|
22
|
+
slot?: string;
|
|
23
|
+
/** Item children */
|
|
24
|
+
children?: TreeItem<T>[];
|
|
25
|
+
/** Fires when item is selected */
|
|
26
|
+
onSelect?: (item: TreeItem<T>) => void;
|
|
27
|
+
/** Fires when item is toggled */
|
|
28
|
+
onToggle?: (item: TreeItem<T>) => void;
|
|
29
|
+
}
|
|
30
|
+
export type TreeIconResolver<T extends string = string> = (item: TreeItem<T>) => {
|
|
31
|
+
icon: string;
|
|
32
|
+
color?: NuanceColor;
|
|
33
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TreeRootProps } from './_ui/tree-root.vue.js';
|
|
2
|
+
import type { TreeModels } from './model.js';
|
|
3
|
+
export interface TreeProps<T extends string = string> extends TreeRootProps<T> {
|
|
4
|
+
}
|
|
5
|
+
declare const __VLS_export: <T extends string = string>(__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<{
|
|
6
|
+
props: __VLS_PrettifyLocal<(TreeProps<T> & {
|
|
7
|
+
tree: TreeModels<T>["tree"];
|
|
8
|
+
active?: TreeModels<T>["active"];
|
|
9
|
+
selected?: TreeModels<T>["selected"];
|
|
10
|
+
expanded?: TreeModels<T>["expanded"];
|
|
11
|
+
}) & __VLS_EmitsToProps<__VLS_NormalizeEmits<((evt: "update:tree", value: import("./model.js").TreeItem<T>[]) => void) & ((evt: "update:active", value: T | null) => void) & ((evt: "update:selected", value: T[]) => void) & ((evt: "update:expanded", value: T[]) => void)>>> & import("vue").PublicProps;
|
|
12
|
+
expose: (exposed: {}) => void;
|
|
13
|
+
attrs: any;
|
|
14
|
+
slots: {};
|
|
15
|
+
emit: ((evt: "update:tree", value: import("./model.js").TreeItem<T>[]) => void) & ((evt: "update:active", value: T | null) => void) & ((evt: "update:selected", value: T[]) => void) & ((evt: "update:expanded", value: T[]) => void);
|
|
16
|
+
}>) => import("vue").VNode & {
|
|
17
|
+
__ctx?: Awaited<typeof __VLS_setup>;
|
|
18
|
+
};
|
|
19
|
+
declare const _default: typeof __VLS_export;
|
|
20
|
+
export default _default;
|
|
21
|
+
type __VLS_PrettifyLocal<T> = {
|
|
22
|
+
[K in keyof T as K]: T[K];
|
|
23
|
+
} & {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import UTreeItem from "./_ui/tree-item.vue";
|
|
3
|
+
import TreeRoot from "./_ui/tree-root.vue";
|
|
4
|
+
import { getExpandedItems } from "./lib/get-default";
|
|
5
|
+
const {
|
|
6
|
+
color,
|
|
7
|
+
variant = "subtle",
|
|
8
|
+
size = "compact-sm",
|
|
9
|
+
...props
|
|
10
|
+
} = defineProps({
|
|
11
|
+
loop: { type: Boolean, required: false },
|
|
12
|
+
orientation: { type: String, required: false },
|
|
13
|
+
attr: { type: String, required: false },
|
|
14
|
+
iconResolver: { type: Function, required: false },
|
|
15
|
+
removable: { type: Boolean, required: false },
|
|
16
|
+
selectable: { type: Boolean, required: false },
|
|
17
|
+
variant: { type: String, required: false },
|
|
18
|
+
color: { type: null, required: false },
|
|
19
|
+
size: { type: null, required: false }
|
|
20
|
+
});
|
|
21
|
+
const tree = defineModel("tree", { type: Array, ...{ required: true } });
|
|
22
|
+
const active = defineModel("active", { type: null, ...{ default: null } });
|
|
23
|
+
const selected = defineModel("selected", { type: Array, ...{ default: [] } });
|
|
24
|
+
const expanded = defineModel("expanded", { type: Array, ...{ default: [] } });
|
|
25
|
+
expanded.value = getExpandedItems(tree.value);
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<TreeRoot
|
|
30
|
+
v-bind='props'
|
|
31
|
+
v-model:tree='tree'
|
|
32
|
+
v-model:active='active'
|
|
33
|
+
v-model:selected='selected'
|
|
34
|
+
v-model:expanded='expanded'
|
|
35
|
+
:size
|
|
36
|
+
:color
|
|
37
|
+
:variant
|
|
38
|
+
>
|
|
39
|
+
<UTreeItem
|
|
40
|
+
v-for='item in tree'
|
|
41
|
+
:key='item.value'
|
|
42
|
+
:item
|
|
43
|
+
:level='1'
|
|
44
|
+
/>
|
|
45
|
+
</TreeRoot>
|
|
46
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TreeRootProps } from './_ui/tree-root.vue.js';
|
|
2
|
+
import type { TreeModels } from './model.js';
|
|
3
|
+
export interface TreeProps<T extends string = string> extends TreeRootProps<T> {
|
|
4
|
+
}
|
|
5
|
+
declare const __VLS_export: <T extends string = string>(__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<{
|
|
6
|
+
props: __VLS_PrettifyLocal<(TreeProps<T> & {
|
|
7
|
+
tree: TreeModels<T>["tree"];
|
|
8
|
+
active?: TreeModels<T>["active"];
|
|
9
|
+
selected?: TreeModels<T>["selected"];
|
|
10
|
+
expanded?: TreeModels<T>["expanded"];
|
|
11
|
+
}) & __VLS_EmitsToProps<__VLS_NormalizeEmits<((evt: "update:tree", value: import("./model.js").TreeItem<T>[]) => void) & ((evt: "update:active", value: T | null) => void) & ((evt: "update:selected", value: T[]) => void) & ((evt: "update:expanded", value: T[]) => void)>>> & import("vue").PublicProps;
|
|
12
|
+
expose: (exposed: {}) => void;
|
|
13
|
+
attrs: any;
|
|
14
|
+
slots: {};
|
|
15
|
+
emit: ((evt: "update:tree", value: import("./model.js").TreeItem<T>[]) => void) & ((evt: "update:active", value: T | null) => void) & ((evt: "update:selected", value: T[]) => void) & ((evt: "update:expanded", value: T[]) => void);
|
|
16
|
+
}>) => import("vue").VNode & {
|
|
17
|
+
__ctx?: Awaited<typeof __VLS_setup>;
|
|
18
|
+
};
|
|
19
|
+
declare const _default: typeof __VLS_export;
|
|
20
|
+
export default _default;
|
|
21
|
+
type __VLS_PrettifyLocal<T> = {
|
|
22
|
+
[K in keyof T as K]: T[K];
|
|
23
|
+
} & {};
|