@webitel/ui-sdk 24.12.61 → 24.12.62
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/CHANGELOG.md +6 -0
- package/dist/img/sprite/index.js +4 -2
- package/dist/img/sprite/tree-corner.svg +3 -0
- package/dist/ui-sdk.css +1 -1
- package/dist/ui-sdk.js +6632 -6462
- package/dist/ui-sdk.umd.cjs +16 -16
- package/package.json +1 -1
- package/src/assets/icons/sprite/index.js +4 -2
- package/src/assets/icons/sprite/tree-corner.svg +3 -0
- package/src/components/index.js +12 -10
- package/src/components/wt-tree/__tests__/WtTree.spec.js +13 -0
- package/src/components/wt-tree/types/wt-tree-mode.ts +4 -0
- package/src/components/wt-tree/wt-tree.vue +178 -0
- package/src/components/wt-tree-line/_variables.scss +21 -0
- package/src/components/wt-tree-line/types/wt-tree-nested-icons.ts +4 -0
- package/src/components/wt-tree-line/wt-tree-line.vue +222 -0
package/package.json
CHANGED
|
@@ -179,10 +179,11 @@ import sttSearch from './stt-search.svg';
|
|
|
179
179
|
import telegramBot from './telegram-bot.svg';
|
|
180
180
|
import tick from './tick.svg';
|
|
181
181
|
import treeCollapse from './tree-collapse.svg';
|
|
182
|
-
import treeCross from './tree-cross.svg';
|
|
183
182
|
import treeExpand from './tree-expand.svg';
|
|
184
|
-
import treeLine from './tree-line.svg';
|
|
185
183
|
import ttsDownload from './tts-download.svg';
|
|
184
|
+
import treeLine from './tree-line.svg';
|
|
185
|
+
import treeCorner from './tree-corner.svg';
|
|
186
|
+
import treeCross from './tree-cross.svg';
|
|
186
187
|
import undo from './undo.svg';
|
|
187
188
|
import unpin from './unpin.svg';
|
|
188
189
|
import upload from './upload.svg';
|
|
@@ -354,6 +355,7 @@ export default objCamelToKebab({
|
|
|
354
355
|
zoomOut,
|
|
355
356
|
ttsDownload,
|
|
356
357
|
treeLine,
|
|
358
|
+
treeCorner,
|
|
357
359
|
treeCross,
|
|
358
360
|
stt,
|
|
359
361
|
sttDownload,
|
package/src/components/index.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import WtNavigationMenu from './on-demand/wt-navigation-menu/components/wt-navigation-menu.vue';
|
|
2
|
+
import WtSelectionPopup from './on-demand/wt-selection-popup/wt-selection-popup.vue';
|
|
3
|
+
import WtStartPage from './on-demand/wt-start-page/components/wt-start-page.vue';
|
|
1
4
|
import WtActionBar from './wt-action-bar/wt-action-bar.vue';
|
|
2
5
|
import WtAppHeader from './wt-app-header/wt-app-header.vue';
|
|
3
6
|
import WtAppNavigator from './wt-app-header/wt-app-navigator.vue';
|
|
4
7
|
import WtHeaderActions from './wt-app-header/wt-header-actions.vue';
|
|
5
8
|
import WtAvatar from './wt-avatar/wt-avatar.vue';
|
|
6
9
|
import WtBadge from './wt-badge/wt-badge.vue';
|
|
7
|
-
import WtButtonSelect from './wt-button-select/wt-button-select.vue';
|
|
8
10
|
import WtButton from './wt-button/wt-button.vue';
|
|
11
|
+
import WtButtonSelect from './wt-button-select/wt-button-select.vue';
|
|
9
12
|
import WtCheckbox from './wt-checkbox/wt-checkbox.vue';
|
|
10
13
|
import WtChip from './wt-chip/wt-chip.vue';
|
|
11
14
|
import WtConfirmDialog from './wt-confirm-dialog/wt-confirm-dialog.vue';
|
|
@@ -13,21 +16,22 @@ import WtContextMenu from './wt-context-menu/wt-context-menu.vue';
|
|
|
13
16
|
import WtCopyAction from './wt-copy-action/wt-copy-action.vue';
|
|
14
17
|
import WtDatepicker from './wt-datepicker/wt-datepicker.vue';
|
|
15
18
|
import WtDivider from './wt-divider/wt-divider.vue';
|
|
19
|
+
import WtDualPanel from './wt-dual-panel/wt-dual-panel.vue';
|
|
16
20
|
import WtDummy from './wt-dummy/wt-dummy.vue';
|
|
17
21
|
import WtEmpty from './wt-empty/wt-empty.vue';
|
|
18
22
|
import WtErrorPage from './wt-error-page/wt-error-page.vue';
|
|
19
23
|
import WtExpansionPanel from './wt-expansion-panel/wt-expansion-panel.vue';
|
|
20
24
|
import WtFiltersPanelWrapper from './wt-filters-panel-wrapper/wt-filters-panel-wrapper.vue';
|
|
21
|
-
import WtHeadlineNav from './wt-headline-nav/wt-headline-nav.vue';
|
|
22
25
|
import WtHeadline from './wt-headline/wt-headline.vue';
|
|
26
|
+
import WtHeadlineNav from './wt-headline-nav/wt-headline-nav.vue';
|
|
23
27
|
import WtHint from './wt-hint/wt-hint.vue';
|
|
28
|
+
import WtIcon from './wt-icon/wt-icon.vue';
|
|
24
29
|
import WtIconAction from './wt-icon-action/wt-icon-action.vue';
|
|
25
30
|
import WtIconBtn from './wt-icon-btn/wt-icon-btn.vue';
|
|
26
|
-
import WtIcon from './wt-icon/wt-icon.vue';
|
|
27
31
|
import WtImage from './wt-image/wt-image.vue';
|
|
28
32
|
import WtIndicator from './wt-indicator/wt-indicator.vue';
|
|
29
|
-
import WtInputInfo from './wt-input-info/wt-input-info.vue';
|
|
30
33
|
import WtInput from './wt-input/wt-input.vue';
|
|
34
|
+
import WtInputInfo from './wt-input-info/wt-input-info.vue';
|
|
31
35
|
import WtIntersectionObserver from './wt-intersection-observer/wt-intersection-observer.vue';
|
|
32
36
|
import WtItemLink from './wt-item-link/wt-item-link.vue';
|
|
33
37
|
import WtLabel from './wt-label/wt-label.vue';
|
|
@@ -39,7 +43,6 @@ import WtNotification from './wt-notification/wt-notification.vue';
|
|
|
39
43
|
import WtNotificationsBar from './wt-notifications-bar/wt-notifications-bar.vue';
|
|
40
44
|
import WtPageHeader from './wt-page-header/wt-page-header.vue';
|
|
41
45
|
import WtPageWrapper from './wt-page-wrapper/wt-page-wrapper.vue';
|
|
42
|
-
import WtDualPanel from './wt-dual-panel/wt-dual-panel.vue';
|
|
43
46
|
import WtPagination from './wt-pagination/wt-pagination.vue';
|
|
44
47
|
import WtPlayer from './wt-player/wt-player.vue';
|
|
45
48
|
import WtPopup from './wt-popup/wt-popup.vue';
|
|
@@ -52,19 +55,17 @@ import WtSlider from './wt-slider/wt-slider.vue';
|
|
|
52
55
|
import WtStatusSelect from './wt-status-select/wt-status-select.vue';
|
|
53
56
|
import WtStepper from './wt-stepper/wt-stepper.vue';
|
|
54
57
|
import WtSwitcher from './wt-switcher/wt-switcher.vue';
|
|
58
|
+
import WtTable from './wt-table/wt-table.vue';
|
|
55
59
|
import WtTableActions from './wt-table-actions/wt-table-actions.vue';
|
|
56
60
|
import WtTableColumnSelect from './wt-table-column-select/wt-table-column-select.vue';
|
|
57
|
-
import WtTable from './wt-table/wt-table.vue';
|
|
58
|
-
import WtTreeTable from './wt-tree-table/wt-tree-table.vue';
|
|
59
61
|
import WtTabs from './wt-tabs/wt-tabs.vue';
|
|
60
62
|
import WtTagsInput from './wt-tags-input/wt-tags-input.vue';
|
|
61
63
|
import WtTextarea from './wt-textarea/wt-textarea.vue';
|
|
62
64
|
import WtTimeInput from './wt-time-input/wt-time-input.vue';
|
|
63
65
|
import WtTimepicker from './wt-timepicker/wt-timepicker.vue';
|
|
64
66
|
import WtTooltip from './wt-tooltip/wt-tooltip.vue';
|
|
65
|
-
import
|
|
66
|
-
import
|
|
67
|
-
import WtSelectionPopup from './on-demand/wt-selection-popup/wt-selection-popup.vue';
|
|
67
|
+
import WtTree from './wt-tree/wt-tree.vue';
|
|
68
|
+
import WtTreeTable from './wt-tree-table/wt-tree-table.vue';
|
|
68
69
|
|
|
69
70
|
const Components = {
|
|
70
71
|
WtActionBar,
|
|
@@ -118,6 +119,7 @@ const Components = {
|
|
|
118
119
|
WtPlayer,
|
|
119
120
|
WtStatusSelect,
|
|
120
121
|
WtTable,
|
|
122
|
+
WtTree,
|
|
121
123
|
WtTreeTable,
|
|
122
124
|
WtTableActions,
|
|
123
125
|
WtTableColumnSelect,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { mount, shallowMount } from '@vue/test-utils';
|
|
2
|
+
import WtTree from '../wt-tree.vue';
|
|
3
|
+
|
|
4
|
+
describe('WtTree', () => {
|
|
5
|
+
it('renders a component', () => {
|
|
6
|
+
const wrapper = shallowMount(WtTree, {
|
|
7
|
+
stubs: {
|
|
8
|
+
WtTree: true,
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
expect(wrapper.classes('wt-tree')).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="wt-tree">
|
|
3
|
+
<div
|
|
4
|
+
v-if="mode === WtTreeMode.TREE"
|
|
5
|
+
class="wt-tree__content"
|
|
6
|
+
>
|
|
7
|
+
<wt-tree-line
|
|
8
|
+
v-for="(item, index) in data"
|
|
9
|
+
:key="index"
|
|
10
|
+
:model-value="modelValue"
|
|
11
|
+
:item-label="itemLabel"
|
|
12
|
+
:item-data="itemData"
|
|
13
|
+
:data="item"
|
|
14
|
+
:children-prop="childrenProp"
|
|
15
|
+
@update:model-value="emit('update:modelValue', $event)"
|
|
16
|
+
/>
|
|
17
|
+
</div>
|
|
18
|
+
<div
|
|
19
|
+
v-if="mode === WtTreeMode.LIST"
|
|
20
|
+
class="wt-tree__list-content"
|
|
21
|
+
>
|
|
22
|
+
<span
|
|
23
|
+
v-for="(item, index) in allData"
|
|
24
|
+
:key="index"
|
|
25
|
+
class="wt-tree__label-wrapper"
|
|
26
|
+
:class="{ active: compareSelectElement(item) }"
|
|
27
|
+
>
|
|
28
|
+
<p
|
|
29
|
+
class="wt-tree__label"
|
|
30
|
+
@click="selectElement(item)"
|
|
31
|
+
>
|
|
32
|
+
{{ itemLabel ? item[itemLabel] : item }}
|
|
33
|
+
</p>
|
|
34
|
+
<wt-icon
|
|
35
|
+
v-if="compareSelectElement(item)"
|
|
36
|
+
icon="chat-message-status-sent"
|
|
37
|
+
class="wt-tree__label-icon"
|
|
38
|
+
/>
|
|
39
|
+
</span>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<script setup lang="ts">
|
|
45
|
+
import deepEqual from 'deep-equal';
|
|
46
|
+
import { computed } from 'vue';
|
|
47
|
+
|
|
48
|
+
import WtTreeLine from '../wt-tree-line/wt-tree-line.vue';
|
|
49
|
+
import { WtTreeMode } from './types/wt-tree-mode.ts';
|
|
50
|
+
|
|
51
|
+
const props = withDefaults(
|
|
52
|
+
defineProps<{
|
|
53
|
+
/**
|
|
54
|
+
* Selected element, it can be an object or a string, related to itemData props
|
|
55
|
+
*/
|
|
56
|
+
modelValue?: null | any;
|
|
57
|
+
/**
|
|
58
|
+
* You need to pass an array of objects that will be displayed in the tree
|
|
59
|
+
*/
|
|
60
|
+
data: any[];
|
|
61
|
+
/**
|
|
62
|
+
* You can pass the name of the property that will be used as the label of the selected item
|
|
63
|
+
*/
|
|
64
|
+
itemLabel?: string;
|
|
65
|
+
/**
|
|
66
|
+
* You can pass the name of the property that will be used as the value of the selected item
|
|
67
|
+
*/
|
|
68
|
+
itemData?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Select mode for display tree data
|
|
71
|
+
* @example 'tree', 'list'
|
|
72
|
+
*/
|
|
73
|
+
mode?: string;
|
|
74
|
+
/**
|
|
75
|
+
* You can pass the name of the property that will be used for getting children elements
|
|
76
|
+
*/
|
|
77
|
+
childrenProp?: string;
|
|
78
|
+
}>(),
|
|
79
|
+
{
|
|
80
|
+
childrenProp: 'children',
|
|
81
|
+
mode: WtTreeMode.TREE,
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const emit = defineEmits<{
|
|
86
|
+
(e: 'select', data: any): void;
|
|
87
|
+
(e: 'update:modelValue', value: any): void;
|
|
88
|
+
}>();
|
|
89
|
+
|
|
90
|
+
const allData = computed(() => {
|
|
91
|
+
const result = [];
|
|
92
|
+
|
|
93
|
+
const getNestedItems = (item: any) => {
|
|
94
|
+
result.push(item);
|
|
95
|
+
|
|
96
|
+
if (item[props.childrenProp]) {
|
|
97
|
+
item[props.childrenProp].forEach((child: any) => {
|
|
98
|
+
getNestedItems(child);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
props.data.forEach((item) => {
|
|
104
|
+
getNestedItems(item);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return result;
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const selectElement = (item: any) => {
|
|
111
|
+
emit('update:modelValue', props.itemData ? item[props.itemData] : item);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const compareSelectElement = (item: any) => {
|
|
115
|
+
if (props.itemData) {
|
|
116
|
+
return item[props.itemData] === props.modelValue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return deepEqual(props.modelValue, item);
|
|
120
|
+
};
|
|
121
|
+
</script>
|
|
122
|
+
|
|
123
|
+
<style lang="scss">
|
|
124
|
+
@use '../../css/main.scss' as *;
|
|
125
|
+
|
|
126
|
+
.wt-tree {
|
|
127
|
+
padding: var(--spacing-sm);
|
|
128
|
+
background: var(--content-wrapper-color);
|
|
129
|
+
border-radius: var(--border-radius);
|
|
130
|
+
overflow: auto;
|
|
131
|
+
|
|
132
|
+
&__content {
|
|
133
|
+
@extend %wt-scrollbar;
|
|
134
|
+
|
|
135
|
+
display: flex;
|
|
136
|
+
flex-direction: column;
|
|
137
|
+
overflow: auto;
|
|
138
|
+
height: 100%;
|
|
139
|
+
padding-right: var(--spacing-2xs);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
&__list-content {
|
|
143
|
+
@extend %wt-scrollbar;
|
|
144
|
+
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
padding-right: var(--spacing-2xs);
|
|
148
|
+
gap: var(--spacing-xs);
|
|
149
|
+
overflow: auto;
|
|
150
|
+
align-items: flex-start;
|
|
151
|
+
height: 100%;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
&__label-wrapper {
|
|
155
|
+
display: flex;
|
|
156
|
+
align-items: center;
|
|
157
|
+
cursor: pointer;
|
|
158
|
+
padding: 0 var(--spacing-2xs);
|
|
159
|
+
border-radius: var(--border-radius);
|
|
160
|
+
color: var(--wt-tree-item-on);
|
|
161
|
+
transition: var(--transition);
|
|
162
|
+
|
|
163
|
+
&:hover {
|
|
164
|
+
background: var(--wt-tree-item-hover);
|
|
165
|
+
color: var(--wt-tree-item-hover-on);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
&.active {
|
|
169
|
+
background: var(--wt-tree-item-active);
|
|
170
|
+
color: var(--wt-tree-item-active-on);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
&__label-icon {
|
|
175
|
+
flex-shrink: 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
:root {
|
|
3
|
+
--wt-tree-item-active: var(--primary-light-color);
|
|
4
|
+
--wt-tree-item-active-on: var(--grey-darken-4);
|
|
5
|
+
|
|
6
|
+
--wt-tree-item: var(--primary-light-color);
|
|
7
|
+
--wt-tree-item-on: var(--grey-darken-1);
|
|
8
|
+
|
|
9
|
+
--wt-tree-item-hover: var(--dp-24-surface-color);
|
|
10
|
+
--wt-tree-item-hover-on: var(--grey-darken-1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
:root.theme--dark {
|
|
14
|
+
--wt-tree-item-active: var(--primary-light-color);
|
|
15
|
+
--wt-tree-item-active-on: var(--grey-lighten-4);
|
|
16
|
+
|
|
17
|
+
--wt-tree-item: var(--primary-light-color);
|
|
18
|
+
--wt-tree-item-on: var(--grey-lighten-3);
|
|
19
|
+
|
|
20
|
+
--wt-tree-item-hover-on: var(--grey-lighten-3);
|
|
21
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="wt-tree-line">
|
|
3
|
+
<div class="wt-tree-line__icon-wrapper">
|
|
4
|
+
<wt-icon
|
|
5
|
+
v-for="(icon, index) in nestedIcons"
|
|
6
|
+
:key="index"
|
|
7
|
+
:icon="icon.icon"
|
|
8
|
+
:class="{ hidden: icon.hidden }"
|
|
9
|
+
/>
|
|
10
|
+
<wt-icon
|
|
11
|
+
v-if="nestedLevel >= 1"
|
|
12
|
+
:icon="lastChild ? 'tree-corner' : 'tree-cross'"
|
|
13
|
+
/>
|
|
14
|
+
<wt-icon-btn
|
|
15
|
+
v-if="data[childrenProp] && data[childrenProp].length"
|
|
16
|
+
:icon="collapsed ? 'plus' : 'minus'"
|
|
17
|
+
@click="collapsed = !collapsed"
|
|
18
|
+
/>
|
|
19
|
+
</div>
|
|
20
|
+
<div
|
|
21
|
+
:class="{ active: isSelected }"
|
|
22
|
+
class="wt-tree-line__label-wrapper"
|
|
23
|
+
>
|
|
24
|
+
<p
|
|
25
|
+
class="wt-tree-line__label"
|
|
26
|
+
@click="selectElement"
|
|
27
|
+
>
|
|
28
|
+
{{ label }}
|
|
29
|
+
</p>
|
|
30
|
+
<wt-icon
|
|
31
|
+
v-if="isSelected"
|
|
32
|
+
icon="chat-message-status-sent"
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<wt-expand-transition v-show="!collapsed">
|
|
37
|
+
<div>
|
|
38
|
+
<wt-tree-line
|
|
39
|
+
v-for="(child, index) in data[childrenProp]"
|
|
40
|
+
:key="index"
|
|
41
|
+
:model-value="modelValue"
|
|
42
|
+
:data="child"
|
|
43
|
+
:children-prop="childrenProp"
|
|
44
|
+
:item-label="itemLabel"
|
|
45
|
+
:item-data="itemData"
|
|
46
|
+
:nested-level="nestedLevel + 1"
|
|
47
|
+
:next-element="!!data[childrenProp][index + 1]"
|
|
48
|
+
:nested-icons="displayIcons"
|
|
49
|
+
:last-child="index === data[childrenProp].length - 1"
|
|
50
|
+
@open-parent="onOpenParent"
|
|
51
|
+
@update:model-value="emit('update:modelValue', $event)"
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
</wt-expand-transition>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<script setup lang="ts">
|
|
58
|
+
import deepEqual from 'deep-equal';
|
|
59
|
+
import { computed, onMounted, ref, watch } from 'vue';
|
|
60
|
+
|
|
61
|
+
import WtExpandTransition from '../transitions/wt-expand-transition.vue';
|
|
62
|
+
import type { WtTreeNestedIcons } from './types/wt-tree-nested-icons.ts';
|
|
63
|
+
|
|
64
|
+
const props = withDefaults(
|
|
65
|
+
defineProps<{
|
|
66
|
+
modelValue: null | any;
|
|
67
|
+
data: any;
|
|
68
|
+
itemLabel?: string | undefined;
|
|
69
|
+
itemData?: string | undefined;
|
|
70
|
+
childrenProp?: string;
|
|
71
|
+
nestedLevel?: number;
|
|
72
|
+
lastChild?: boolean;
|
|
73
|
+
nestedIcons?: WtTreeNestedIcons[];
|
|
74
|
+
nextElement?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* 'It's a key in data object, which contains field what display searched elements. By this field, table will be opened to elements with this field value. '
|
|
77
|
+
*/
|
|
78
|
+
searchedProp?: string;
|
|
79
|
+
}>(),
|
|
80
|
+
{
|
|
81
|
+
nestedLevel: 0,
|
|
82
|
+
childrenProp: 'children',
|
|
83
|
+
lastChild: false,
|
|
84
|
+
nextElement: false,
|
|
85
|
+
searchedProp: 'searched',
|
|
86
|
+
},
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const emit = defineEmits<{
|
|
90
|
+
(e: 'openParent'): void;
|
|
91
|
+
(e: 'update:modelValue', value: any): void;
|
|
92
|
+
}>();
|
|
93
|
+
|
|
94
|
+
const label = computed(() =>
|
|
95
|
+
props.itemLabel ? props.data[props.itemLabel] : props.data,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const displayIcons = computed(() => {
|
|
99
|
+
const icons = props.nestedIcons ? [...props.nestedIcons] : [];
|
|
100
|
+
|
|
101
|
+
if (props.nestedLevel === 0) {
|
|
102
|
+
return icons;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
icons.push({
|
|
106
|
+
icon: 'tree-line',
|
|
107
|
+
hidden: !props.nextElement,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return icons;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const isSelected = computed(() => {
|
|
114
|
+
if (props.itemData) {
|
|
115
|
+
return props.data[props.itemData] === props.modelValue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return deepEqual(props.modelValue, props.data);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const selectElement = () => {
|
|
122
|
+
if (props.data[props.childrenProp]?.length) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
emit(
|
|
127
|
+
'update:modelValue',
|
|
128
|
+
props.itemData ? props.data[props.itemData] : props.data,
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const collapsed = ref(true);
|
|
133
|
+
const openParent = () => {
|
|
134
|
+
if (props.nestedLevel > 0) {
|
|
135
|
+
emit('openParent');
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const onOpenParent = () => {
|
|
140
|
+
collapsed.value = false;
|
|
141
|
+
openParent();
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const hasSearchedElement = (data: Record<string, any>, nestedLevel = 0) => {
|
|
145
|
+
// Check if the object itself has searched
|
|
146
|
+
if (data[props.searchedProp] && nestedLevel) {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Check if the object has children
|
|
151
|
+
if (Array.isArray(data[props.childrenProp])) {
|
|
152
|
+
// Iterate through the array
|
|
153
|
+
for (const child of data[props.childrenProp]) {
|
|
154
|
+
// Recursively check nested objects
|
|
155
|
+
if (hasSearchedElement(child, nestedLevel + 1)) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// If no match is found, return false
|
|
162
|
+
return false;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
onMounted(() => {
|
|
166
|
+
if (isSelected.value) {
|
|
167
|
+
openParent();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (props.data[props.searchedProp]) {
|
|
171
|
+
openParent();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
watch(
|
|
176
|
+
() => props.modelValue,
|
|
177
|
+
() => {
|
|
178
|
+
if (isSelected.value) {
|
|
179
|
+
openParent();
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
</script>
|
|
184
|
+
|
|
185
|
+
<style lang="scss">
|
|
186
|
+
@use '../../css/main.scss' as *;
|
|
187
|
+
@use './variables.scss' as *;
|
|
188
|
+
|
|
189
|
+
.wt-tree-line {
|
|
190
|
+
display: flex;
|
|
191
|
+
align-items: flex-start;
|
|
192
|
+
|
|
193
|
+
&__icon-wrapper {
|
|
194
|
+
display: flex;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
&__label-wrapper {
|
|
198
|
+
display: flex;
|
|
199
|
+
align-items: center;
|
|
200
|
+
cursor: pointer;
|
|
201
|
+
padding: 0 var(--spacing-2xs);
|
|
202
|
+
border-radius: var(--border-radius);
|
|
203
|
+
color: var(--wt-tree-item-on);
|
|
204
|
+
transition: var(--transition);
|
|
205
|
+
|
|
206
|
+
&:hover {
|
|
207
|
+
background: var(--wt-tree-item-hover);
|
|
208
|
+
color: var(--wt-tree-item-hover-on);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
&.active {
|
|
212
|
+
background: var(--wt-tree-item-active);
|
|
213
|
+
color: var(--wt-tree-item-active-on);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
&__label {
|
|
218
|
+
@extend %typo-body-1;
|
|
219
|
+
text-wrap: nowrap;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
</style>
|