@vuecs/navigation 1.1.1 → 2.1.0

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.
Files changed (98) hide show
  1. package/README.md +54 -142
  2. package/dist/components/index.d.ts +1 -1
  3. package/dist/components/index.d.ts.map +1 -1
  4. package/dist/components/item/index.d.ts +2 -0
  5. package/dist/components/item/index.d.ts.map +1 -0
  6. package/dist/components/item/module.d.ts +16 -0
  7. package/dist/components/item/module.d.ts.map +1 -0
  8. package/dist/components/items/index.d.ts +2 -0
  9. package/dist/components/items/index.d.ts.map +1 -0
  10. package/dist/components/items/module.d.ts +27 -0
  11. package/dist/components/items/module.d.ts.map +1 -0
  12. package/dist/helpers/component/build.d.ts +3 -0
  13. package/dist/helpers/component/build.d.ts.map +1 -0
  14. package/dist/helpers/component/index.d.ts +3 -0
  15. package/dist/helpers/component/index.d.ts.map +1 -0
  16. package/dist/helpers/component/types.d.ts +17 -0
  17. package/dist/helpers/component/types.d.ts.map +1 -0
  18. package/dist/helpers/index.d.ts +8 -0
  19. package/dist/helpers/index.d.ts.map +1 -0
  20. package/dist/helpers/level.d.ts +11 -0
  21. package/dist/helpers/level.d.ts.map +1 -0
  22. package/dist/helpers/match.d.ts +7 -0
  23. package/dist/helpers/match.d.ts.map +1 -0
  24. package/dist/helpers/normalize.d.ts +8 -0
  25. package/dist/helpers/normalize.d.ts.map +1 -0
  26. package/dist/helpers/reset.d.ts +3 -0
  27. package/dist/helpers/reset.d.ts.map +1 -0
  28. package/dist/helpers/trace.d.ts +3 -0
  29. package/dist/helpers/trace.d.ts.map +1 -0
  30. package/dist/helpers/url.d.ts.map +1 -0
  31. package/dist/index.cjs +456 -456
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.css +87 -0
  34. package/dist/index.d.ts +4 -6
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.mjs +455 -452
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/manager/index.d.ts +4 -0
  39. package/dist/manager/index.d.ts.map +1 -0
  40. package/dist/manager/module.d.ts +20 -0
  41. package/dist/manager/module.d.ts.map +1 -0
  42. package/dist/manager/singleton.d.ts +5 -0
  43. package/dist/manager/singleton.d.ts.map +1 -0
  44. package/dist/manager/types.d.ts +9 -0
  45. package/dist/manager/types.d.ts.map +1 -0
  46. package/dist/types.d.ts +33 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/package.json +10 -6
  49. package/dist/components/item.d.ts +0 -26
  50. package/dist/components/item.d.ts.map +0 -1
  51. package/dist/components/items.d.ts +0 -27
  52. package/dist/components/items.d.ts.map +0 -1
  53. package/dist/core/build.d.ts +0 -4
  54. package/dist/core/build.d.ts.map +0 -1
  55. package/dist/core/check.d.ts +0 -3
  56. package/dist/core/check.d.ts.map +0 -1
  57. package/dist/core/expansion.d.ts +0 -6
  58. package/dist/core/expansion.d.ts.map +0 -1
  59. package/dist/core/flatten.d.ts +0 -3
  60. package/dist/core/flatten.d.ts.map +0 -1
  61. package/dist/core/index.d.ts +0 -12
  62. package/dist/core/index.d.ts.map +0 -1
  63. package/dist/core/match.d.ts +0 -3
  64. package/dist/core/match.d.ts.map +0 -1
  65. package/dist/core/reduce.d.ts +0 -8
  66. package/dist/core/reduce.d.ts.map +0 -1
  67. package/dist/core/refresh.d.ts +0 -3
  68. package/dist/core/refresh.d.ts.map +0 -1
  69. package/dist/core/replace.d.ts +0 -6
  70. package/dist/core/replace.d.ts.map +0 -1
  71. package/dist/core/reset.d.ts +0 -3
  72. package/dist/core/reset.d.ts.map +0 -1
  73. package/dist/core/select.d.ts +0 -4
  74. package/dist/core/select.d.ts.map +0 -1
  75. package/dist/core/tier.d.ts +0 -7
  76. package/dist/core/tier.d.ts.map +0 -1
  77. package/dist/core/toggle.d.ts +0 -4
  78. package/dist/core/toggle.d.ts.map +0 -1
  79. package/dist/module.d.ts +0 -3
  80. package/dist/module.d.ts.map +0 -1
  81. package/dist/provider/index.d.ts +0 -3
  82. package/dist/provider/index.d.ts.map +0 -1
  83. package/dist/provider/module.d.ts +0 -5
  84. package/dist/provider/module.d.ts.map +0 -1
  85. package/dist/provider/type.d.ts +0 -8
  86. package/dist/provider/type.d.ts.map +0 -1
  87. package/dist/store/index.d.ts +0 -3
  88. package/dist/store/index.d.ts.map +0 -1
  89. package/dist/store/module.d.ts +0 -7
  90. package/dist/store/module.d.ts.map +0 -1
  91. package/dist/store/type.d.ts +0 -16
  92. package/dist/store/type.d.ts.map +0 -1
  93. package/dist/type.d.ts +0 -27
  94. package/dist/type.d.ts.map +0 -1
  95. package/dist/utils/index.d.ts +0 -2
  96. package/dist/utils/index.d.ts.map +0 -1
  97. package/dist/utils/url.d.ts.map +0 -1
  98. /package/dist/{utils → helpers}/url.d.ts +0 -0
package/dist/index.mjs CHANGED
@@ -1,436 +1,490 @@
1
- import { hasNormalizedSlot, normalizeSlot, installStoreManager, applyStoreManagerOptions } from '@vuecs/core';
2
- import { inject, ref, provide, hasInjectionContext, isRef, defineComponent, toRef, h, resolveComponent, computed } from 'vue';
1
+ import { createComponentOptionsManager, mergeOption, inject, provide, hasNormalizedSlot, normalizeSlot, installStoreManager, applyStoreManagerOptions } from '@vuecs/core';
2
+ import { EventEmitter } from '@posva/event-emitter';
3
3
  import { VCLink } from '@vuecs/link';
4
+ import { defineComponent, resolveComponent, toRef, h, ref, onMounted, onUnmounted, computed } from 'vue';
4
5
 
5
- let instance;
6
- function useNavigationProvider(module) {
7
- if (typeof instance !== 'undefined') {
8
- return instance;
9
- }
10
- if (typeof module === 'undefined') {
11
- throw new Error('A Navigation Provider must be set!');
12
- }
13
- instance = module;
14
- return instance;
15
- }
16
- function setNavigationProvider(module) {
17
- instance = module;
18
- }
19
- function createNavigationProvider(input) {
20
- return input;
6
+ function buildComponentOptions() {
7
+ const manager = createComponentOptionsManager({
8
+ name: 'navigation'
9
+ });
10
+ return {
11
+ groupClass: mergeOption('class', manager.get('groupClass'), 'vc-nav-items'),
12
+ groupTag: manager.get('groupTag') || 'ul',
13
+ itemClass: mergeOption('class', manager.get('itemClass'), 'vc-nav-item'),
14
+ itemTag: manager.get('itemTag') || 'li',
15
+ subGroupTitleClass: mergeOption('class', manager.get('subGroupTitleClass'), 'vc-nav-sub-level-title'),
16
+ subGroupItemsClass: mergeOption('class', manager.get('subGroupTitleClass'), 'vc-nav-sub-level-items'),
17
+ separatorTag: manager.get('separatorTag') || 'div',
18
+ separatorClass: mergeOption('class', manager.get('iconClass'), 'vc-nav-separator'),
19
+ iconClass: mergeOption('class', manager.get('iconClass'), 'vc-nav-icon'),
20
+ linkClass: mergeOption('class', manager.get('linkClass'), 'vc-nav-link'),
21
+ linkRootClass: mergeOption('class', manager.get('linkRootClass'), 'vc-nav-link-root'),
22
+ linkTextTag: manager.get('linkTextTag') || 'span',
23
+ linkTextClass: mergeOption('class', manager.get('linkTextClass'), 'vc-nav-link-text')
24
+ };
21
25
  }
22
26
 
23
- const StoreSymbol = Symbol.for('VLNavigationStore');
24
- function isStoreInjected() {
25
- if (!hasInjectionContext()) {
26
- return false;
27
+ function findItemMatchesIF(items, options, parent) {
28
+ const output = [];
29
+ for(let i = 0; i < items.length; i++){
30
+ const item = items[i];
31
+ let { score } = parent;
32
+ if (options.path) {
33
+ if (item.activeMatch) {
34
+ if (item.activeMatch === options.path) {
35
+ score += 3;
36
+ } else if (options.path.startsWith(item.activeMatch)) {
37
+ score += 2;
38
+ }
39
+ }
40
+ if (item.url && item.url !== '/') {
41
+ if (item.url === options.path) {
42
+ score += 3;
43
+ } else if (options.path.startsWith(item.url)) {
44
+ score += 2;
45
+ }
46
+ }
47
+ }
48
+ if (item.default) {
49
+ score += 1;
50
+ }
51
+ if (item.children) {
52
+ const childMatches = findItemMatchesIF(item.children, options, {
53
+ score
54
+ });
55
+ output.push(...childMatches);
56
+ }
57
+ output.push({
58
+ data: item,
59
+ score
60
+ });
27
61
  }
28
- const instance = inject(StoreSymbol);
29
- return !!instance;
62
+ return output.sort((a, b)=>b.score - a.score);
30
63
  }
31
- function setupStore(app) {
32
- const store = {
33
- items: ref([]),
34
- itemsActive: ref([])
64
+ function findBestItemMatches(items, options = {}) {
65
+ const result = findItemMatchesIF(items, options, {
66
+ score: 0
67
+ });
68
+ const [first] = result;
69
+ if (!first) {
70
+ return [];
71
+ }
72
+ return result.filter((match)=>match.score === first.score).map((match)=>match.data);
73
+ }
74
+
75
+ /*
76
+ * Copyright (c) 2024.
77
+ * Author Peter Placzek (tada5hi)
78
+ * For the full copyright and license information,
79
+ * view the LICENSE file that was distributed with this source code.
80
+ */ function normalizeItemIF(item, defaults, trace) {
81
+ const output = {
82
+ ...item,
83
+ level: defaults.level,
84
+ children: [],
85
+ trace: [
86
+ ...trace,
87
+ item.name
88
+ ]
35
89
  };
36
- if (typeof app === 'undefined') {
37
- if (isStoreInjected()) {
38
- return;
39
- }
40
- provide(StoreSymbol, store);
41
- return;
90
+ if (!item.children) {
91
+ return output;
42
92
  }
43
- if (app._context && app._context.provides && app._context.provides[StoreSymbol]) {
44
- return;
93
+ for(let i = 0; i < item.children.length; i++){
94
+ output.children.push(normalizeItemIF(item.children[i], defaults, output.trace));
45
95
  }
46
- app.provide(StoreSymbol, store);
96
+ return output;
47
97
  }
48
- function injectStore() {
49
- const instance = inject(StoreSymbol);
50
- if (!instance) {
51
- throw new Error('The Store is not set.');
52
- }
53
- return instance;
98
+ function normalizeItem(item, defaults) {
99
+ return normalizeItemIF(item, defaults, []);
100
+ }
101
+ function normalizeItems(items, options) {
102
+ return items.map((item)=>normalizeItem(item, options));
54
103
  }
55
104
 
56
- function isNavigationItemMatch(one, two) {
57
- if (!one || !two) {
105
+ /*
106
+ * Copyright (c) 2024.
107
+ * Author Peter Placzek (tada5hi)
108
+ * For the full copyright and license information,
109
+ * view the LICENSE file that was distributed with this source code.
110
+ */ function isTraceEqual(a, b) {
111
+ if (a.length !== b.length) {
58
112
  return false;
59
113
  }
60
- if (one.id && two.id && one.id === two.id) {
61
- return true;
62
- }
63
- if (one.name && two.name && one.name === two.name) {
64
- return true;
65
- }
66
- if (one.url && two.url && one.url === two.url) {
67
- return true;
68
- }
69
- if (one.children && two.children && one.children.length === two.children.length) {
70
- for(let i = 0; i < one.children.length; i++){
71
- if (!isNavigationItemMatch(one.children[i], two.children[i])) {
72
- return false;
73
- }
114
+ for(let i = 0; i < a.length; i++){
115
+ if (a[i] !== b[i]) {
116
+ return false;
74
117
  }
75
- return true;
76
118
  }
77
- return false;
119
+ return true;
78
120
  }
79
-
80
- // --------------------------------------------------
81
- function setNavigationExpansion(items, item, parentMatch = false) {
82
- let matchInIteration = false;
83
- for(let i = 0; i < items.length; i++){
84
- const isMatch = isNavigationItemMatch(items[i], item);
85
- let isChildMatch = false;
86
- const { children } = items[i];
87
- if (typeof children !== 'undefined') {
88
- const { items: childItems, match: childMatch } = setNavigationExpansion(children, item, isMatch);
89
- items[i].children = childItems;
90
- isChildMatch = childMatch;
91
- }
92
- if (isMatch) {
93
- items[i].active = true;
94
- }
95
- if (isMatch || isChildMatch) {
96
- items[i].display = true;
97
- items[i].displayChildren = true;
98
- }
99
- if (parentMatch) {
100
- items[i].display = true;
101
- }
102
- if (!matchInIteration) {
103
- matchInIteration = isMatch || isChildMatch;
104
- }
105
- }
106
- if (matchInIteration) {
107
- for(let i = 0; i < items.length; i++){
108
- items[i].display = true;
121
+ function isTracePartOf(item, parent) {
122
+ for(let i = 0; i < item.length; i++){
123
+ if (parent[i] !== item[i]) {
124
+ return false;
109
125
  }
110
126
  }
111
- return {
112
- items,
113
- match: matchInIteration
114
- };
127
+ return true;
115
128
  }
116
129
 
117
- function resetNavigationItem(items, root = true) {
130
+ function resetItemsByTraceIF(items, trace) {
118
131
  for(let i = 0; i < items.length; i++){
119
- items[i].display = root;
120
- items[i].displayChildren = false;
121
- items[i].active = false;
122
- const { children } = items[i];
123
- if (typeof children !== 'undefined') {
124
- items[i].children = resetNavigationItem(children, false);
132
+ const item = items[i];
133
+ const isEqual = isTraceEqual(items[i].trace, trace);
134
+ item.active = isEqual;
135
+ item.display = true;
136
+ if (isEqual) {
137
+ item.displayChildren = true;
138
+ } else {
139
+ item.displayChildren = isTracePartOf(item.trace, trace);
125
140
  }
141
+ item.children = resetItemsByTraceIF(item.children, trace);
126
142
  }
127
143
  return items;
128
144
  }
145
+ function resetItemsByTrace(items, trace) {
146
+ return resetItemsByTraceIF(items, trace);
147
+ }
129
148
 
130
- function findNavigationItemsForTier(items, tier) {
131
- const filterFn = (component)=>typeof component.tier !== 'undefined' && component.tier === tier;
132
- return items.filter(filterFn);
149
+ function findItemsWithLevel(items, tier) {
150
+ return items.filter((item)=>item.level === tier);
133
151
  }
134
- function findNavigationItemForTier(items, tier) {
135
- const data = findNavigationItemsForTier(items, tier);
152
+ function findItemWithLevel(tier, items) {
153
+ const data = findItemsWithLevel(items, tier);
136
154
  if (data.length >= 1) {
137
155
  return data[0];
138
156
  }
139
157
  return undefined;
140
158
  }
141
- function setTierForNavigationItems(items, tier) {
142
- const mapFn = (component)=>{
143
- component.tier = tier;
144
- return component;
145
- };
146
- if (isRef(items)) {
147
- return items.value.map(mapFn);
148
- }
149
- return items.map(mapFn);
150
- }
151
- function removeTierFromNavigationItems(items, tier) {
152
- const filterFn = (items)=>typeof items.tier === 'undefined' || items.tier !== tier;
153
- if (isRef(items)) {
154
- return items.value.filter(filterFn);
155
- }
156
- return items.filter(filterFn);
159
+ function removeItemsWithLevel(tier, items) {
160
+ return items.filter((item)=>item.level !== tier);
157
161
  }
158
-
159
- function replaceNavigationTierItemActive(store, tier, item) {
160
- const items = removeTierFromNavigationItems(store.itemsActive.value, tier);
161
- if (item) {
162
- item.tier = tier;
163
- store.itemsActive.value = [
164
- ...items,
165
- item
162
+ function replaceLevelItem(tier, input, next) {
163
+ const output = removeItemsWithLevel(tier, input);
164
+ if (next) {
165
+ next.level = tier;
166
+ return [
167
+ ...output,
168
+ next
166
169
  ];
167
- } else {
168
- store.itemsActive.value = items;
169
170
  }
171
+ return output;
170
172
  }
171
- function replaceNavigationTierItems(store, tier, items) {
172
- const componentsExisting = removeTierFromNavigationItems(store.items.value, tier);
173
- store.items.value = [
173
+ function replaceLevelItems(tier, src, next) {
174
+ const componentsExisting = removeItemsWithLevel(tier, src);
175
+ return [
174
176
  ...componentsExisting,
175
- ...setTierForNavigationItems(items, tier)
177
+ ...next
176
178
  ];
177
179
  }
178
180
 
179
- function refreshNavigationTierItems(store, tier) {
180
- const components = resetNavigationItem(findNavigationItemsForTier(store.items.value, tier));
181
- const component = findNavigationItemForTier(store.itemsActive.value, tier);
182
- if (component) {
183
- const { items } = setNavigationExpansion(components, component);
184
- replaceNavigationTierItems(store, tier, items);
185
- return;
186
- }
187
- replaceNavigationTierItems(store, tier, components);
181
+ function isAbsoluteURL(str) {
182
+ return str.substring(0, 7) === 'http://' || str.substring(0, 8) === 'https://';
188
183
  }
189
184
 
190
- async function buildNavigationForTier(store, tier, itemsActive) {
191
- if (typeof itemsActive === 'undefined' || itemsActive.length === 0) {
192
- let tierStartIndex = 0;
193
- const tierEndIndex = tier;
194
- itemsActive = [];
195
- while(tierStartIndex <= tierEndIndex){
196
- const component = findNavigationItemForTier(store.itemsActive.value, tierStartIndex);
197
- if (!component) {
185
+ class NavigationManager extends EventEmitter {
186
+ getItems(tier) {
187
+ if (typeof tier === 'undefined') {
188
+ return this.items;
189
+ }
190
+ return this.items.filter((item)=>item.level === tier);
191
+ }
192
+ async buildOnce(options) {
193
+ if (this.built && !options.reset) {
194
+ return this.items;
195
+ }
196
+ return this.build(options);
197
+ }
198
+ async build(options) {
199
+ this.built = true;
200
+ this.items = [];
201
+ this.itemsActive = [];
202
+ let parent;
203
+ let level = 0;
204
+ while(true){
205
+ const raw = await this.itemsFn({
206
+ level,
207
+ parent
208
+ });
209
+ if (!raw || raw.length === 0) {
210
+ break;
211
+ }
212
+ const items = normalizeItems(raw, {
213
+ level
214
+ });
215
+ const matches = findBestItemMatches(items, {
216
+ path: options.path
217
+ });
218
+ const [match] = matches;
219
+ if (!match) {
198
220
  break;
199
221
  }
200
- itemsActive.push(component);
201
- tierStartIndex++;
222
+ this.itemsActive.push(match);
223
+ await this.buildLevel(level);
224
+ parent = match;
225
+ level++;
202
226
  }
227
+ this.emit('updated', this.items);
228
+ return this.items;
203
229
  }
204
- const items = await useNavigationProvider().getItems(tier, itemsActive);
205
- if (typeof items === 'undefined') {
206
- return false;
207
- }
208
- replaceNavigationTierItems(store, tier, items);
209
- refreshNavigationTierItems(store, tier);
210
- return true;
211
- }
212
-
213
- function flattenNestedNavigationItems(items) {
214
- const output = [];
215
- for(let i = 0; i < items.length; i++){
216
- const { children, ...data } = items[i];
217
- output.push(data);
218
- if (children && children.length > 0) {
219
- output.push(...flattenNestedNavigationItems([
220
- ...children
221
- ]));
230
+ async select(level, itemNew) {
231
+ const itemOld = findItemWithLevel(level, this.itemsActive);
232
+ if (itemOld && isTraceEqual(itemOld.trace, itemNew.trace)) {
233
+ return;
234
+ }
235
+ this.itemsActive = this.itemsActive.filter((el)=>el.level < level);
236
+ this.itemsActive.push(itemNew);
237
+ const startLevel = level;
238
+ while(true){
239
+ const built = await this.buildLevel(level, startLevel === level);
240
+ if (!built) {
241
+ break;
242
+ }
243
+ level++;
222
244
  }
223
245
  }
224
- return output;
225
- }
226
-
227
- async function selectNavigationTierItem(store, tier, component) {
228
- const isMatch = isNavigationItemMatch(findNavigationItemForTier(store.itemsActive.value, tier), component);
229
- if (isMatch) {
230
- return;
246
+ async toggle(level, item) {
247
+ let isMatch;
248
+ if (item.displayChildren) {
249
+ isMatch = true;
250
+ } else {
251
+ const itemOld = findItemWithLevel(level, this.itemsActive);
252
+ isMatch = !!itemOld && isTraceEqual(item.trace, itemOld.trace);
253
+ }
254
+ if (isMatch) {
255
+ this.itemsActive = removeItemsWithLevel(level, this.itemsActive);
256
+ } else {
257
+ this.itemsActive = replaceLevelItem(level, this.itemsActive, item);
258
+ }
259
+ await this.buildLevel(level, true);
260
+ }
261
+ async buildLevel(level, cached) {
262
+ let items;
263
+ if (cached) {
264
+ items = findItemsWithLevel(this.items, level);
265
+ } else {
266
+ const parent = findItemWithLevel(level - 1, this.itemsActive);
267
+ const raw = await this.itemsFn({
268
+ level,
269
+ parent
270
+ });
271
+ items = raw && raw.length > 0 ? normalizeItems(raw, {
272
+ level
273
+ }) : [];
274
+ }
275
+ if (!items || items.length === 0) {
276
+ this.items = this.items.filter((item)=>item.level < level);
277
+ this.emit('tierUpdated', level, []);
278
+ return false;
279
+ }
280
+ let trace = [];
281
+ const item = findItemWithLevel(level, this.itemsActive);
282
+ if (item) {
283
+ trace = item.trace;
284
+ }
285
+ resetItemsByTrace(items, trace);
286
+ this.items = replaceLevelItems(level, this.items, items);
287
+ this.emit('tierUpdated', level, items);
288
+ return true;
231
289
  }
232
- replaceNavigationTierItemActive(store, tier, component);
233
- refreshNavigationTierItems(store, tier);
234
- tier++;
235
- // eslint-disable-next-line no-constant-condition
236
- while(true){
237
- const built = await buildNavigationForTier(store, tier);
238
- if (!built) {
239
- break;
290
+ constructor(options){
291
+ super();
292
+ let itemsFn;
293
+ if (typeof options.items === 'function') {
294
+ itemsFn = options.items;
295
+ } else {
296
+ itemsFn = async ({ level })=>{
297
+ if (level > 0) {
298
+ return [];
299
+ }
300
+ return options.items;
301
+ };
240
302
  }
241
- tier++;
303
+ this.itemsFn = itemsFn;
304
+ this.items = [];
305
+ this.itemsActive = [];
306
+ this.built = false;
242
307
  }
243
308
  }
244
309
 
245
- function toggleNavigation(store, tier, component) {
246
- const isMatch = component.displayChildren || isNavigationItemMatch(findNavigationItemForTier(store.itemsActive.value, tier), component);
247
- if (isMatch) {
248
- replaceNavigationTierItemActive(store, tier, undefined);
249
- } else {
250
- replaceNavigationTierItemActive(store, tier, component);
310
+ const sym = Symbol.for('VCNavigationManager');
311
+ function injectNavigationManager(app) {
312
+ const instance = inject(sym, app);
313
+ if (!instance) {
314
+ throw new Error('A navigation provider has not been provided.');
251
315
  }
252
- refreshNavigationTierItems(store, tier);
316
+ return instance;
253
317
  }
254
-
255
- function isAbsoluteURL(str) {
256
- return str.substring(0, 7) === 'http://' || str.substring(0, 8) === 'https://';
318
+ function provideNavigationManager(manager, app) {
319
+ provide(sym, manager, app);
257
320
  }
258
321
 
259
- var SlotName;
260
- (function(SlotName) {
322
+ var SlotName = /*#__PURE__*/ function(SlotName) {
261
323
  SlotName["ITEM"] = "item";
262
324
  SlotName["SEPARATOR"] = "separator";
263
325
  SlotName["LINK"] = "link";
264
326
  SlotName["SUB"] = "sub";
265
327
  SlotName["SUB_TITLE"] = "sub-title";
266
328
  SlotName["SUB_ITEMS"] = "sub-items";
267
- })(SlotName || (SlotName = {}));
268
- var ElementType;
269
- (function(ElementType) {
329
+ return SlotName;
330
+ }({});
331
+ var ElementType = /*#__PURE__*/ function(ElementType) {
270
332
  ElementType["LINK"] = "link";
271
333
  ElementType["SEPARATOR"] = "separator";
272
- })(ElementType || (ElementType = {}));
334
+ return ElementType;
335
+ }({});
273
336
 
274
337
  const VCNavItem = defineComponent({
275
338
  props: {
276
- tier: {
277
- type: Number,
278
- default: 0
279
- },
280
- component: {
339
+ data: {
281
340
  type: Object,
282
341
  required: true
283
342
  }
284
343
  },
285
344
  setup (props, { slots }) {
286
- const store = injectStore();
287
- const component = toRef(props, 'component');
288
- const selectComponent = async (value)=>{
289
- await selectNavigationTierItem(store, props.tier, value);
345
+ const itemsNode = resolveComponent('VCNavItems');
346
+ const options = buildComponentOptions();
347
+ const manager = injectNavigationManager();
348
+ const data = toRef(props, 'data');
349
+ const select = async (value)=>{
350
+ await manager.select(data.value.level, value);
351
+ };
352
+ const toggle = async (value)=>{
353
+ await manager.toggle(data.value.level, value);
290
354
  };
291
- const toggleComponentExpansion = async (value)=>toggleNavigation(store, props.tier, value);
292
355
  return ()=>{
293
356
  const buildItem = ()=>{
294
- let item;
295
- switch(component.value.type){
296
- case ElementType.SEPARATOR:
297
- {
298
- const hasSlot = hasNormalizedSlot(SlotName.SEPARATOR, slots);
299
- if (hasSlot) {
300
- item = normalizeSlot(SlotName.SEPARATOR, {
301
- component: component.value
302
- }, slots);
303
- } else {
304
- item = h('div', {
305
- class: 'nav-separator'
306
- }, component.value.name);
357
+ // type: separator
358
+ if (data.value.type === ElementType.SEPARATOR) {
359
+ const hasSlot = hasNormalizedSlot(SlotName.SEPARATOR, slots);
360
+ if (hasSlot) {
361
+ return normalizeSlot(SlotName.SEPARATOR, {
362
+ data: data.value
363
+ }, slots);
364
+ }
365
+ return h(options.separatorTag, {
366
+ class: options.separatorClass
367
+ }, data.value.name);
368
+ }
369
+ // type: group
370
+ if (!data.value.children || data.value.children.length === 0) {
371
+ const hasSlot = hasNormalizedSlot(SlotName.LINK, slots);
372
+ if (hasSlot) {
373
+ return normalizeSlot(SlotName.LINK, {
374
+ data: data.value,
375
+ select,
376
+ isActive: data.value.active
377
+ }, slots);
378
+ }
379
+ const linkProps = {
380
+ active: data.value.active,
381
+ disabled: false,
382
+ prefetch: true
383
+ };
384
+ if (data.value.url) {
385
+ if (isAbsoluteURL(data.value.url) || data.value.url.startsWith('#')) {
386
+ linkProps.href = data.value.url;
387
+ if (data.value.urlTarget) {
388
+ linkProps.target = data.value.urlTarget;
307
389
  }
308
- break;
390
+ } else {
391
+ linkProps.to = data.value.url;
309
392
  }
310
- default:
311
- {
312
- if (typeof component.value.children === 'undefined') {
313
- const hasSlot = hasNormalizedSlot(SlotName.LINK, slots);
314
- if (hasSlot) {
315
- item = normalizeSlot(SlotName.LINK, {
316
- component: component.value,
317
- selectComponent,
318
- isActive: component.value.active
319
- }, slots);
320
- } else {
321
- const linkProps = {
322
- active: component.value.active,
323
- disabled: false,
324
- prefetch: true
325
- };
326
- if (component.value.url) {
327
- if (isAbsoluteURL(component.value.url) || component.value.url.startsWith('#')) {
328
- linkProps.href = component.value.url;
329
- if (component.value.urlTarget) {
330
- linkProps.target = component.value.urlTarget;
331
- }
332
- } else {
333
- linkProps.to = component.value.url;
334
- }
335
- }
336
- item = h(VCLink, {
337
- class: [
338
- 'nav-link',
339
- {
340
- 'root-link': component.value.root
341
- }
342
- ],
343
- ...linkProps,
344
- onClicked () {
345
- if (!component.value.url) {
346
- return selectComponent.call(null, component.value);
347
- }
348
- return undefined;
349
- },
350
- onClick () {
351
- return selectComponent.call(null, component.value);
352
- }
353
- }, {
354
- default: ()=>[
355
- ...component.value.icon ? [
356
- h('i', {
357
- class: component.value.icon
358
- })
359
- ] : [],
360
- h('span', {
361
- class: 'nav-link-text'
362
- }, [
363
- component.value.name
364
- ])
365
- ]
366
- });
367
- }
368
- } else if (hasNormalizedSlot(SlotName.SUB, slots)) {
369
- item = normalizeSlot(SlotName.SUB, {
370
- component: component.value,
371
- selectComponent,
372
- toggleComponentExpansion
373
- }, slots);
374
- } else {
375
- let title;
376
- if (hasNormalizedSlot(SlotName.SUB_TITLE, slots)) {
377
- title = normalizeSlot(SlotName.SUB_TITLE, {
378
- component: component.value,
379
- selectComponent,
380
- toggleComponentExpansion
381
- });
382
- } else {
383
- title = h('div', {
384
- class: 'nav-sub-title',
385
- onClick ($event) {
386
- $event.preventDefault();
387
- return toggleComponentExpansion.call(null, component.value);
388
- }
389
- }, [
390
- [
391
- ...component.value.icon ? [
392
- h('i', {
393
- class: component.value.icon
394
- })
395
- ] : [],
396
- h('span', {
397
- class: 'nav-link-text'
398
- }, [
399
- component.value.name
400
- ])
401
- ]
402
- ]);
403
- }
404
- let items;
405
- if (hasNormalizedSlot(SlotName.SUB_ITEMS, slots)) {
406
- items = normalizeSlot(SlotName.SUB_ITEMS, {
407
- component: component.value,
408
- selectComponent,
409
- toggleComponentExpansion
410
- });
411
- } else if (component.value.displayChildren) {
412
- const navigationComponents = resolveComponent('VCNavItems');
413
- items = h(navigationComponents, {
414
- class: 'list-unstyled nav-sub-items',
415
- tier: props.tier,
416
- entities: component.value.children
417
- });
418
- }
419
- item = [
420
- title,
421
- items
422
- ];
393
+ }
394
+ return h(VCLink, {
395
+ class: [
396
+ options.linkClass,
397
+ data.value.url && data.value.url === '/' ? [
398
+ options.linkRootClass
399
+ ] : []
400
+ ],
401
+ ...linkProps,
402
+ onClicked () {
403
+ if (!data.value.url) {
404
+ return select.call(null, data.value);
423
405
  }
424
- break;
406
+ return undefined;
407
+ },
408
+ onClick () {
409
+ return select.call(null, data.value);
425
410
  }
411
+ }, {
412
+ default: ()=>[
413
+ ...data.value.icon ? [
414
+ h('i', {
415
+ class: data.value.icon
416
+ })
417
+ ] : [],
418
+ h(options.linkTextTag, {
419
+ class: options.linkTextClass
420
+ }, [
421
+ data.value.name
422
+ ])
423
+ ]
424
+ });
425
+ }
426
+ if (hasNormalizedSlot(SlotName.SUB, slots)) {
427
+ return normalizeSlot(SlotName.SUB, {
428
+ data: data.value,
429
+ select,
430
+ toggle
431
+ }, slots);
432
+ }
433
+ let title;
434
+ if (hasNormalizedSlot(SlotName.SUB_TITLE, slots)) {
435
+ title = normalizeSlot(SlotName.SUB_TITLE, {
436
+ data: data.value,
437
+ select,
438
+ toggle
439
+ });
440
+ } else {
441
+ title = h('div', {
442
+ class: options.subGroupTitleClass,
443
+ onClick ($event) {
444
+ $event.preventDefault();
445
+ return toggle(data.value);
446
+ }
447
+ }, [
448
+ [
449
+ ...data.value.icon ? [
450
+ h('i', {
451
+ class: data.value.icon
452
+ })
453
+ ] : [],
454
+ h(options.linkTextTag, {
455
+ class: options.linkTextClass
456
+ }, [
457
+ data.value.name
458
+ ])
459
+ ]
460
+ ]);
461
+ }
462
+ if (!data.value.displayChildren) {
463
+ return title;
426
464
  }
427
- return item;
465
+ let vNodes;
466
+ if (hasNormalizedSlot(SlotName.SUB_ITEMS, slots)) {
467
+ vNodes = normalizeSlot(SlotName.SUB_ITEMS, {
468
+ data: data.value,
469
+ select,
470
+ toggle
471
+ });
472
+ } else {
473
+ vNodes = h(itemsNode, {
474
+ level: data.value.level,
475
+ data: data.value.children
476
+ });
477
+ }
478
+ return [
479
+ title,
480
+ vNodes
481
+ ];
428
482
  };
429
- return h('div', {
483
+ return h(options.itemTag, {
430
484
  class: [
431
- 'nav-item',
485
+ options.itemClass,
432
486
  {
433
- active: component.value.active || component.value.displayChildren
487
+ active: data.value.active || data.value.displayChildren
434
488
  }
435
489
  ]
436
490
  }, [
@@ -442,127 +496,76 @@ const VCNavItem = defineComponent({
442
496
 
443
497
  const VCNavItems = defineComponent({
444
498
  props: {
445
- tier: {
499
+ level: {
446
500
  type: Number,
447
501
  default: 0
448
502
  },
449
- entities: {
503
+ data: {
450
504
  type: Array,
451
505
  default: undefined
452
506
  }
453
507
  },
454
508
  setup (props, { slots }) {
455
- const store = injectStore();
456
- const items = computed(()=>{
457
- if (typeof props.entities !== 'undefined') {
458
- return props.entities;
459
- }
460
- return findNavigationItemsForTier(store.items.value, props.tier);
461
- });
462
- const buildChild = (context)=>{
463
- if (hasNormalizedSlot(SlotName.ITEM, slots)) {
464
- return normalizeSlot(SlotName.ITEM, context, slots);
465
- }
466
- return h(VCNavItem, context);
467
- };
468
- const buildChildren = ()=>{
469
- const entities = [];
470
- if (items.value) {
471
- for(let i = 0; i < items.value.length; i++){
472
- if (items.value[i].display) {
473
- entities.push(h('li', {
474
- key: i
475
- }, [
476
- buildChild({
477
- tier: props.tier,
478
- component: items.value[i]
479
- })
480
- ]));
481
- }
509
+ const options = buildComponentOptions();
510
+ const manager = injectNavigationManager();
511
+ const managerItems = ref([]);
512
+ if (!props.data) {
513
+ managerItems.value = manager.getItems(props.level);
514
+ }
515
+ const counter = ref(0);
516
+ let removeListener;
517
+ onMounted(()=>{
518
+ removeListener = manager.on('tierUpdated', (tier, items)=>{
519
+ if (tier !== props.level) {
520
+ return;
482
521
  }
522
+ managerItems.value = items;
523
+ counter.value++;
524
+ });
525
+ });
526
+ onUnmounted(()=>{
527
+ if (typeof removeListener === 'function') {
528
+ removeListener();
529
+ removeListener = undefined;
483
530
  }
484
- return entities;
485
- };
486
- return ()=>h('ul', {
487
- class: 'nav-items'
488
- }, [
489
- buildChildren()
490
- ]);
491
- }
492
- });
493
-
494
- async function buildNavigation(context = {}) {
495
- const store = injectStore();
496
- const navigationProvider = useNavigationProvider();
497
- let itemsActive = [];
498
- if (typeof context.itemsActive !== 'undefined') {
499
- itemsActive = context.itemsActive;
500
- } else if (context.route) {
501
- if (typeof navigationProvider.getItemsActiveByRoute !== 'undefined') {
502
- itemsActive = await navigationProvider.getItemsActiveByRoute(context.route);
503
- } else if (typeof navigationProvider.getItemsActiveByURL !== 'undefined') {
504
- itemsActive = await navigationProvider.getItemsActiveByURL(context.route.fullPath);
505
- }
506
- } else if (context.url && typeof navigationProvider.getItemsActiveByURL !== 'undefined') {
507
- itemsActive = await navigationProvider.getItemsActiveByURL(context.url);
508
- }
509
- if (itemsActive.length > 0) {
510
- for(let i = 0; i < itemsActive.length; i++){
511
- if (typeof itemsActive[i].tier === 'undefined') {
512
- itemsActive[i].tier = i;
531
+ });
532
+ const items = computed(()=>{
533
+ if (typeof props.data !== 'undefined') {
534
+ return props.data;
513
535
  }
514
- }
515
- }
516
- let tierIndex = 0;
517
- let url;
518
- if (typeof context.url === 'string') {
519
- url = context.url;
520
- } else if (typeof context.route !== 'undefined') {
521
- url = context.route.fullPath;
522
- }
523
- // eslint-disable-next-line no-constant-condition
524
- while(true){
525
- let items = await navigationProvider.getItems(tierIndex, itemsActive);
526
- if (!items || items.length === 0) {
527
- break;
528
- }
529
- // ensure tier property
530
- items = setTierForNavigationItems(items, tierIndex);
531
- let currentItem = findNavigationItemForTier(itemsActive, tierIndex);
532
- if (!currentItem) {
533
- if (url) {
534
- const urlMatches = items.filter((item)=>isNavigationItemMatch(item, {
535
- url
536
- }));
537
- if (urlMatches.length > 0) {
538
- [currentItem] = urlMatches;
536
+ return managerItems.value;
537
+ });
538
+ return ()=>{
539
+ const vNodes = [];
540
+ for(let i = 0; i < items.value.length; i++){
541
+ if (!items.value[i].display && !items.value[i].displayChildren) {
542
+ continue;
539
543
  }
540
- }
541
- if (!currentItem) {
542
- const defaultItem = items.filter((item)=>item.default);
543
- if (defaultItem.length > 0) {
544
- currentItem = defaultItem;
544
+ let vNode;
545
+ if (hasNormalizedSlot(SlotName.ITEM, slots)) {
546
+ vNode = normalizeSlot(SlotName.ITEM, {
547
+ data: items.value[i]
548
+ }, slots);
545
549
  } else {
546
- [currentItem] = items;
550
+ vNode = h(VCNavItem, {
551
+ key: `${i}:${counter.value}`,
552
+ data: items.value[i]
553
+ });
547
554
  }
555
+ vNodes.push(vNode);
548
556
  }
549
- currentItem.tier = tierIndex;
550
- itemsActive.push(currentItem);
551
- }
552
- if (!currentItem) {
553
- continue;
554
- }
555
- replaceNavigationTierItemActive(store, tierIndex, currentItem);
556
- await buildNavigationForTier(store, tierIndex, itemsActive);
557
- tierIndex++;
557
+ return h(options.groupTag, {
558
+ class: props.data ? options.subGroupItemsClass : options.groupClass
559
+ }, vNodes);
560
+ };
558
561
  }
559
- }
562
+ });
560
563
 
561
564
  function install(instance, options) {
562
- if (options.provider) {
563
- setNavigationProvider(options.provider);
564
- }
565
- setupStore(instance);
565
+ const manager = new NavigationManager({
566
+ items: options.items
567
+ });
568
+ provideNavigationManager(manager, instance);
566
569
  const storeManager = installStoreManager(instance);
567
570
  if (options.storeManager) {
568
571
  applyStoreManagerOptions(storeManager, options.storeManager);
@@ -578,5 +581,5 @@ var index = {
578
581
  install
579
582
  };
580
583
 
581
- export { VCNavItem, VCNavItems, buildNavigation, buildNavigationForTier, createNavigationProvider, index as default, flattenNestedNavigationItems, install, setNavigationProvider, useNavigationProvider };
584
+ export { NavigationManager, VCNavItem, VCNavItems, index as default, injectNavigationManager, install, provideNavigationManager };
582
585
  //# sourceMappingURL=index.mjs.map