nuance-ui 0.1.18 → 0.1.19

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 CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^4.0.0"
6
6
  },
7
- "version": "0.1.18",
7
+ "version": "0.1.19",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
@@ -3,5 +3,5 @@
3
3
  </template>
4
4
 
5
5
  <style module>
6
- .root{display:inline-block}.root,.root:after{height:var(--loader-size);width:var(--loader-size)}.root:after{animation:oval-loader-animation 1.2s linear infinite;border-color:var(--loader-color) var(--loader-color) var(--loader-color) transparent;border-radius:10000px;border-style:solid;border-width:calc(var(--loader-size)/8);content:"";display:block}@keyframes oval-loader-animation{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}
6
+ .root{display:inline-block}.root,.root:after{height:var(--loader-size);width:var(--loader-size)}.root:after{animation:oval-loader-animation 1.2s linear infinite;border-color:var(--loader-color) var(--loader-color) var(--loader-color) transparent;border-radius:10000px;border-style:solid;border-width:calc(var(--loader-size)/6);content:"";display:block}@keyframes oval-loader-animation{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}
7
7
  </style>
@@ -1,7 +1,7 @@
1
1
  import type { NuanceColor, NuanceSize } from '@nui/types';
2
2
  export type LoaderType = 'bars' | 'dots' | 'oval';
3
3
  export interface LoaderProps {
4
- size?: NuanceSize | string;
4
+ size?: NuanceSize | `compact-${NuanceSize}` | string;
5
5
  color?: NuanceColor | string;
6
6
  type?: LoaderType;
7
7
  }
@@ -5,12 +5,8 @@ import { computed } from "vue";
5
5
  import BarsLoader from "./_loaders/bars-loader.vue";
6
6
  import DotsLoader from "./_loaders/dots-loader.vue";
7
7
  import OvalLoader from "./_loaders/oval-loader.vue";
8
- const {
9
- size = "sm",
10
- color,
11
- type = "oval"
12
- } = defineProps({
13
- size: { type: String, required: false },
8
+ const { size, color, type = "oval" } = defineProps({
9
+ size: { type: null, required: false },
14
10
  color: { type: null, required: false },
15
11
  type: { type: String, required: false }
16
12
  });
@@ -21,8 +17,9 @@ const loaders = {
21
17
  };
22
18
  const style = computed(() => useStyleResolver((theme) => {
23
19
  const _color = parseThemeColor({ color, theme });
20
+ const _size = size?.includes("compact") ? size.replace("compact-", "") : size;
24
21
  return {
25
- "--loader-size": getSize(size, "loader-size"),
22
+ "--loader-size": getSize(_size, "loader-size"),
26
23
  "--loader-color": _color.value
27
24
  };
28
25
  }));
@@ -33,5 +30,5 @@ const style = computed(() => useStyleResolver((theme) => {
33
30
  </template>
34
31
 
35
32
  <style module>
36
- .root{--loader-size-xs:rem(18px);--loader-size-sm:rem(22px);--loader-size-md:rem(36px);--loader-size-lg:rem(44px);--loader-size-xl:rem(58px);--loader-size:var(--loader-size-md);--loader-color:var(--color-primary-filled)}
33
+ .root{--loader-size-xs:rem(18px);--loader-size-sm:rem(22px);--loader-size-md:rem(36px);--loader-size-lg:rem(44px);--loader-size-xl:rem(58px);--loader-size:var(--loader-size-sm);--loader-color:var(--color-primary-filled)}
37
34
  </style>
@@ -1,7 +1,7 @@
1
1
  import type { NuanceColor, NuanceSize } from '@nui/types';
2
2
  export type LoaderType = 'bars' | 'dots' | 'oval';
3
3
  export interface LoaderProps {
4
- size?: NuanceSize | string;
4
+ size?: NuanceSize | `compact-${NuanceSize}` | string;
5
5
  color?: NuanceColor | string;
6
6
  type?: LoaderType;
7
7
  }
@@ -1,19 +1,7 @@
1
1
  import type { TreeItem } from '../model.js';
2
- export interface TreeItemProps<T extends string = string> {
3
- item: TreeItem<T>;
2
+ export interface TreeItemProps extends TreeItem {
4
3
  level: number;
5
4
  }
6
- 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<{
7
- props: __VLS_PrettifyLocal<TreeItemProps<T>> & import("vue").PublicProps;
8
- expose: (exposed: {}) => void;
9
- attrs: any;
10
- slots: {};
11
- emit: {};
12
- }>) => import("vue").VNode & {
13
- __ctx?: Awaited<typeof __VLS_setup>;
14
- };
5
+ declare const __VLS_export: import("vue").DefineComponent<TreeItemProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<TreeItemProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
6
  declare const _default: typeof __VLS_export;
16
7
  export default _default;
17
- type __VLS_PrettifyLocal<T> = {
18
- [K in keyof T as K]: T[K];
19
- } & {};
@@ -1,79 +1,54 @@
1
1
  <script setup>
2
2
  import { useTheme } from "@nui/composals";
3
- import { getThemeColor, isFalsy } from "@nui/utils";
4
- import { computed } from "vue";
3
+ import { getThemeColor } from "@nui/utils";
4
+ import { computed, watch } from "vue";
5
5
  import Button from "../../button/button.vue";
6
- import { useRovingFocus } from "../../roving-focus";
6
+ import Loader from "../../loader/loader.vue";
7
7
  import RovingFocusItem from "../../roving-focus/roving-focus-item.vue";
8
+ import UTransition from "../../transition/transition.vue";
8
9
  import { useTreeState } from "../lib/context";
9
- const { item, level } = defineProps({
10
- item: { type: Object, required: true },
11
- level: { type: Number, required: true }
12
- });
10
+ import { useTreeItemHandlers } from "../lib/item-handlers";
13
11
  const {
12
+ type = "file",
14
13
  icon = "gravity-ui:folder",
15
14
  trailingIcon = "gravity-ui:folder-open",
16
- value,
17
- label,
18
- children,
15
+ path,
16
+ name,
17
+ level,
19
18
  disabled
20
- } = item;
19
+ } = defineProps({
20
+ level: { type: Number, required: true },
21
+ icon: { type: String, required: false },
22
+ path: { type: String, required: true },
23
+ name: { type: String, required: false },
24
+ trailingIcon: { type: String, required: false },
25
+ disabled: { type: Boolean, required: false },
26
+ type: { type: String, required: false },
27
+ children: { type: Array, required: false }
28
+ });
21
29
  const { value: theme } = useTheme();
22
- const isFolder = computed(() => !isFalsy(children));
30
+ const isFolder = computed(() => type === "directory");
23
31
  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");
32
+ const selected = computed(() => ctx.selected.value.includes(path));
33
+ const expanded = computed(() => ctx.expanded.value.includes(path));
34
+ const active = computed(() => ctx.active.value === path);
35
+ const { data, pending, execute } = ctx.loadBranch(path);
36
+ watch(expanded, (expanded2) => {
37
+ if (expanded2) {
38
+ try {
39
+ execute();
40
+ } catch (e) {
41
+ console.error(e);
42
+ ctx.off("expand", path);
70
43
  }
71
44
  }
72
- }
45
+ }, { immediate: true });
46
+ const { icon: fileIcon, color } = ctx.iconResolver(type, name, path, disabled);
47
+ const { handleClick, handleKeyDown } = useTreeItemHandlers(path, isFolder, expanded);
73
48
  </script>
74
49
 
75
50
  <template>
76
- <li :class='$style.root' role='presentation'>
51
+ <li :class='$style.item' role='presentation'>
77
52
  <RovingFocusItem>
78
53
  <Button
79
54
  :size='ctx.size'
@@ -81,55 +56,80 @@ function handleKeyDown(event) {
81
56
  :variant='ctx.variant'
82
57
  :disabled
83
58
  role='treeitem'
84
- :classes='{
85
- root: $style.button,
86
- label: $style.label,
87
- inner: $style.inner,
88
- section: $style.section
89
- }'
59
+ :classes='$style'
90
60
  :aria-level='level'
91
61
  :aria-selected='selected'
92
- :mod='{ active, selected, level }'
62
+ :mod='{ active, selected, "tree-item": path }'
93
63
  @click.prevent='handleClick'
94
64
  @keydown.prevent='handleKeyDown'
95
65
  >
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
- />
66
+ <template #leftSection>
67
+ <template v-if='pending'>
68
+ <Loader :class='$style.icon' />
69
+ </template>
70
+
71
+ <template v-else-if='isFolder'>
72
+ <Icon v-if='expanded' :class='$style.icon' :name='trailingIcon' />
73
+ <Icon v-else :class='$style.icon' :name='icon' />
74
+ </template>
75
+
76
+ <template v-else>
77
+ <Icon
78
+ :class='$style.icon'
79
+ :name='fileIcon'
80
+ :style='{ color: color && getThemeColor(color, theme) }'
81
+ />
82
+ </template>
106
83
  </template>
107
- {{ label ?? value }}
84
+
85
+ {{ name ?? path }}
108
86
  </Button>
109
87
  </RovingFocusItem>
110
88
 
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>
89
+ <UTransition name='scale-y'>
90
+ <ul
91
+ v-if='expanded && data && data.length > 0'
92
+ :class='$style.list'
93
+ role='group'
94
+ >
95
+ <TreeItem
96
+ v-for='child in data'
97
+ :key='child.path'
98
+ v-bind='child'
99
+ :path='child.path'
100
+ :level='level + 1'
101
+ />
102
+ </ul>
103
+ </UTransition>
123
104
  </li>
124
105
  </template>
125
106
 
126
107
  <style module lang="postcss">
127
- .root {
108
+ .item {
128
109
  display: grid;
129
110
  gap: .25rem;
130
111
  }
131
112
 
132
- .button {
113
+ .icon {
114
+ --loader-size: var(--tree-icon-size);
115
+
116
+ width: var(--tree-icon-size);
117
+ height: var(--tree-icon-size);
118
+ }
119
+
120
+ .list {
121
+ display: grid;
122
+ gap: .25rem;
123
+
124
+ margin-inline-start: 1rem;
125
+
126
+ padding-inline-start: .75rem;
127
+ border-left: 1px solid var(--color-gray-4);
128
+
129
+ list-style: none;
130
+ }
131
+
132
+ .root {
133
133
  .inner {
134
134
  display: grid;
135
135
  grid-template-columns: auto 1fr auto;
@@ -152,21 +152,4 @@ function handleKeyDown(event) {
152
152
  background: alpha(var(--button-color), .1);
153
153
  }
154
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
155
  </style>
@@ -1,19 +1,7 @@
1
1
  import type { TreeItem } from '../model.js';
2
- export interface TreeItemProps<T extends string = string> {
3
- item: TreeItem<T>;
2
+ export interface TreeItemProps extends TreeItem {
4
3
  level: number;
5
4
  }
6
- 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<{
7
- props: __VLS_PrettifyLocal<TreeItemProps<T>> & import("vue").PublicProps;
8
- expose: (exposed: {}) => void;
9
- attrs: any;
10
- slots: {};
11
- emit: {};
12
- }>) => import("vue").VNode & {
13
- __ctx?: Awaited<typeof __VLS_setup>;
14
- };
5
+ declare const __VLS_export: import("vue").DefineComponent<TreeItemProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<TreeItemProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
6
  declare const _default: typeof __VLS_export;
16
7
  export default _default;
17
- type __VLS_PrettifyLocal<T> = {
18
- [K in keyof T as K]: T[K];
19
- } & {};
@@ -1,44 +1,42 @@
1
1
  import type { ButtonProps } from '@nui/components';
2
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>;
3
+ import type { TreeIconResolver, TreeLoader, TreeModels } from '../model.js';
4
+ export type TreeRootProps = RovingFocusProps & {
5
+ iconResolver?: TreeIconResolver;
6
6
  removable?: boolean;
7
7
  selectable?: boolean;
8
+ loadBranch: TreeLoader;
8
9
  variant?: ButtonProps['variant'];
9
10
  color?: ButtonProps['color'];
10
11
  size?: ButtonProps['size'];
11
12
  };
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
- }) & {
26
- "onUpdate:tree"?: ((value: import("@nui/components").TreeItem<T>[]) => any) | undefined;
27
- "onUpdate:active"?: ((value: T | null) => any) | undefined;
28
- "onUpdate:selected"?: ((value: T[]) => any) | undefined;
29
- "onUpdate:expanded"?: ((value: T[]) => any) | undefined;
30
- }> & import("vue").PublicProps;
31
- expose: (exposed: {}) => void;
32
- attrs: any;
33
- slots: {
34
- default?: (props: {}) => any;
35
- };
36
- 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);
37
- }>) => import("vue").VNode & {
38
- __ctx?: Awaited<typeof __VLS_setup>;
13
+ type __VLS_Props = TreeRootProps;
14
+ type __VLS_ModelProps = {
15
+ 'active'?: TreeModels['active'];
16
+ 'selected'?: TreeModels['selected'];
17
+ 'expanded'?: TreeModels['expanded'];
18
+ };
19
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
20
+ declare var __VLS_15: {};
21
+ type __VLS_Slots = {} & {
22
+ default?: (props: typeof __VLS_15) => any;
39
23
  };
24
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
25
+ delete: (path: string[]) => any;
26
+ "update:active": (value: string | null) => any;
27
+ "update:selected": (value: string[]) => any;
28
+ "update:expanded": (value: string[]) => any;
29
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
30
+ onDelete?: ((path: string[]) => any) | undefined;
31
+ "onUpdate:active"?: ((value: string | null) => any) | undefined;
32
+ "onUpdate:selected"?: ((value: string[]) => any) | undefined;
33
+ "onUpdate:expanded"?: ((value: string[]) => any) | undefined;
34
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
40
36
  declare const _default: typeof __VLS_export;
41
37
  export default _default;
42
- type __VLS_PrettifyLocal<T> = {
43
- [K in keyof T as K]: T[K];
44
- } & {};
38
+ type __VLS_WithSlots<T, S> = T & {
39
+ new (): {
40
+ $slots: S;
41
+ };
42
+ };
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import { useStyleResolver } from "@nui/composals";
3
- import { getSize, removeTreeNodes } from "@nui/utils";
3
+ import { getSize } from "@nui/utils";
4
4
  import { onClickOutside, useEventListener } from "@vueuse/core";
5
5
  import { useTemplateRef } from "vue";
6
6
  import Box from "../../box.vue";
@@ -15,7 +15,8 @@ const {
15
15
  size = "compact-sm",
16
16
  iconResolver = () => ({ icon: "gravity-ui:file" }),
17
17
  removable = false,
18
- selectable = false
18
+ selectable = false,
19
+ loadBranch
19
20
  } = defineProps({
20
21
  loop: { type: Boolean, required: false },
21
22
  orientation: { type: String, required: false },
@@ -23,12 +24,13 @@ const {
23
24
  iconResolver: { type: Function, required: false },
24
25
  removable: { type: Boolean, required: false },
25
26
  selectable: { type: Boolean, required: false },
27
+ loadBranch: { type: Function, required: true },
26
28
  variant: { type: String, required: false },
27
29
  color: { type: null, required: false },
28
30
  size: { type: null, required: false }
29
31
  });
30
- const tree = defineModel("tree", { type: Array, ...{ required: true } });
31
- const active = defineModel("active", { type: null, ...{ default: null } });
32
+ const emit = defineEmits(["delete"]);
33
+ const active = defineModel("active", { type: [String, null], ...{ default: null } });
32
34
  const selected = defineModel("selected", { type: Array, ...{ default: [] } });
33
35
  const expanded = defineModel("expanded", { type: Array, ...{ default: [] } });
34
36
  const style = useStyleResolver(() => ({
@@ -37,7 +39,7 @@ const style = useStyleResolver(() => ({
37
39
  const root = useTemplateRef("parent");
38
40
  onClickOutside(root, () => selected.value = []);
39
41
  useProvideTreeState({
40
- tree,
42
+ root,
41
43
  active,
42
44
  selected,
43
45
  expanded,
@@ -45,13 +47,14 @@ useProvideTreeState({
45
47
  size,
46
48
  color,
47
49
  variant,
48
- selectable
50
+ selectable,
51
+ loadBranch
49
52
  });
50
53
  if (removable) {
51
54
  useEventListener(root, "keydown", (event) => {
52
55
  if (event.key === "Delete") {
53
56
  event.preventDefault();
54
- return tree.value = removeTreeNodes(tree.value, selected.value);
57
+ emit("delete", selected.value);
55
58
  }
56
59
  });
57
60
  }
@@ -65,7 +68,7 @@ if (removable) {
65
68
  role='tree'
66
69
  :style
67
70
  :class='$style.root'
68
- @keydown.esc.prevent='selected.value = []'
71
+ @keydown.esc.prevent='selected = []'
69
72
  >
70
73
  <slot />
71
74
  </Box>
@@ -1,44 +1,42 @@
1
1
  import type { ButtonProps } from '@nui/components';
2
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>;
3
+ import type { TreeIconResolver, TreeLoader, TreeModels } from '../model.js';
4
+ export type TreeRootProps = RovingFocusProps & {
5
+ iconResolver?: TreeIconResolver;
6
6
  removable?: boolean;
7
7
  selectable?: boolean;
8
+ loadBranch: TreeLoader;
8
9
  variant?: ButtonProps['variant'];
9
10
  color?: ButtonProps['color'];
10
11
  size?: ButtonProps['size'];
11
12
  };
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
- }) & {
26
- "onUpdate:tree"?: ((value: import("@nui/components").TreeItem<T>[]) => any) | undefined;
27
- "onUpdate:active"?: ((value: T | null) => any) | undefined;
28
- "onUpdate:selected"?: ((value: T[]) => any) | undefined;
29
- "onUpdate:expanded"?: ((value: T[]) => any) | undefined;
30
- }> & import("vue").PublicProps;
31
- expose: (exposed: {}) => void;
32
- attrs: any;
33
- slots: {
34
- default?: (props: {}) => any;
35
- };
36
- 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);
37
- }>) => import("vue").VNode & {
38
- __ctx?: Awaited<typeof __VLS_setup>;
13
+ type __VLS_Props = TreeRootProps;
14
+ type __VLS_ModelProps = {
15
+ 'active'?: TreeModels['active'];
16
+ 'selected'?: TreeModels['selected'];
17
+ 'expanded'?: TreeModels['expanded'];
18
+ };
19
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
20
+ declare var __VLS_15: {};
21
+ type __VLS_Slots = {} & {
22
+ default?: (props: typeof __VLS_15) => any;
39
23
  };
24
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
25
+ delete: (path: string[]) => any;
26
+ "update:active": (value: string | null) => any;
27
+ "update:selected": (value: string[]) => any;
28
+ "update:expanded": (value: string[]) => any;
29
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
30
+ onDelete?: ((path: string[]) => any) | undefined;
31
+ "onUpdate:active"?: ((value: string | null) => any) | undefined;
32
+ "onUpdate:selected"?: ((value: string[]) => any) | undefined;
33
+ "onUpdate:expanded"?: ((value: string[]) => any) | undefined;
34
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
40
36
  declare const _default: typeof __VLS_export;
41
37
  export default _default;
42
- type __VLS_PrettifyLocal<T> = {
43
- [K in keyof T as K]: T[K];
44
- } & {};
38
+ type __VLS_WithSlots<T, S> = T & {
39
+ new (): {
40
+ $slots: S;
41
+ };
42
+ };
@@ -1,32 +1,26 @@
1
- import type { ButtonProps, TreeIconResolver, TreeItem } from '@nui/components';
2
- import type { ModelRef } from 'vue';
1
+ import type { ButtonProps } from '@nui/components';
2
+ import type { ModelRef, ShallowRef } from 'vue';
3
+ import type { TreeIconResolver, TreeLoader } from '../model.js';
3
4
  type EventType = 'select' | 'expand';
4
5
  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>;
6
+ export interface TreeContext {
7
+ root: ShallowRef<HTMLUListElement | null>;
8
+ active: ModelRef<string | null>;
9
+ selected: ModelRef<string[]>;
10
+ expanded: ModelRef<string[]>;
11
+ iconResolver: TreeIconResolver;
12
+ loadBranch: TreeLoader;
11
13
  selectable: boolean;
12
14
  variant: ButtonProps['variant'];
13
15
  color: ButtonProps['color'];
14
16
  size: ButtonProps['size'];
15
17
  }
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'];
18
+ export interface TreeState extends Omit<TreeContext, 'root'> {
19
+ toggle: (type: EventType, path: string, mode?: SelectMode) => void;
20
+ on: ((type: 'expand', path: string) => void) & ((type: 'select', path: string, mode?: SelectMode) => void);
21
+ off: (type: EventType, path: string) => void;
22
+ setActive: (path: string | null) => void;
29
23
  }
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>;
24
+ export declare const useProvideTreeState: (args_0: TreeContext) => TreeState;
25
+ export declare const useTreeState: () => TreeState;
32
26
  export {};
@@ -1,8 +1,8 @@
1
1
  import { createStrictInjection } from "@nui/helpers";
2
- import { getBranchChildren, getTreeItemsBetween } from "@nui/utils";
2
+ import { unrefElement } from "@vueuse/core";
3
3
  const injectionKey = Symbol("nui-tree");
4
4
  const [useProvide, useState] = createStrictInjection(({
5
- tree,
5
+ root,
6
6
  active,
7
7
  selected,
8
8
  expanded,
@@ -11,70 +11,82 @@ const [useProvide, useState] = createStrictInjection(({
11
11
  ...rest
12
12
  }) => {
13
13
  const setActive = (value) => active.value = value;
14
- function on(type, value, mode) {
14
+ function on(type, path, mode) {
15
15
  if (type === "select") {
16
- setActive(value);
16
+ setActive(path);
17
17
  if (!selectable)
18
18
  return;
19
19
  switch (mode) {
20
20
  case "single":
21
- return selected.value = [value];
21
+ return selected.value = [path];
22
22
  case "multiple": {
23
- const exist = selected.value.includes(value);
23
+ const exist = selected.value.includes(path);
24
24
  if (!exist)
25
- selected.value = [...selected.value, value];
25
+ selected.value = [...selected.value, path];
26
26
  return;
27
27
  }
28
28
  case "range": {
29
- if (!active.value || active.value === value)
29
+ if (!active.value || active.value === path || !root.value)
30
30
  return;
31
- const range = getTreeItemsBetween(tree.value, active.value, value);
32
- return selected.value = [.../* @__PURE__ */ new Set([...selected.value, ...range])];
31
+ const elements = unrefElement(root)?.querySelectorAll("[data-tree-item]");
32
+ if (!elements)
33
+ return;
34
+ const newSelected = /* @__PURE__ */ new Set();
35
+ let startIx = -1;
36
+ for (const [ix, elem] of elements.entries()) {
37
+ const elemPath = elem.getAttribute("data-tree-item");
38
+ if (!elemPath)
39
+ continue;
40
+ const isBoundary = elemPath === active.value || elemPath === path;
41
+ if (isBoundary || startIx >= 0)
42
+ newSelected.add(elemPath);
43
+ if (isBoundary) {
44
+ if (startIx >= 0)
45
+ break;
46
+ startIx = ix;
47
+ }
48
+ }
49
+ return selected.value = [...newSelected];
33
50
  }
34
51
  default:
35
- return selected.value = [value];
52
+ return selected.value = [path];
36
53
  }
37
54
  }
38
55
  if (type === "expand") {
39
- const exist = expanded.value.includes(value);
40
- if (!exist)
41
- expanded.value = [...expanded.value, value];
56
+ if (!expanded.value.includes(path))
57
+ expanded.value = [...expanded.value, path];
42
58
  return;
43
59
  }
44
60
  return console.warn(`Unknown target type in NuiTree: ${type}`);
45
61
  }
46
- const off = (type, value) => {
62
+ const off = (type, path) => {
47
63
  switch (type) {
48
64
  case "select": {
49
- selected.value = selected.value.filter((i) => i !== value);
50
- if (active.value === value)
65
+ selected.value = selected.value.filter((i) => i !== path);
66
+ if (active.value === path)
51
67
  active.value = selected.value[0] ?? null;
52
68
  return;
53
69
  }
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
- }
70
+ case "expand":
71
+ return expanded.value = expanded.value.filter((v) => !v.startsWith(path));
58
72
  default:
59
73
  return console.warn(`Unknown target type in NuiTree: ${type}`);
60
74
  }
61
75
  };
62
- const toggle = (type, value, mode = "single") => {
76
+ const toggle = (type, path, mode = "single") => {
63
77
  switch (type) {
64
78
  case "select": {
65
- const isSelected = selected.value.includes(value);
79
+ const isSelected = selected.value.includes(path);
66
80
  if (mode === "single")
67
- return on(type, value, mode);
81
+ return on(type, path, mode);
68
82
  if (mode === "multiple")
69
- return isSelected ? off(type, value) : on(type, value, mode);
83
+ return isSelected ? off(type, path) : on(type, path, mode);
70
84
  if (mode === "range")
71
- return on(type, value, mode);
85
+ return on(type, path, mode);
72
86
  return;
73
87
  }
74
- case "expand": {
75
- const isExpanded = expanded.value.includes(value);
76
- return isExpanded ? off(type, value) : on(type, value);
77
- }
88
+ case "expand":
89
+ return expanded.value.includes(path) ? off(type, path) : on(type, path);
78
90
  default:
79
91
  console.warn(`Unknown target type in NuiTree: ${type}`);
80
92
  }
@@ -95,9 +107,5 @@ const [useProvide, useState] = createStrictInjection(({
95
107
  injectionKey,
96
108
  name: "TreeState"
97
109
  });
98
- export function useProvideTreeState(ctx) {
99
- return useProvide(ctx);
100
- }
101
- export function useTreeState() {
102
- return useState();
103
- }
110
+ export const useProvideTreeState = useProvide;
111
+ export const useTreeState = useState;
@@ -0,0 +1,5 @@
1
+ import type { Ref } from 'vue';
2
+ export declare function useTreeItemHandlers(path: string, isFolder: Ref<boolean>, expanded: Ref<boolean>): {
3
+ handleClick: (event: MouseEvent) => void;
4
+ handleKeyDown: (event: KeyboardEvent) => void;
5
+ };
@@ -0,0 +1,54 @@
1
+ import { useRovingFocus } from "@nui/components";
2
+ import { useTreeState } from "./context.js";
3
+ export function useTreeItemHandlers(path, isFolder, expanded) {
4
+ const ctx = useTreeState();
5
+ const { focus } = useRovingFocus();
6
+ function handleClick(event) {
7
+ if (event.shiftKey)
8
+ ctx.toggle("select", path, "range");
9
+ else if (event.ctrlKey || event.metaKey)
10
+ ctx.toggle("select", path, "multiple");
11
+ else
12
+ ctx.toggle("select", path, "single");
13
+ if (isFolder.value && !event.ctrlKey && !event.metaKey && !event.shiftKey)
14
+ ctx.toggle("expand", path);
15
+ }
16
+ function handleKeyDown(event) {
17
+ switch (event.key) {
18
+ // Arrow Left - закрыть папку или перейти к родителю
19
+ case "ArrowLeft": {
20
+ event.preventDefault();
21
+ if (isFolder.value && expanded.value)
22
+ return ctx.off("expand", path);
23
+ else
24
+ return focus("prev", event.currentTarget);
25
+ }
26
+ // Arrow Right - открыть папку или перейти к первому ребенку
27
+ case "ArrowRight": {
28
+ event.preventDefault();
29
+ if (isFolder.value && !expanded.value)
30
+ return ctx.on("expand", path);
31
+ else if (expanded.value)
32
+ return focus("next", event.currentTarget);
33
+ break;
34
+ }
35
+ // Enter/Space - выбор элемента
36
+ case "Enter": {
37
+ ctx.on("select", path);
38
+ return ctx.setActive(path);
39
+ }
40
+ case " ": {
41
+ event.preventDefault();
42
+ if (event.shiftKey)
43
+ return ctx.toggle("select", path, "range");
44
+ else if (event.ctrlKey || event.metaKey)
45
+ return ctx.toggle("select", path, "multiple");
46
+ return ctx.toggle("select", path, "single");
47
+ }
48
+ }
49
+ }
50
+ return {
51
+ handleClick,
52
+ handleKeyDown
53
+ };
54
+ }
@@ -1,33 +1,39 @@
1
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[];
2
+ import type { AsyncData } from '#app';
3
+ export interface TreeModels {
4
+ active: string | null;
5
+ tree: TreeItem[];
6
+ selected: string[];
7
+ expanded: string[];
7
8
  }
8
- export interface TreeItem<T extends string = string> {
9
+ export interface TreeEmits {
10
+ delete: [path: string[]];
11
+ }
12
+ /**
13
+ * Required pass instance of `useFetch`/`useAsyncData` with `{ immediate: false }`
14
+ * Root path will be queried immediate with path `/`
15
+ */
16
+ export type TreeLoader = (path: string) => AsyncData<TreeItem[], unknown>;
17
+ export type TreeItemType = 'file' | 'directory';
18
+ export interface TreeItem {
9
19
  /** @IconifyIcon */
10
20
  icon?: string;
11
- /** Value given to this item */
12
- value: T;
13
- /** Item label */
14
- label?: string;
21
+ /** Path given to this item */
22
+ path: string;
23
+ /** Item name */
24
+ name?: string;
15
25
  /** @IconifyIcon */
16
26
  trailingIcon?: string;
17
- /** Item default expanded */
18
- expanded?: boolean;
19
27
  /** Item disabled state */
20
28
  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
+ * Type of item
31
+ * @default `file`
32
+ */
33
+ type?: TreeItemType;
34
+ children?: TreeItem[];
29
35
  }
30
- export type TreeIconResolver<T extends string = string> = (item: TreeItem<T>) => {
36
+ export type TreeIconResolver = (type: TreeItemType, name?: string, path?: string, disabled?: boolean) => {
31
37
  icon: string;
32
38
  color?: NuanceColor;
33
39
  };
@@ -1,28 +1,24 @@
1
1
  import type { TreeRootProps } from './_ui/tree-root.vue.js';
2
2
  import type { TreeModels } from './model.js';
3
- export interface TreeProps<T extends string = string> extends TreeRootProps<T> {
3
+ export interface TreeProps extends TreeRootProps {
4
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
- }) & {
12
- "onUpdate:tree"?: ((value: import("./model.js").TreeItem<T>[]) => any) | undefined;
13
- "onUpdate:active"?: ((value: T | null) => any) | undefined;
14
- "onUpdate:selected"?: ((value: T[]) => any) | undefined;
15
- "onUpdate:expanded"?: ((value: T[]) => any) | undefined;
16
- }> & import("vue").PublicProps;
17
- expose: (exposed: {}) => void;
18
- attrs: any;
19
- slots: {};
20
- 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);
21
- }>) => import("vue").VNode & {
22
- __ctx?: Awaited<typeof __VLS_setup>;
5
+ type __VLS_Props = TreeProps;
6
+ type __VLS_ModelProps = {
7
+ 'active'?: TreeModels['active'];
8
+ 'selected'?: TreeModels['selected'];
9
+ 'expanded'?: TreeModels['expanded'];
23
10
  };
11
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
12
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
13
+ delete: (path: string[]) => any;
14
+ "update:active": (value: string | null) => any;
15
+ "update:selected": (value: string[]) => any;
16
+ "update:expanded": (value: string[]) => any;
17
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
18
+ onDelete?: ((path: string[]) => any) | undefined;
19
+ "onUpdate:active"?: ((value: string | null) => any) | undefined;
20
+ "onUpdate:selected"?: ((value: string[]) => any) | undefined;
21
+ "onUpdate:expanded"?: ((value: string[]) => any) | undefined;
22
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
23
  declare const _default: typeof __VLS_export;
25
24
  export default _default;
26
- type __VLS_PrettifyLocal<T> = {
27
- [K in keyof T as K]: T[K];
28
- } & {};
@@ -1,11 +1,12 @@
1
1
  <script setup>
2
+ import { onMounted } from "vue";
2
3
  import UTreeItem from "./_ui/tree-item.vue";
3
4
  import TreeRoot from "./_ui/tree-root.vue";
4
- import { getExpandedItems } from "./lib/get-default";
5
5
  const {
6
6
  color,
7
7
  variant = "subtle",
8
8
  size = "compact-sm",
9
+ loadBranch,
9
10
  ...props
10
11
  } = defineProps({
11
12
  loop: { type: Boolean, required: false },
@@ -14,32 +15,36 @@ const {
14
15
  iconResolver: { type: Function, required: false },
15
16
  removable: { type: Boolean, required: false },
16
17
  selectable: { type: Boolean, required: false },
18
+ loadBranch: { type: Function, required: true },
17
19
  variant: { type: String, required: false },
18
20
  color: { type: null, required: false },
19
21
  size: { type: null, required: false }
20
22
  });
21
- const tree = defineModel("tree", { type: Array, ...{ required: true } });
22
- const active = defineModel("active", { type: null, ...{ default: null } });
23
+ defineEmits(["delete"]);
24
+ const active = defineModel("active", { type: [String, null], ...{ default: null } });
23
25
  const selected = defineModel("selected", { type: Array, ...{ default: [] } });
24
26
  const expanded = defineModel("expanded", { type: Array, ...{ default: [] } });
25
- expanded.value = getExpandedItems(tree.value);
27
+ const { data: root, execute } = loadBranch("/");
28
+ onMounted(execute);
26
29
  </script>
27
30
 
28
31
  <template>
29
32
  <TreeRoot
30
33
  v-bind='props'
31
- v-model:tree='tree'
32
34
  v-model:active='active'
33
35
  v-model:selected='selected'
34
36
  v-model:expanded='expanded'
37
+ :load-branch
35
38
  :size
36
39
  :color
37
40
  :variant
41
+ @delete='(path) => $emit("delete", path)'
38
42
  >
39
43
  <UTreeItem
40
- v-for='item in tree'
41
- :key='item.value'
42
- :item
44
+ v-for='item in root'
45
+ :key='item.path'
46
+ v-bind='item'
47
+ :path='item.path'
43
48
  :level='1'
44
49
  />
45
50
  </TreeRoot>
@@ -1,28 +1,24 @@
1
1
  import type { TreeRootProps } from './_ui/tree-root.vue.js';
2
2
  import type { TreeModels } from './model.js';
3
- export interface TreeProps<T extends string = string> extends TreeRootProps<T> {
3
+ export interface TreeProps extends TreeRootProps {
4
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
- }) & {
12
- "onUpdate:tree"?: ((value: import("./model.js").TreeItem<T>[]) => any) | undefined;
13
- "onUpdate:active"?: ((value: T | null) => any) | undefined;
14
- "onUpdate:selected"?: ((value: T[]) => any) | undefined;
15
- "onUpdate:expanded"?: ((value: T[]) => any) | undefined;
16
- }> & import("vue").PublicProps;
17
- expose: (exposed: {}) => void;
18
- attrs: any;
19
- slots: {};
20
- 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);
21
- }>) => import("vue").VNode & {
22
- __ctx?: Awaited<typeof __VLS_setup>;
5
+ type __VLS_Props = TreeProps;
6
+ type __VLS_ModelProps = {
7
+ 'active'?: TreeModels['active'];
8
+ 'selected'?: TreeModels['selected'];
9
+ 'expanded'?: TreeModels['expanded'];
23
10
  };
11
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
12
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
13
+ delete: (path: string[]) => any;
14
+ "update:active": (value: string | null) => any;
15
+ "update:selected": (value: string[]) => any;
16
+ "update:expanded": (value: string[]) => any;
17
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
18
+ onDelete?: ((path: string[]) => any) | undefined;
19
+ "onUpdate:active"?: ((value: string | null) => any) | undefined;
20
+ "onUpdate:selected"?: ((value: string[]) => any) | undefined;
21
+ "onUpdate:expanded"?: ((value: string[]) => any) | undefined;
22
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
23
  declare const _default: typeof __VLS_export;
25
24
  export default _default;
26
- type __VLS_PrettifyLocal<T> = {
27
- [K in keyof T as K]: T[K];
28
- } & {};
@@ -1,7 +1,7 @@
1
1
  /** Represents a tree node with a value and optional children. */
2
2
  export interface TreeNode<T extends string = string> {
3
3
  /** The value stored in this tree node */
4
- value: string;
4
+ path: string;
5
5
  /** Optional array of child nodes */
6
6
  children?: TreeNode<T>[];
7
7
  }
@@ -28,14 +28,14 @@ export declare function filterTree<Node extends TreeNode = TreeNode>(tree: Node[
28
28
  * Searches for a tree item by its value using depth-first search.
29
29
  * @template T - The type of node values
30
30
  * @param {TreeNode<T>[]} items - The array of tree nodes to search in
31
- * @param {T} value - The value to search for
31
+ * @param {T} path - The value to search for
32
32
  * @returns {TreeNode<T> | null} The found node or null if not found
33
33
  * @example
34
34
  * const tree = [{ value: 'folder', children: [{ value: 'file' }] }]
35
35
  * findTreeItem(tree, 'file') // { value: 'file' }
36
36
  * findTreeItem(tree, 'missing') // null
37
37
  */
38
- export declare function findTreeItem<T extends string = string>(items: TreeNode<T>[], value: T): TreeNode<T> | null;
38
+ export declare function findTreeItem<T extends string = string>(items: TreeNode<T>[], path: T): TreeNode<T> | null;
39
39
  /**
40
40
  * Flattens a tree structure into a single-level array in depth-first order.
41
41
  * @template T - The type of node values
@@ -68,7 +68,7 @@ export declare function flatTree<T extends string = string>(tree: TreeNode<T>[])
68
68
  * getBranchChildren(tree, 'folder') // ['file1', 'subfolder', 'file2']
69
69
  * getBranchChildren(tree, 'file1') // []
70
70
  */
71
- export declare function getBranchChildren<T extends string = string>(tree: TreeNode<T>[], value: T): T[];
71
+ export declare function getBranchChildren<T extends string = string>(tree: TreeNode<T>[], path: T): T[];
72
72
  /**
73
73
  * Gets all node values between two specified values (inclusive) in tree traversal order.
74
74
  * If start comes after end in traversal order, the range is automatically reversed.
@@ -92,7 +92,7 @@ export declare function getTreeItemsBetween<T extends string = string>(tree: Tre
92
92
  * Removes nodes with specified values from the tree, including their subtrees.
93
93
  * Returns a new tree without modifying the original.
94
94
  *
95
- * @template T - The type of node values
95
+ * @template T - The type of node path
96
96
  * @param {TreeNode<T>[]} tree - The original tree (array of root nodes)
97
97
  * @param {T[]} valuesToRemove - Array of values to remove
98
98
  * @returns {TreeNode<T>[]} New tree with specified nodes and their subtrees removed
@@ -104,4 +104,4 @@ export declare function getTreeItemsBetween<T extends string = string>(tree: Tre
104
104
  * removeTreeNodes(tree, ['b', 'd']) // [{ value: 'a', children: [{ value: 'c' }] }]
105
105
  * removeTreeNodes(tree, ['a']) // [{ value: 'd' }]
106
106
  */
107
- export declare function removeTreeNodes<Node extends TreeNode = TreeNode, Value extends string = string>(tree: Node[], valuesToRemove: Value[]): Node[];
107
+ export declare function removeTreeNodes<Node extends TreeNode = TreeNode, Path extends string = string>(tree: Node[], valuesToRemove: Path[]): Node[];
@@ -22,12 +22,12 @@ export function filterTree(tree, predicate) {
22
22
  }
23
23
  return result;
24
24
  }
25
- export function findTreeItem(items, value) {
25
+ export function findTreeItem(items, path) {
26
26
  for (const item of items) {
27
- if (item.value === value)
27
+ if (item.path === path)
28
28
  return item;
29
29
  if (item.children?.length) {
30
- const found = findTreeItem(item.children, value);
30
+ const found = findTreeItem(item.children, path);
31
31
  if (found)
32
32
  return found;
33
33
  }
@@ -37,14 +37,14 @@ export function findTreeItem(items, value) {
37
37
  export function flatTree(tree) {
38
38
  return traverse(tree);
39
39
  }
40
- export function getBranchChildren(tree, value) {
40
+ export function getBranchChildren(tree, path) {
41
41
  const children = [];
42
42
  function findAndExtract(nodes) {
43
43
  for (const node of nodes) {
44
- if (node.value === value) {
44
+ if (node.path === path) {
45
45
  if (node.children?.length) {
46
46
  const extracted = traverse(node.children);
47
- children.push(...extracted.map((i) => i.value));
47
+ children.push(...extracted.map((i) => i.path));
48
48
  }
49
49
  return true;
50
50
  }
@@ -63,11 +63,11 @@ export function getTreeItemsBetween(tree, start, end) {
63
63
  let currentIdx = 0;
64
64
  function traverseAndFind(nodes) {
65
65
  for (const node of nodes) {
66
- if (node.value === start)
66
+ if (node.path === start)
67
67
  startIdx = currentIdx;
68
- if (node.value === end)
68
+ if (node.path === end)
69
69
  endIdx = currentIdx;
70
- result.push(node.value);
70
+ result.push(node.path);
71
71
  currentIdx++;
72
72
  if (node.children?.length)
73
73
  traverseAndFind(node.children);
@@ -81,5 +81,5 @@ export function getTreeItemsBetween(tree, start, end) {
81
81
  }
82
82
  export function removeTreeNodes(tree, valuesToRemove) {
83
83
  const removeSet = new Set(valuesToRemove);
84
- return filterTree(tree, (n) => !removeSet.has(n.value));
84
+ return filterTree(tree, (n) => !removeSet.has(n.path));
85
85
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuance-ui",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "A UI Library for Modern Web Apps, powered by Vue.",
5
5
  "repository": {
6
6
  "type": "git",