@vuecs/navigation 1.1.0 → 2.0.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 (100) hide show
  1. package/README.md +54 -142
  2. package/core/index.cjs +1 -1
  3. package/core/index.mjs +1 -1
  4. package/dist/components/index.d.ts +1 -1
  5. package/dist/components/index.d.ts.map +1 -1
  6. package/dist/components/item/index.d.ts +2 -0
  7. package/dist/components/item/index.d.ts.map +1 -0
  8. package/dist/components/item/module.d.ts +16 -0
  9. package/dist/components/item/module.d.ts.map +1 -0
  10. package/dist/components/items/index.d.ts +2 -0
  11. package/dist/components/items/index.d.ts.map +1 -0
  12. package/dist/components/items/module.d.ts +27 -0
  13. package/dist/components/items/module.d.ts.map +1 -0
  14. package/dist/helpers/component/build.d.ts +3 -0
  15. package/dist/helpers/component/build.d.ts.map +1 -0
  16. package/dist/helpers/component/index.d.ts +3 -0
  17. package/dist/helpers/component/index.d.ts.map +1 -0
  18. package/dist/helpers/component/types.d.ts +17 -0
  19. package/dist/helpers/component/types.d.ts.map +1 -0
  20. package/dist/helpers/index.d.ts +8 -0
  21. package/dist/helpers/index.d.ts.map +1 -0
  22. package/dist/helpers/level.d.ts +11 -0
  23. package/dist/helpers/level.d.ts.map +1 -0
  24. package/dist/helpers/match.d.ts +7 -0
  25. package/dist/helpers/match.d.ts.map +1 -0
  26. package/dist/helpers/normalize.d.ts +8 -0
  27. package/dist/helpers/normalize.d.ts.map +1 -0
  28. package/dist/helpers/reset.d.ts +3 -0
  29. package/dist/helpers/reset.d.ts.map +1 -0
  30. package/dist/helpers/trace.d.ts +3 -0
  31. package/dist/helpers/trace.d.ts.map +1 -0
  32. package/dist/helpers/url.d.ts.map +1 -0
  33. package/dist/index.cjs +455 -459
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.css +87 -0
  36. package/dist/index.d.ts +4 -6
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.mjs +454 -455
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/manager/index.d.ts +4 -0
  41. package/dist/manager/index.d.ts.map +1 -0
  42. package/dist/manager/module.d.ts +19 -0
  43. package/dist/manager/module.d.ts.map +1 -0
  44. package/dist/manager/singleton.d.ts +5 -0
  45. package/dist/manager/singleton.d.ts.map +1 -0
  46. package/dist/manager/types.d.ts +8 -0
  47. package/dist/manager/types.d.ts.map +1 -0
  48. package/dist/types.d.ts +33 -0
  49. package/dist/types.d.ts.map +1 -0
  50. package/package.json +10 -6
  51. package/dist/components/item.d.ts +0 -26
  52. package/dist/components/item.d.ts.map +0 -1
  53. package/dist/components/items.d.ts +0 -27
  54. package/dist/components/items.d.ts.map +0 -1
  55. package/dist/core/build.d.ts +0 -4
  56. package/dist/core/build.d.ts.map +0 -1
  57. package/dist/core/check.d.ts +0 -3
  58. package/dist/core/check.d.ts.map +0 -1
  59. package/dist/core/expansion.d.ts +0 -6
  60. package/dist/core/expansion.d.ts.map +0 -1
  61. package/dist/core/flatten.d.ts +0 -3
  62. package/dist/core/flatten.d.ts.map +0 -1
  63. package/dist/core/index.d.ts +0 -12
  64. package/dist/core/index.d.ts.map +0 -1
  65. package/dist/core/match.d.ts +0 -3
  66. package/dist/core/match.d.ts.map +0 -1
  67. package/dist/core/reduce.d.ts +0 -8
  68. package/dist/core/reduce.d.ts.map +0 -1
  69. package/dist/core/refresh.d.ts +0 -3
  70. package/dist/core/refresh.d.ts.map +0 -1
  71. package/dist/core/replace.d.ts +0 -6
  72. package/dist/core/replace.d.ts.map +0 -1
  73. package/dist/core/reset.d.ts +0 -3
  74. package/dist/core/reset.d.ts.map +0 -1
  75. package/dist/core/select.d.ts +0 -4
  76. package/dist/core/select.d.ts.map +0 -1
  77. package/dist/core/tier.d.ts +0 -7
  78. package/dist/core/tier.d.ts.map +0 -1
  79. package/dist/core/toggle.d.ts +0 -4
  80. package/dist/core/toggle.d.ts.map +0 -1
  81. package/dist/module.d.ts +0 -3
  82. package/dist/module.d.ts.map +0 -1
  83. package/dist/provider/index.d.ts +0 -3
  84. package/dist/provider/index.d.ts.map +0 -1
  85. package/dist/provider/module.d.ts +0 -5
  86. package/dist/provider/module.d.ts.map +0 -1
  87. package/dist/provider/type.d.ts +0 -8
  88. package/dist/provider/type.d.ts.map +0 -1
  89. package/dist/store/index.d.ts +0 -3
  90. package/dist/store/index.d.ts.map +0 -1
  91. package/dist/store/module.d.ts +0 -7
  92. package/dist/store/module.d.ts.map +0 -1
  93. package/dist/store/type.d.ts +0 -16
  94. package/dist/store/type.d.ts.map +0 -1
  95. package/dist/type.d.ts +0 -27
  96. package/dist/type.d.ts.map +0 -1
  97. package/dist/utils/index.d.ts +0 -2
  98. package/dist/utils/index.d.ts.map +0 -1
  99. package/dist/utils/url.d.ts.map +0 -1
  100. /package/dist/{utils → helpers}/url.d.ts +0 -0
package/dist/index.mjs CHANGED
@@ -1,436 +1,487 @@
1
- import { hasNormalizedSlot, normalizeSlot, applyStoreManagerOptions, installStoreManager } 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 build(options) {
193
+ if (this.built) {
194
+ return this.items;
195
+ }
196
+ this.built = true;
197
+ this.items = [];
198
+ this.itemsActive = [];
199
+ let parent;
200
+ let level = 0;
201
+ while(true){
202
+ const raw = await this.itemsFn({
203
+ level,
204
+ parent
205
+ });
206
+ if (!raw || raw.length === 0) {
207
+ break;
208
+ }
209
+ const items = normalizeItems(raw, {
210
+ level
211
+ });
212
+ const matches = findBestItemMatches(items, {
213
+ path: options.path
214
+ });
215
+ const [match] = matches;
216
+ if (!match) {
198
217
  break;
199
218
  }
200
- itemsActive.push(component);
201
- tierStartIndex++;
219
+ this.itemsActive.push(match);
220
+ await this.buildLevel(level);
221
+ parent = match;
222
+ level++;
202
223
  }
224
+ this.emit('updated', this.items);
225
+ return this.items;
203
226
  }
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
- ]));
227
+ async select(level, itemNew) {
228
+ const itemOld = findItemWithLevel(level, this.itemsActive);
229
+ if (itemOld && isTraceEqual(itemOld.trace, itemNew.trace)) {
230
+ return;
231
+ }
232
+ this.itemsActive = this.itemsActive.filter((el)=>el.level < level);
233
+ this.itemsActive.push(itemNew);
234
+ const startLevel = level;
235
+ while(true){
236
+ const built = await this.buildLevel(level, startLevel === level);
237
+ if (!built) {
238
+ break;
239
+ }
240
+ level++;
222
241
  }
223
242
  }
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;
243
+ async toggle(level, item) {
244
+ let isMatch;
245
+ if (item.displayChildren) {
246
+ isMatch = true;
247
+ } else {
248
+ const itemOld = findItemWithLevel(level, this.itemsActive);
249
+ isMatch = !!itemOld && isTraceEqual(item.trace, itemOld.trace);
250
+ }
251
+ if (isMatch) {
252
+ this.itemsActive = removeItemsWithLevel(level, this.itemsActive);
253
+ } else {
254
+ this.itemsActive = replaceLevelItem(level, this.itemsActive, item);
255
+ }
256
+ await this.buildLevel(level, true);
257
+ }
258
+ async buildLevel(level, cached) {
259
+ let items;
260
+ if (cached) {
261
+ items = findItemsWithLevel(this.items, level);
262
+ } else {
263
+ const parent = findItemWithLevel(level - 1, this.itemsActive);
264
+ const raw = await this.itemsFn({
265
+ level,
266
+ parent
267
+ });
268
+ items = raw && raw.length > 0 ? normalizeItems(raw, {
269
+ level
270
+ }) : [];
271
+ }
272
+ if (!items || items.length === 0) {
273
+ this.items = this.items.filter((item)=>item.level < level);
274
+ this.emit('tierUpdated', level, []);
275
+ return false;
276
+ }
277
+ let trace = [];
278
+ const item = findItemWithLevel(level, this.itemsActive);
279
+ if (item) {
280
+ trace = item.trace;
281
+ }
282
+ resetItemsByTrace(items, trace);
283
+ this.items = replaceLevelItems(level, this.items, items);
284
+ this.emit('tierUpdated', level, items);
285
+ return true;
231
286
  }
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;
287
+ constructor(options){
288
+ super();
289
+ let itemsFn;
290
+ if (typeof options.items === 'function') {
291
+ itemsFn = options.items;
292
+ } else {
293
+ itemsFn = async ({ level })=>{
294
+ if (level > 0) {
295
+ return [];
296
+ }
297
+ return options.items;
298
+ };
240
299
  }
241
- tier++;
300
+ this.itemsFn = itemsFn;
301
+ this.items = [];
302
+ this.itemsActive = [];
303
+ this.built = false;
242
304
  }
243
305
  }
244
306
 
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);
307
+ const sym = Symbol.for('VCNavigationManager');
308
+ function injectNavigationManager(app) {
309
+ const instance = inject(sym, app);
310
+ if (!instance) {
311
+ throw new Error('A navigation provider has not been provided.');
251
312
  }
252
- refreshNavigationTierItems(store, tier);
313
+ return instance;
253
314
  }
254
-
255
- function isAbsoluteURL(str) {
256
- return str.substring(0, 7) === 'http://' || str.substring(0, 8) === 'https://';
315
+ function provideNavigationManager(manager, app) {
316
+ provide(sym, manager, app);
257
317
  }
258
318
 
259
- var SlotName;
260
- (function(SlotName) {
319
+ var SlotName = /*#__PURE__*/ function(SlotName) {
261
320
  SlotName["ITEM"] = "item";
262
321
  SlotName["SEPARATOR"] = "separator";
263
322
  SlotName["LINK"] = "link";
264
323
  SlotName["SUB"] = "sub";
265
324
  SlotName["SUB_TITLE"] = "sub-title";
266
325
  SlotName["SUB_ITEMS"] = "sub-items";
267
- })(SlotName || (SlotName = {}));
268
- var ElementType;
269
- (function(ElementType) {
326
+ return SlotName;
327
+ }({});
328
+ var ElementType = /*#__PURE__*/ function(ElementType) {
270
329
  ElementType["LINK"] = "link";
271
330
  ElementType["SEPARATOR"] = "separator";
272
- })(ElementType || (ElementType = {}));
331
+ return ElementType;
332
+ }({});
273
333
 
274
334
  const VCNavItem = defineComponent({
275
335
  props: {
276
- tier: {
277
- type: Number,
278
- default: 0
279
- },
280
- component: {
336
+ data: {
281
337
  type: Object,
282
338
  required: true
283
339
  }
284
340
  },
285
341
  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);
342
+ const itemsNode = resolveComponent('VCNavItems');
343
+ const options = buildComponentOptions();
344
+ const manager = injectNavigationManager();
345
+ const data = toRef(props, 'data');
346
+ const select = async (value)=>{
347
+ await manager.select(data.value.level, value);
348
+ };
349
+ const toggle = async (value)=>{
350
+ await manager.toggle(data.value.level, value);
290
351
  };
291
- const toggleComponentExpansion = async (value)=>toggleNavigation(store, props.tier, value);
292
352
  return ()=>{
293
353
  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);
354
+ // type: separator
355
+ if (data.value.type === ElementType.SEPARATOR) {
356
+ const hasSlot = hasNormalizedSlot(SlotName.SEPARATOR, slots);
357
+ if (hasSlot) {
358
+ return normalizeSlot(SlotName.SEPARATOR, {
359
+ data: data.value
360
+ }, slots);
361
+ }
362
+ return h(options.separatorTag, {
363
+ class: options.separatorClass
364
+ }, data.value.name);
365
+ }
366
+ // type: group
367
+ if (!data.value.children || data.value.children.length === 0) {
368
+ const hasSlot = hasNormalizedSlot(SlotName.LINK, slots);
369
+ if (hasSlot) {
370
+ return normalizeSlot(SlotName.LINK, {
371
+ data: data.value,
372
+ select,
373
+ isActive: data.value.active
374
+ }, slots);
375
+ }
376
+ const linkProps = {
377
+ active: data.value.active,
378
+ disabled: false,
379
+ prefetch: true
380
+ };
381
+ if (data.value.url) {
382
+ if (isAbsoluteURL(data.value.url) || data.value.url.startsWith('#')) {
383
+ linkProps.href = data.value.url;
384
+ if (data.value.urlTarget) {
385
+ linkProps.target = data.value.urlTarget;
307
386
  }
308
- break;
387
+ } else {
388
+ linkProps.to = data.value.url;
309
389
  }
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
- ];
390
+ }
391
+ return h(VCLink, {
392
+ class: [
393
+ options.linkClass,
394
+ data.value.url && data.value.url === '/' ? [
395
+ options.linkRootClass
396
+ ] : []
397
+ ],
398
+ ...linkProps,
399
+ onClicked () {
400
+ if (!data.value.url) {
401
+ return select.call(null, data.value);
423
402
  }
424
- break;
403
+ return undefined;
404
+ },
405
+ onClick () {
406
+ return select.call(null, data.value);
425
407
  }
408
+ }, {
409
+ default: ()=>[
410
+ ...data.value.icon ? [
411
+ h('i', {
412
+ class: data.value.icon
413
+ })
414
+ ] : [],
415
+ h(options.linkTextTag, {
416
+ class: options.linkTextClass
417
+ }, [
418
+ data.value.name
419
+ ])
420
+ ]
421
+ });
422
+ }
423
+ if (hasNormalizedSlot(SlotName.SUB, slots)) {
424
+ return normalizeSlot(SlotName.SUB, {
425
+ data: data.value,
426
+ select,
427
+ toggle
428
+ }, slots);
429
+ }
430
+ let title;
431
+ if (hasNormalizedSlot(SlotName.SUB_TITLE, slots)) {
432
+ title = normalizeSlot(SlotName.SUB_TITLE, {
433
+ data: data.value,
434
+ select,
435
+ toggle
436
+ });
437
+ } else {
438
+ title = h('div', {
439
+ class: options.subGroupTitleClass,
440
+ onClick ($event) {
441
+ $event.preventDefault();
442
+ return toggle(data.value);
443
+ }
444
+ }, [
445
+ [
446
+ ...data.value.icon ? [
447
+ h('i', {
448
+ class: data.value.icon
449
+ })
450
+ ] : [],
451
+ h(options.linkTextTag, {
452
+ class: options.linkTextClass
453
+ }, [
454
+ data.value.name
455
+ ])
456
+ ]
457
+ ]);
458
+ }
459
+ if (!data.value.displayChildren) {
460
+ return title;
426
461
  }
427
- return item;
462
+ let vNodes;
463
+ if (hasNormalizedSlot(SlotName.SUB_ITEMS, slots)) {
464
+ vNodes = normalizeSlot(SlotName.SUB_ITEMS, {
465
+ data: data.value,
466
+ select,
467
+ toggle
468
+ });
469
+ } else {
470
+ vNodes = h(itemsNode, {
471
+ level: data.value.level,
472
+ data: data.value.children
473
+ });
474
+ }
475
+ return [
476
+ title,
477
+ vNodes
478
+ ];
428
479
  };
429
- return h('div', {
480
+ return h(options.itemTag, {
430
481
  class: [
431
- 'nav-item',
482
+ options.itemClass,
432
483
  {
433
- active: component.value.active || component.value.displayChildren
484
+ active: data.value.active || data.value.displayChildren
434
485
  }
435
486
  ]
436
487
  }, [
@@ -442,131 +493,79 @@ const VCNavItem = defineComponent({
442
493
 
443
494
  const VCNavItems = defineComponent({
444
495
  props: {
445
- tier: {
496
+ level: {
446
497
  type: Number,
447
498
  default: 0
448
499
  },
449
- entities: {
500
+ data: {
450
501
  type: Array,
451
502
  default: undefined
452
503
  }
453
504
  },
454
505
  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
- }
506
+ const options = buildComponentOptions();
507
+ const manager = injectNavigationManager();
508
+ const managerItems = ref([]);
509
+ if (!props.data) {
510
+ managerItems.value = manager.getItems(props.level);
511
+ }
512
+ const counter = ref(0);
513
+ let removeListener;
514
+ onMounted(()=>{
515
+ removeListener = manager.on('tierUpdated', (tier, items)=>{
516
+ if (tier !== props.level) {
517
+ return;
482
518
  }
519
+ managerItems.value = items;
520
+ counter.value++;
521
+ });
522
+ });
523
+ onUnmounted(()=>{
524
+ if (typeof removeListener === 'function') {
525
+ removeListener();
526
+ removeListener = undefined;
483
527
  }
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;
528
+ });
529
+ const items = computed(()=>{
530
+ if (typeof props.data !== 'undefined') {
531
+ return props.data;
513
532
  }
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;
533
+ return managerItems.value;
534
+ });
535
+ return ()=>{
536
+ const vNodes = [];
537
+ for(let i = 0; i < items.value.length; i++){
538
+ if (!items.value[i].display && !items.value[i].displayChildren) {
539
+ continue;
539
540
  }
540
- }
541
- if (!currentItem) {
542
- const defaultItem = items.filter((item)=>item.default);
543
- if (defaultItem.length > 0) {
544
- currentItem = defaultItem;
541
+ let vNode;
542
+ if (hasNormalizedSlot(SlotName.ITEM, slots)) {
543
+ vNode = normalizeSlot(SlotName.ITEM, {
544
+ data: items.value[i]
545
+ }, slots);
545
546
  } else {
546
- [currentItem] = items;
547
+ vNode = h(VCNavItem, {
548
+ key: `${i}:${counter.value}`,
549
+ data: items.value[i]
550
+ });
547
551
  }
552
+ vNodes.push(vNode);
548
553
  }
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++;
554
+ return h(options.groupTag, {
555
+ class: props.data ? options.subGroupItemsClass : options.groupClass
556
+ }, vNodes);
557
+ };
558
558
  }
559
- }
559
+ });
560
560
 
561
561
  function install(instance, options) {
562
- if (options.provider) {
563
- setNavigationProvider(options.provider);
564
- }
565
- setupStore(instance);
562
+ const manager = new NavigationManager({
563
+ items: options.items
564
+ });
565
+ provideNavigationManager(manager, instance);
566
+ const storeManager = installStoreManager(instance);
566
567
  if (options.storeManager) {
567
- applyStoreManagerOptions(instance, options.storeManager);
568
- } else {
569
- installStoreManager(instance);
568
+ applyStoreManagerOptions(storeManager, options.storeManager);
570
569
  }
571
570
  Object.entries({
572
571
  VCNavItem,
@@ -579,5 +578,5 @@ var index = {
579
578
  install
580
579
  };
581
580
 
582
- export { VCNavItem, VCNavItems, buildNavigation, buildNavigationForTier, createNavigationProvider, index as default, flattenNestedNavigationItems, install, setNavigationProvider, useNavigationProvider };
581
+ export { NavigationManager, VCNavItem, VCNavItems, index as default, injectNavigationManager, install, provideNavigationManager };
583
582
  //# sourceMappingURL=index.mjs.map