js-kompo-utils 1.0.17 → 1.0.18

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.
@@ -0,0 +1,220 @@
1
+ <template>
2
+ <component :is="tag" class="vl-lazy-tree" :class="treeClass">
3
+ <template v-for="item in visibleItems">
4
+ <slot
5
+ v-if="item.type === 'node'"
6
+ name="node"
7
+ v-bind="item"
8
+ :toggle="toggleFor(item)"
9
+ :load-more="loadMoreFor(item)"
10
+ >
11
+ <div class="vl-lazy-tree__node" :style="item.indentStyle">
12
+ <button
13
+ v-if="item.hasChildren"
14
+ type="button"
15
+ class="vl-lazy-tree__toggle"
16
+ :aria-expanded="item.isExpanded ? 'true' : 'false'"
17
+ @click="toggle(item)"
18
+ >
19
+ <svg
20
+ class="vl-lazy-tree__chevron"
21
+ :class="{ 'vl-lazy-tree__chevron--open': item.isExpanded }"
22
+ viewBox="0 0 20 20"
23
+ aria-hidden="true"
24
+ >
25
+ <path d="M7.5 5l5 5-5 5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
26
+ </svg>
27
+ </button>
28
+ <span>{{ item.node.label || item.node.name }}</span>
29
+ </div>
30
+ </slot>
31
+
32
+ <slot
33
+ v-else-if="item.type === 'loading'"
34
+ name="loading"
35
+ v-bind="item"
36
+ >
37
+ <div class="vl-lazy-tree__loading" :style="item.indentStyle">
38
+ {{ loadingLabel }}
39
+ </div>
40
+ </slot>
41
+
42
+ <slot
43
+ v-else-if="item.type === 'load-more'"
44
+ name="load-more"
45
+ v-bind="item"
46
+ :load-more="loadMoreFor(item)"
47
+ >
48
+ <vl-infinite-load
49
+ class="vl-lazy-tree__load-more"
50
+ :loading="item.isLoading"
51
+ :disabled="item.isLoading"
52
+ :label="showMoreLabel"
53
+ :loading-label="loadingLabel"
54
+ @visible="loadMore(item)"
55
+ />
56
+ </slot>
57
+ </template>
58
+ </component>
59
+ </template>
60
+
61
+ <script>
62
+ import VlInfiniteLoad from './VlInfiniteLoad.vue'
63
+
64
+ const ROOT_KEY = 'root'
65
+
66
+ export default {
67
+ name: 'VlLazyTree',
68
+ components: { VlInfiniteLoad },
69
+ props: {
70
+ tag: { type: String, default: 'div' },
71
+ treeClass: { type: [String, Array, Object], default: '' },
72
+ rootKey: { type: String, default: ROOT_KEY },
73
+ rootNodeIds: { type: Array, default: () => [] },
74
+ nodesById: { type: Object, required: true },
75
+ childrenByParent: { type: Object, required: true },
76
+ pagingByParent: { type: Object, default: () => ({}) },
77
+ expanded: { type: Object, default: () => ({}) },
78
+ loadingParents: { type: Object, default: () => ({}) },
79
+ includeRootPager: { type: Boolean, default: true },
80
+ baseIndent: { type: Number, default: 0 },
81
+ indentStep: { type: Number, default: 0.65 },
82
+ maxIndentDepth: { type: Number, default: 5 },
83
+ loadingLabel: { type: String, default: 'Loading...' },
84
+ showMoreLabel: { type: String, default: 'Show more' },
85
+ },
86
+ computed: {
87
+ visibleItems() {
88
+ const items = []
89
+
90
+ this.appendNodes(items, this.rootNodeIds, 0)
91
+
92
+ if (this.includeRootPager) {
93
+ this.appendLoadMore(items, this.rootKey, null, 0, true)
94
+ }
95
+
96
+ return items
97
+ },
98
+ },
99
+ methods: {
100
+ appendNodes(items, nodeIds, depth) {
101
+ nodeIds.forEach(nodeId => {
102
+ const node = this.nodesById[nodeId]
103
+ if (!node) return
104
+
105
+ const childIds = this.childIds(nodeId)
106
+ const paging = this.paging(nodeId)
107
+ const item = {
108
+ type: 'node',
109
+ key: `node:${nodeId}`,
110
+ nodeId,
111
+ node,
112
+ depth,
113
+ childIds,
114
+ paging,
115
+ hasChildren: !!node.hasChildren || childIds.length > 0,
116
+ isExpanded: this.isExpanded(nodeId),
117
+ isLoading: this.isLoading(nodeId),
118
+ indentStyle: this.indentStyle(depth),
119
+ }
120
+
121
+ items.push(item)
122
+
123
+ if (!item.isExpanded) return
124
+
125
+ if (item.isLoading && childIds.length === 0) {
126
+ items.push({
127
+ type: 'loading',
128
+ key: `loading:${nodeId}`,
129
+ parentId: nodeId,
130
+ parentNode: node,
131
+ depth: depth + 1,
132
+ indentStyle: this.indentStyle(depth + 1),
133
+ })
134
+ }
135
+
136
+ this.appendNodes(items, childIds, depth + 1)
137
+ this.appendLoadMore(items, nodeId, node, depth + 1, false)
138
+ })
139
+ },
140
+ appendLoadMore(items, parentId, parentNode, depth, isRoot) {
141
+ const paging = this.paging(parentId)
142
+ if (!paging || paging.nextCursor === null) return
143
+
144
+ items.push({
145
+ type: 'load-more',
146
+ key: `load-more:${parentId}:${paging.nextCursor}`,
147
+ parentId,
148
+ parentNode,
149
+ root: isRoot,
150
+ depth,
151
+ paging,
152
+ isLoading: this.isLoading(parentId),
153
+ indentStyle: this.indentStyle(depth),
154
+ })
155
+ },
156
+ childIds(parentId) {
157
+ return this.childrenByParent[parentId] || []
158
+ },
159
+ paging(parentId) {
160
+ return this.pagingByParent[parentId] || null
161
+ },
162
+ isExpanded(nodeId) {
163
+ return !!this.expanded[nodeId]
164
+ },
165
+ isLoading(parentId) {
166
+ return !!this.loadingParents[parentId]
167
+ },
168
+ indentStyle(depth) {
169
+ return { paddingLeft: `${this.baseIndent + (Math.min(depth, this.maxIndentDepth) * this.indentStep)}rem` }
170
+ },
171
+ toggle(item) {
172
+ if (!item || !item.hasChildren) return
173
+
174
+ this.$emit('toggle', item.node)
175
+ },
176
+ loadMore(item) {
177
+ if (!item || item.isLoading) return
178
+
179
+ this.$emit('load-more', item)
180
+ },
181
+ toggleFor(item) {
182
+ return () => this.toggle(item)
183
+ },
184
+ loadMoreFor(item) {
185
+ return () => this.loadMore(item)
186
+ },
187
+ },
188
+ }
189
+ </script>
190
+
191
+ <style>
192
+ .vl-lazy-tree {
193
+ display: block;
194
+ }
195
+
196
+ .vl-lazy-tree__node {
197
+ display: flex;
198
+ align-items: center;
199
+ gap: 0.4rem;
200
+ }
201
+
202
+ .vl-lazy-tree__toggle {
203
+ display: inline-flex;
204
+ align-items: center;
205
+ justify-content: center;
206
+ border: 0;
207
+ background: transparent;
208
+ cursor: pointer;
209
+ }
210
+
211
+ .vl-lazy-tree__chevron {
212
+ width: 0.9rem;
213
+ height: 0.9rem;
214
+ transition: transform 0.2s ease;
215
+ }
216
+
217
+ .vl-lazy-tree__chevron--open {
218
+ transform: rotate(90deg);
219
+ }
220
+ </style>