zova-module-a-routertabs 5.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016-present Zova
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.js ADDED
@@ -0,0 +1,429 @@
1
+ import { BeanInfo, BeanScopeBase, Use, deepEqual, deepExtend, prepareComponentOptions, useComputed, useController } from "zova";
2
+ import { mutate } from "mutate-on-copy";
3
+ import { BeanModelBase, Model } from "zova-module-a-model";
4
+ import { Controller, Scope } from "zova-module-a-bean";
5
+ import { BeanRouterViewBase } from "zova-module-a-router";
6
+ import { defineComponent } from "vue";
7
+ //#region src/model/tabs.ts
8
+ var _dec$2, _dec2$2, _class$2;
9
+ var ModelTabs$1 = (_dec$2 = Model({
10
+ enableSelector: true,
11
+ max: -1,
12
+ maxItems: -1,
13
+ cache: false
14
+ }), _dec2$2 = BeanInfo({ module: "a-routertabs" }), _dec$2(_class$2 = _dec2$2(_class$2 = class ModelTabs extends BeanModelBase {
15
+ constructor(...args) {
16
+ super(...args);
17
+ this.tabsOptions = void 0;
18
+ this.tabs = void 0;
19
+ this.componentKeyCurrent = void 0;
20
+ this.tabKeyCurrent = void 0;
21
+ this.tabCurrentIndex = void 0;
22
+ this.tabCurrent = void 0;
23
+ this.keepAliveInclude = void 0;
24
+ this._eventSsrHmrReload = void 0;
25
+ }
26
+ async __init__(scene, options) {
27
+ await super.__init__(scene);
28
+ this.bean._setBean("$$modelTabs", this);
29
+ this.tabsOptions = deepExtend({}, this.$onionOptions, options);
30
+ this.tabCurrentIndex = useComputed(() => {
31
+ const [index] = this.findTab(this.tabKeyCurrent);
32
+ return index;
33
+ });
34
+ this.tabCurrent = useComputed(() => {
35
+ const [, tab] = this.findTab(this.tabKeyCurrent);
36
+ return tab;
37
+ });
38
+ this.keepAliveInclude = useComputed(() => {
39
+ return this._getKeepAliveInclude();
40
+ });
41
+ this.componentKeyCurrent = this.$useStateMem({ queryKey: ["componentKeyCurrent"] });
42
+ this.tabKeyCurrent = this.$useStateMem({ queryKey: ["tabKeyCurrent"] });
43
+ const queryOptionsTabs = {
44
+ queryKey: ["tabs"],
45
+ meta: { defaultData: this._getInitialTabs() }
46
+ };
47
+ if (this.tabsOptions.cache) this.tabs = this.$useStateDb(queryOptionsTabs);
48
+ else this.tabs = this.$useStateMem(queryOptionsTabs);
49
+ if (this.tabsOptions.cache) await this.$loadStateDb(this.tabs);
50
+ if (this.$currentRoute) this.forwardRoute(this.$currentRoute);
51
+ if (process.env.CLIENT && this.sys.env.SSR_HMR === "true") this._eventSsrHmrReload = this.sys.meta.event.on("a-ssrhmr:reload", async (_data, next) => {
52
+ this.updateAllTabInfos();
53
+ return next();
54
+ });
55
+ this.$watch(() => {
56
+ return this.app.meta.locale.current;
57
+ }, () => {
58
+ this.updateAllTabInfos();
59
+ });
60
+ }
61
+ __dispose__() {
62
+ if (this._eventSsrHmrReload) this._eventSsrHmrReload();
63
+ }
64
+ get cache() {
65
+ return this.tabsOptions.cache;
66
+ }
67
+ addTab(tab, affix) {
68
+ const res = this._addTab(tab, affix);
69
+ this.tabKeyCurrent = res ? tab.tabKey : void 0;
70
+ this.componentKeyCurrent = res ? tab.componentKey : void 0;
71
+ return res;
72
+ }
73
+ _addTab(tab, affix) {
74
+ const tabKey = tab.tabKey;
75
+ if (!tabKey) return false;
76
+ const [index, tabOld] = this.findTab(tabKey);
77
+ const tabInfo = this.tabsOptions.getTabInfo?.(tabKey) ?? tabOld?.info;
78
+ if (!tabInfo) return false;
79
+ if (index === -1) {
80
+ const tabNew = {
81
+ tabKey,
82
+ affix,
83
+ items: tab.componentKey ? [{
84
+ componentKey: tab.componentKey,
85
+ fullPath: tab.fullPath,
86
+ keepAlive: tab.keepAlive,
87
+ updatedAt: Date.now()
88
+ }] : [],
89
+ updatedAt: Date.now(),
90
+ info: tabInfo
91
+ };
92
+ if (this.tabCurrentIndex === -1) this.tabs = mutate(this.tabs, (copyState) => {
93
+ copyState.push(tabNew);
94
+ });
95
+ else this.tabs = mutate(this.tabs, (copyState) => {
96
+ copyState.splice(this.tabCurrentIndex + 1, 0, tabNew);
97
+ });
98
+ this.pruneTabs();
99
+ } else {
100
+ if (!deepEqual(tabInfo, tabOld?.info)) this.updateTabInfo(tabKey);
101
+ if (!this._checkIfTabNeedUpdate(tabOld, tab)) return true;
102
+ this.updateTab(tab);
103
+ this.pruneTabItems(tabKey);
104
+ }
105
+ return true;
106
+ }
107
+ updateAllTabInfos(tabInitials) {
108
+ for (const tab of this.tabs) {
109
+ const tabInitial = tabInitials?.find((item) => item.tabKey === tab.tabKey);
110
+ this.updateTabInfo(tab.tabKey, tabInitial);
111
+ }
112
+ }
113
+ updateTabInfo(tabKey, tabInitial) {
114
+ if (!tabKey) return;
115
+ const [index, tabOld] = this.findTab(tabKey);
116
+ if (index === -1) return;
117
+ const tabInfo = this.tabsOptions.getTabInfo ? this.tabsOptions.getTabInfo(tabKey) : tabInitial?.info ?? tabOld?.info;
118
+ if (!tabInfo) return;
119
+ const tabNew = {
120
+ ...tabOld,
121
+ info: tabInfo
122
+ };
123
+ this.updateTab(tabNew);
124
+ }
125
+ updateTabItemPageMeta(tabKey, componentKey, pageMeta) {
126
+ if (!tabKey || !componentKey) return false;
127
+ const [index, tab] = this.findTab(tabKey);
128
+ if (index === -1 || !tab) return false;
129
+ if (!tab.items) return false;
130
+ const indexItem = tab.items.findIndex((item) => item.componentKey === componentKey);
131
+ if (indexItem === -1) return false;
132
+ const tabItem = tab.items[indexItem];
133
+ const pageMetaNew = {
134
+ ...tabItem.pageMeta,
135
+ ...pageMeta
136
+ };
137
+ const tabItemNew = {
138
+ ...tabItem,
139
+ pageMeta: pageMetaNew
140
+ };
141
+ const items = mutate(tab.items, (copyState) => {
142
+ copyState.splice(indexItem, 1, tabItemNew);
143
+ });
144
+ const tabNew = {
145
+ ...tab,
146
+ items
147
+ };
148
+ this.tabs = mutate(this.tabs, (copyState) => {
149
+ copyState.splice(index, 1, tabNew);
150
+ });
151
+ return true;
152
+ }
153
+ async deleteTab(tabKey, noActiveNext) {
154
+ if (!tabKey) return;
155
+ const [index] = this.findTab(tabKey);
156
+ if (index === -1) return;
157
+ let tabKeyActiveNext;
158
+ if (!noActiveNext && index === this.tabCurrentIndex) {
159
+ const tabCurrentIndex = index - 1 > -1 ? index - 1 : index + 1 < this.tabs.length ? index + 1 : -1;
160
+ if (tabCurrentIndex > -1) tabKeyActiveNext = this.tabs[tabCurrentIndex]?.tabKey;
161
+ }
162
+ this.tabs = mutate(this.tabs, (copyState) => {
163
+ copyState.splice(index, 1);
164
+ });
165
+ if (tabKeyActiveNext) await this.activeTab(tabKeyActiveNext);
166
+ }
167
+ async deleteTabItem(tabKey, componentKey, noActiveNext) {
168
+ if (!tabKey || !componentKey) return false;
169
+ if (tabKey === componentKey) return false;
170
+ const [index, tab] = this.findTab(tabKey);
171
+ if (index === -1 || !tab) return false;
172
+ if (!tab.items) return false;
173
+ const indexItem = tab.items.findIndex((item) => item.componentKey === componentKey);
174
+ if (indexItem === -1) return false;
175
+ if (tab.items.length === 1 && !tab.affix) await this.deleteTab(tabKey, noActiveNext);
176
+ else {
177
+ const items = mutate(tab.items, (copyState) => {
178
+ copyState.splice(indexItem, 1);
179
+ });
180
+ const tabNew = {
181
+ ...tab,
182
+ items
183
+ };
184
+ this.tabs = mutate(this.tabs, (copyState) => {
185
+ copyState.splice(index, 1, tabNew);
186
+ });
187
+ }
188
+ return true;
189
+ }
190
+ findTabItemByFullPath(fullPath) {
191
+ for (const tab of this.tabs) {
192
+ if (!tab.items) continue;
193
+ for (const item of tab.items) if (item.fullPath === fullPath) return [tab.tabKey, item.componentKey];
194
+ }
195
+ return [];
196
+ }
197
+ updateTab(tab) {
198
+ const tabKey = tab.tabKey;
199
+ const [index, tabOld] = this.findTab(tabKey);
200
+ if (index === -1 || !tabOld) return;
201
+ const items = tabOld.items ? [].concat(tabOld.items) : [];
202
+ if (tab.componentKey) {
203
+ const tabItem = {
204
+ componentKey: tab.componentKey,
205
+ fullPath: tab.fullPath,
206
+ keepAlive: tab.keepAlive,
207
+ updatedAt: Date.now()
208
+ };
209
+ const index = items.findIndex((item) => item.componentKey === tab.componentKey);
210
+ if (index === -1) items.push(tabItem);
211
+ else {
212
+ const tabItemNew = {
213
+ ...items[index],
214
+ ...tabItem
215
+ };
216
+ items.splice(index, 1, tabItemNew);
217
+ }
218
+ items.sort((a, b) => (a.componentKey === tabKey ? 0 : 1) - (b.componentKey === tabKey ? 0 : 1));
219
+ }
220
+ const tabNew = {
221
+ ...tabOld,
222
+ ...tab,
223
+ tabKey,
224
+ items,
225
+ updatedAt: Date.now()
226
+ };
227
+ this.tabs = mutate(this.tabs, (copyState) => {
228
+ copyState.splice(index, 1, tabNew);
229
+ });
230
+ }
231
+ async activeTab(tabKey) {
232
+ if (!tabKey) return;
233
+ const [_, tab] = this.findTab(tabKey);
234
+ if (!tab) return;
235
+ const tabItemFirst = tab.items?.[0];
236
+ const path = tabItemFirst?.componentKey === tabKey ? tabItemFirst.fullPath : tabKey;
237
+ await this.$router.push(path);
238
+ }
239
+ async activeTabItem(tabKey, componentKey) {
240
+ if (!tabKey || !componentKey) return;
241
+ const [_, tab] = this.findTab(tabKey);
242
+ if (!tab) return;
243
+ const tabItem = tab.items?.find((item) => item.componentKey === componentKey);
244
+ if (!tabItem) return;
245
+ const path = tabItem.fullPath;
246
+ await this.$router.push(path);
247
+ }
248
+ findTab(tabKey) {
249
+ if (!tabKey) return [-1, void 0];
250
+ const index = this.tabs.findIndex((item) => item.tabKey === tabKey);
251
+ if (index === -1) return [index, void 0];
252
+ return [index, this.tabs[index]];
253
+ }
254
+ async pruneTabs() {
255
+ let max = this.tabsOptions.max;
256
+ if (max === void 0 || max === -1) return;
257
+ if (max < 1) max = 1;
258
+ while (true) {
259
+ const affixCount = this.tabs.filter((item) => item.affix).length;
260
+ if (this.tabs.length - affixCount <= max) break;
261
+ let tabKey;
262
+ let updatedAt = Date.now();
263
+ for (const tab of this.tabs) if (!tab.affix && tab.updatedAt < updatedAt) {
264
+ tabKey = tab.tabKey;
265
+ updatedAt = tab.updatedAt;
266
+ }
267
+ if (!tabKey) break;
268
+ await this.deleteTab(tabKey, true);
269
+ }
270
+ }
271
+ async pruneTabItems(tabKey) {
272
+ if (!tabKey) return;
273
+ let maxItems = this.tabsOptions.maxItems;
274
+ if (maxItems === void 0 || maxItems === -1) return;
275
+ if (maxItems < 1) maxItems = 1;
276
+ while (true) {
277
+ const [_, tab] = this.findTab(tabKey);
278
+ if (!tab || !tab.items) break;
279
+ const ignoreCount = tab.items.filter((item) => item.componentKey === tabKey).length;
280
+ if (tab.items.length - ignoreCount <= maxItems) break;
281
+ let componentKey;
282
+ let updatedAt = Date.now();
283
+ for (const tabItem of tab.items) if (tabItem.componentKey !== tabKey && tabItem.updatedAt < updatedAt) {
284
+ componentKey = tabItem.componentKey;
285
+ updatedAt = tabItem.updatedAt;
286
+ }
287
+ if (!componentKey) break;
288
+ await this.deleteTabItem(tabKey, componentKey, true);
289
+ }
290
+ }
291
+ _checkIfTabNeedUpdate(tabOld, tabNew) {
292
+ for (const key in tabNew) {
293
+ if ([
294
+ "fullPath",
295
+ "keepAlive",
296
+ "updatedAt"
297
+ ].includes(key)) continue;
298
+ if (["componentKey"].includes(key)) {
299
+ if (!tabOld.items) return true;
300
+ const tabItemOld = tabOld.items.find((item) => item[key] === tabNew[key]);
301
+ if (!tabItemOld) return true;
302
+ for (const key2 of ["fullPath", "keepAlive"]) if (tabItemOld[key2] !== tabNew[key2]) return true;
303
+ if (tabOld.items.findIndex((item) => item[key] !== tabItemOld[key] && (item.updatedAt ?? 0) >= (tabItemOld.updatedAt ?? 0)) > -1) return true;
304
+ } else if (tabNew[key] !== tabOld[key]) return true;
305
+ }
306
+ if (this.tabs.findIndex((item) => item.tabKey !== tabOld.tabKey && (item.updatedAt ?? 0) >= (tabOld.updatedAt ?? 0)) > -1) return true;
307
+ return false;
308
+ }
309
+ _getKeepAliveInclude() {
310
+ const include = [];
311
+ for (const tab of this.tabs) {
312
+ if (!tab.items) continue;
313
+ for (const item of tab.items) if (item.keepAlive !== false && item.componentKey) {
314
+ if (!include.includes(item.componentKey)) include.push(item.componentKey);
315
+ }
316
+ }
317
+ return include;
318
+ }
319
+ _getInitialTabs() {
320
+ const tabs = this.tabsOptions.getInitialTabs?.() ?? [];
321
+ if (!this.tabsOptions.getTabInfo) return tabs;
322
+ return tabs.map((tab) => {
323
+ return {
324
+ ...tab,
325
+ info: this.tabsOptions.getTabInfo?.(tab.tabKey) ?? tab.info
326
+ };
327
+ });
328
+ }
329
+ backRoute(route) {
330
+ const [tabKey, componentKey] = this.findTabItemByFullPath(route.fullPath);
331
+ this.deleteTabItem(tabKey, componentKey, true);
332
+ }
333
+ forwardRoute(route) {
334
+ const routeMeta = this.prepareRouteMeta(route);
335
+ this.addTab(routeMeta);
336
+ }
337
+ setPageMeta(route, pageMeta) {
338
+ const [tabKey, componentKey] = this.findTabItemByFullPath(route.fullPath);
339
+ this.updateTabItemPageMeta(tabKey, componentKey, pageMeta);
340
+ }
341
+ prepareRouteMeta(route) {
342
+ const fullPath = route.fullPath;
343
+ const componentKey = this.__handleRoutePropComponentKey(route);
344
+ return {
345
+ tabKey: this._handleRouteProp(route, "tabKey") || componentKey,
346
+ componentKey,
347
+ fullPath,
348
+ keepAlive: this._handleRouteProp(route, "keepAlive")
349
+ };
350
+ }
351
+ _handleRouteProp(route, prop) {
352
+ let value = route.meta[prop];
353
+ if (typeof value === "function") value = value.call(this.app, route);
354
+ return value;
355
+ }
356
+ __handleRoutePropComponentKey(route) {
357
+ const componentKey = this._handleRouteProp(route, "componentKey");
358
+ if (componentKey) return componentKey;
359
+ const name = this.$router.getRealRouteName(route.name);
360
+ if (!name) return route.path;
361
+ if (route.meta.componentKeyMode === "nameOnly") return name;
362
+ return route.path;
363
+ }
364
+ }) || _class$2) || _class$2);
365
+ //#endregion
366
+ //#region src/component/routerViewTabs/controller.tsx
367
+ var _dec$1, _dec2$1, _dec3, _dec4, _class$1, _class2, _descriptor, _ControllerRouterViewTabs;
368
+ function _initializerDefineProperty(e, i, r, l) {
369
+ r && Object.defineProperty(e, i, {
370
+ enumerable: r.enumerable,
371
+ configurable: r.configurable,
372
+ writable: r.writable,
373
+ value: r.initializer ? r.initializer.call(l) : void 0
374
+ });
375
+ }
376
+ function _applyDecoratedDescriptor(i, e, r, n, l) {
377
+ var a = {};
378
+ return Object.keys(n).forEach(function(i) {
379
+ a[i] = n[i];
380
+ }), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce(function(r, n) {
381
+ return n(i, e, r) || r;
382
+ }, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a;
383
+ }
384
+ var ControllerRouterViewTabs = (_dec$1 = Controller(), _dec2$1 = BeanInfo({ module: "a-routertabs" }), _dec3 = Use({ injectionScope: "skipSelf" }), _dec4 = Reflect.metadata("design:type", typeof ModelTabs === "undefined" ? Object : ModelTabs), _dec$1(_class$1 = _dec2$1(_class$1 = (_class2 = (_ControllerRouterViewTabs = class ControllerRouterViewTabs extends BeanRouterViewBase {
385
+ constructor(...args) {
386
+ super(...args);
387
+ _initializerDefineProperty(this, "$$modelTabs", _descriptor, this);
388
+ }
389
+ backRoute(route) {
390
+ this.$$modelTabs.backRoute(route);
391
+ return true;
392
+ }
393
+ forwardRoute(route) {
394
+ this.$$modelTabs.forwardRoute(route);
395
+ return true;
396
+ }
397
+ setPageMeta(route, pageMeta) {
398
+ this.$$modelTabs.setPageMeta(route, pageMeta);
399
+ }
400
+ prepareRouteMeta(route) {
401
+ return this.$$modelTabs.prepareRouteMeta(route);
402
+ }
403
+ getKeepAliveInclude() {
404
+ return this.$$modelTabs.keepAliveInclude;
405
+ }
406
+ }, _ControllerRouterViewTabs.$propsDefault = {}, _ControllerRouterViewTabs), _descriptor = _applyDecoratedDescriptor(_class2.prototype, "$$modelTabs", [_dec3, _dec4], {
407
+ configurable: true,
408
+ enumerable: true,
409
+ writable: true,
410
+ initializer: null
411
+ }), _class2)) || _class$1) || _class$1);
412
+ //#endregion
413
+ //#region src/.metadata/component/routerViewTabs.ts
414
+ var ZRouterViewTabs = defineComponent((_props) => {
415
+ useController(ControllerRouterViewTabs, void 0, void 0);
416
+ return () => {};
417
+ }, prepareComponentOptions());
418
+ //#endregion
419
+ //#region src/.metadata/index.ts
420
+ /** components: end */
421
+ /** scope: begin */
422
+ var _dec, _dec2, _class;
423
+ var components = { "routerViewTabs": ZRouterViewTabs };
424
+ var ScopeModuleARoutertabs = (_dec = Scope(), _dec2 = BeanInfo({ module: "a-routertabs" }), _dec(_class = _dec2(_class = class ScopeModuleARoutertabs extends BeanScopeBase {}) || _class) || _class);
425
+ /** scope: end */
426
+ //#endregion
427
+ export { ControllerRouterViewTabs, ModelTabs$1 as ModelTabs, ScopeModuleARoutertabs, ZRouterViewTabs, components };
428
+
429
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["Use","Controller","BeanRouterViewBase","ControllerRouterViewTabs","_dec","_dec2","__z_BeanInfo","module","_dec3","injectionScope","_dec4","Reflect","metadata","ModelTabs","Object","_class","_class2","_ControllerRouterViewTabs","constructor","args","_initializerDefineProperty","_descriptor","backRoute","route","$$modelTabs","forwardRoute","setPageMeta","pageMeta","prepareRouteMeta","getKeepAliveInclude","keepAliveInclude","$propsDefault","_applyDecoratedDescriptor","prototype","configurable","enumerable","writable","initializer"],"sources":["../src/model/tabs.ts","../src/component/routerViewTabs/controller.tsx","../src/.metadata/component/routerViewTabs.ts","../src/.metadata/index.ts"],"sourcesContent":["import type { IDecoratorModelOptions, UseQueryOptions } from 'zova-module-a-model';\n\nimport { RouteLocationNormalizedLoaded, RouteLocationNormalizedLoadedGeneric } from '@cabloy/vue-router';\nimport { mutate } from 'mutate-on-copy';\nimport { deepEqual, deepExtend, TypeEventOff, useComputed } from 'zova';\nimport { BeanModelBase, Model } from 'zova-module-a-model';\nimport { IPageMeta, IRouteViewRouteItem, IRouteViewRouteMeta } from 'zova-module-a-router';\n\nimport { ModelTabsOptions, ModelTabsOptionsBase, RouteTab, RouteTabInitial, RouteTabTransient } from '../types/tabs.js';\n\nexport interface IModelOptionsTabs extends IDecoratorModelOptions, ModelTabsOptionsBase {}\n\n@Model<IModelOptionsTabs>({\n enableSelector: true,\n max: -1,\n maxItems: -1,\n cache: false,\n})\nexport class ModelTabs extends BeanModelBase {\n tabsOptions: ModelTabsOptions;\n tabs: RouteTab[];\n componentKeyCurrent?: string;\n tabKeyCurrent?: string;\n tabCurrentIndex: number;\n tabCurrent?: RouteTab;\n keepAliveInclude: string[];\n private _eventSsrHmrReload: TypeEventOff;\n\n protected async __init__(scene: string, options?: ModelTabsOptions) {\n await super.__init__(scene);\n this.bean._setBean('$$modelTabs', this);\n // options\n this.tabsOptions = deepExtend({}, this.$onionOptions, options);\n // computed\n this.tabCurrentIndex = useComputed(() => {\n const [index] = this.findTab(this.tabKeyCurrent);\n return index;\n });\n this.tabCurrent = useComputed(() => {\n const [, tab] = this.findTab(this.tabKeyCurrent);\n return tab;\n });\n this.keepAliveInclude = useComputed(() => {\n return this._getKeepAliveInclude();\n });\n // componentKeyCurrent\n const queryOptionsComponentKeyCurrent: UseQueryOptions<string> = {\n queryKey: ['componentKeyCurrent'],\n };\n this.componentKeyCurrent = this.$useStateMem(queryOptionsComponentKeyCurrent);\n // tabKeyCurrent\n const queryOptionsTabKeyCurrent: UseQueryOptions<string> = {\n queryKey: ['tabKeyCurrent'],\n };\n this.tabKeyCurrent = this.$useStateMem(queryOptionsTabKeyCurrent);\n // if (this.tabsOptions.cache) {\n // this.tabKeyCurrent = this.$useStateDb(queryOptionsTabKeyCurrent);\n // } else {\n // this.tabKeyCurrent = this.$useStateMem(queryOptionsTabKeyCurrent);\n // }\n // tabs\n const queryOptionsTabs: UseQueryOptions<RouteTab[]> = {\n queryKey: ['tabs'],\n meta: {\n defaultData: this._getInitialTabs(),\n },\n };\n if (this.tabsOptions.cache) {\n this.tabs = this.$useStateDb(queryOptionsTabs);\n } else {\n this.tabs = this.$useStateMem(queryOptionsTabs);\n }\n // load cache\n if (this.tabsOptions.cache) {\n // await this.$loadStateDb(this.tabKeyCurrent);\n await this.$loadStateDb(this.tabs);\n }\n // first route\n if (this.$currentRoute) {\n this.forwardRoute(this.$currentRoute);\n }\n // event\n if (process.env.CLIENT && this.sys.env.SSR_HMR === 'true') {\n this._eventSsrHmrReload = this.sys.meta.event.on('a-ssrhmr:reload', async (_data, next) => {\n this.updateAllTabInfos();\n return next();\n });\n }\n // locale\n this.$watch(\n () => {\n return this.app.meta.locale.current;\n },\n () => {\n this.updateAllTabInfos();\n },\n );\n }\n\n protected __dispose__() {\n if (this._eventSsrHmrReload) {\n this._eventSsrHmrReload();\n }\n }\n\n get cache() {\n return this.tabsOptions.cache;\n }\n\n // need not async\n addTab(tab: RouteTabTransient, affix?: boolean): boolean {\n const res = this._addTab(tab, affix);\n // current\n this.tabKeyCurrent = res ? tab.tabKey : undefined;\n this.componentKeyCurrent = res ? tab.componentKey : undefined;\n return res;\n }\n\n // need not async\n _addTab(tab: Partial<RouteTabTransient>, affix?: boolean): boolean {\n const tabKey = tab.tabKey;\n if (!tabKey) return false;\n // tab\n const [index, tabOld] = this.findTab(tabKey);\n // tabInfo\n const tabInfo = this.tabsOptions.getTabInfo?.(tabKey) ?? tabOld?.info;\n if (!tabInfo) return false;\n // tabs\n if (index === -1) {\n // new\n const items: IRouteViewRouteItem[] = tab.componentKey\n ? [\n {\n componentKey: tab.componentKey!,\n fullPath: tab.fullPath!,\n keepAlive: tab.keepAlive,\n updatedAt: Date.now(),\n },\n ]\n : [];\n const tabNew: RouteTab = {\n tabKey,\n affix,\n items,\n updatedAt: Date.now(),\n info: tabInfo,\n };\n if (this.tabCurrentIndex === -1) {\n this.tabs = mutate(this.tabs, copyState => {\n copyState.push(tabNew);\n });\n } else {\n this.tabs = mutate(this.tabs, copyState => {\n copyState.splice(this.tabCurrentIndex + 1, 0, tabNew);\n });\n }\n // need not await\n this.pruneTabs();\n } else {\n // update tabInfo\n if (!deepEqual(tabInfo, tabOld?.info)) {\n this.updateTabInfo(tabKey);\n }\n // update\n if (!this._checkIfTabNeedUpdate(tabOld!, tab)) {\n return true;\n }\n this.updateTab(tab);\n // need not await\n this.pruneTabItems(tabKey);\n }\n return true;\n }\n\n updateAllTabInfos(tabInitials?: RouteTabInitial[]) {\n for (const tab of this.tabs) {\n const tabInitial = tabInitials?.find(item => item.tabKey === tab.tabKey);\n this.updateTabInfo(tab.tabKey, tabInitial);\n }\n }\n\n updateTabInfo(tabKey?: string, tabInitial?: RouteTabInitial) {\n if (!tabKey) return;\n // tabs\n const [index, tabOld] = this.findTab(tabKey);\n if (index === -1) return;\n // tabInfo\n const tabInfo = this.tabsOptions.getTabInfo ? this.tabsOptions.getTabInfo(tabKey) : (tabInitial?.info ?? tabOld?.info);\n if (!tabInfo) return;\n // update\n const tabNew = { ...tabOld, info: tabInfo };\n this.updateTab(tabNew);\n }\n\n updateTabItemPageMeta(tabKey?: string, componentKey?: string, pageMeta?: IPageMeta) {\n if (!tabKey || !componentKey) return false;\n // tab\n const [index, tab] = this.findTab(tabKey);\n if (index === -1 || !tab) return false;\n // tabItem\n if (!tab.items) return false;\n const indexItem = tab.items.findIndex(item => item.componentKey === componentKey);\n if (indexItem === -1) return false;\n const tabItem = tab.items[indexItem];\n // change tab item\n const pageMetaNew: IPageMeta = { ...tabItem.pageMeta, ...pageMeta };\n const tabItemNew: IRouteViewRouteItem = { ...tabItem, pageMeta: pageMetaNew };\n const items = mutate(tab.items, copyState => {\n copyState.splice(indexItem, 1, tabItemNew);\n });\n const tabNew: RouteTab = { ...tab, items };\n this.tabs = mutate(this.tabs, copyState => {\n copyState.splice(index, 1, tabNew);\n });\n return true;\n }\n\n async deleteTab(tabKey?: string, noActiveNext?: boolean) {\n if (!tabKey) return;\n // tabs\n const [index] = this.findTab(tabKey);\n if (index === -1) return;\n // current\n let tabKeyActiveNext;\n if (!noActiveNext && index === this.tabCurrentIndex) {\n // prev/next\n const tabCurrentIndex = index - 1 > -1 ? index - 1 : index + 1 < this.tabs.length ? index + 1 : -1;\n if (tabCurrentIndex > -1) {\n tabKeyActiveNext = this.tabs[tabCurrentIndex]?.tabKey;\n }\n }\n // tabs\n this.tabs = mutate(this.tabs, copyState => {\n copyState.splice(index, 1);\n });\n // active next\n if (tabKeyActiveNext) {\n await this.activeTab(tabKeyActiveNext);\n }\n }\n\n async deleteTabItem(tabKey?: string, componentKey?: string, noActiveNext?: boolean) {\n if (!tabKey || !componentKey) return false;\n if (tabKey === componentKey) return false; // not delete first tabItem\n // tab\n const [index, tab] = this.findTab(tabKey);\n if (index === -1 || !tab) return false;\n // indexItem\n if (!tab.items) return false;\n const indexItem = tab.items.findIndex(item => item.componentKey === componentKey);\n if (indexItem === -1) return false;\n if (tab.items.length === 1 && !tab.affix) {\n // delete tab\n await this.deleteTab(tabKey, noActiveNext);\n } else {\n // delete tab item\n const items = mutate(tab.items, copyState => {\n copyState.splice(indexItem, 1);\n });\n const tabNew: RouteTab = { ...tab, items };\n this.tabs = mutate(this.tabs, copyState => {\n copyState.splice(index, 1, tabNew);\n });\n }\n return true;\n }\n\n findTabItemByFullPath(fullPath: string) {\n for (const tab of this.tabs) {\n if (!tab.items) continue;\n for (const item of tab.items) {\n if (item.fullPath === fullPath) {\n return [tab.tabKey, item.componentKey];\n }\n }\n }\n return [];\n }\n\n updateTab(tab: Partial<RouteTabTransient>) {\n const tabKey = tab.tabKey!;\n const [index, tabOld] = this.findTab(tabKey);\n if (index === -1 || !tabOld) return;\n const items: IRouteViewRouteItem[] = tabOld.items ? ([] as IRouteViewRouteItem[]).concat(tabOld.items) : [];\n if (tab.componentKey) {\n const tabItem: IRouteViewRouteItem = {\n componentKey: tab.componentKey,\n fullPath: tab.fullPath!,\n keepAlive: tab.keepAlive,\n updatedAt: Date.now(),\n };\n const index = items.findIndex(item => item.componentKey === tab.componentKey);\n if (index === -1) {\n items.push(tabItem);\n } else {\n const tabItemNew: IRouteViewRouteItem = { ...items[index], ...tabItem };\n items.splice(index, 1, tabItemNew);\n }\n // not use fullPath, because fullPath has query string\n items.sort((a, b) => (a.componentKey === tabKey ? 0 : 1) - (b.componentKey === tabKey ? 0 : 1));\n }\n const tabNew: RouteTab = {\n ...tabOld,\n ...tab,\n tabKey,\n items,\n updatedAt: Date.now(),\n };\n this.tabs = mutate(this.tabs, copyState => {\n copyState.splice(index, 1, tabNew);\n });\n }\n\n async activeTab(tabKey?: string) {\n if (!tabKey) return;\n const [_, tab] = this.findTab(tabKey);\n if (!tab) return;\n // should not updateTab here\n // this.updateTab({ tabKey });\n // this.tabKeyCurrent = tabKey;\n // first check tab.items?.[0]?.fullPath, because fullPath maybe has query string\n const tabItemFirst = tab.items?.[0];\n const path = tabItemFirst?.componentKey === tabKey ? tabItemFirst.fullPath : tabKey;\n await this.$router.push(path);\n }\n\n async activeTabItem(tabKey?: string, componentKey?: string) {\n if (!tabKey || !componentKey) return;\n const [_, tab] = this.findTab(tabKey);\n if (!tab) return;\n const tabItem = tab.items?.find(item => item.componentKey === componentKey);\n if (!tabItem) return;\n //\n const path = tabItem.fullPath;\n await this.$router.push(path);\n }\n\n findTab(tabKey?: string): [number, RouteTab | undefined] {\n if (!tabKey) return [-1, undefined];\n const index = this.tabs.findIndex(item => item.tabKey === tabKey);\n if (index === -1) return [index, undefined];\n return [index, this.tabs[index]];\n }\n\n async pruneTabs() {\n let max = this.tabsOptions.max;\n if (max === undefined || max === -1) return;\n if (max < 1) max = 1;\n while (true) {\n const affixCount = this.tabs.filter(item => item.affix).length;\n if (this.tabs.length - affixCount <= max) break;\n let tabKey: string | undefined;\n let updatedAt = Date.now();\n for (const tab of this.tabs) {\n if (!tab.affix && tab.updatedAt < updatedAt) {\n tabKey = tab.tabKey;\n updatedAt = tab.updatedAt;\n }\n }\n if (!tabKey) break;\n await this.deleteTab(tabKey, true);\n }\n }\n\n async pruneTabItems(tabKey?: string) {\n if (!tabKey) return;\n let maxItems = this.tabsOptions.maxItems;\n if (maxItems === undefined || maxItems === -1) return;\n if (maxItems < 1) maxItems = 1;\n while (true) {\n const [_, tab] = this.findTab(tabKey);\n if (!tab || !tab.items) break;\n const ignoreCount = tab.items.filter(item => item.componentKey === tabKey).length;\n if (tab.items.length - ignoreCount <= maxItems) break;\n let componentKey: string | undefined;\n let updatedAt = Date.now();\n for (const tabItem of tab.items) {\n if (tabItem.componentKey !== tabKey && tabItem.updatedAt < updatedAt) {\n componentKey = tabItem.componentKey;\n updatedAt = tabItem.updatedAt;\n }\n }\n if (!componentKey) break;\n await this.deleteTabItem(tabKey, componentKey, true);\n }\n }\n\n // special for _addTab\n private _checkIfTabNeedUpdate(tabOld: RouteTab, tabNew: Partial<RouteTabTransient>) {\n for (const key in tabNew) {\n if (['fullPath', 'keepAlive', 'updatedAt'].includes(key)) continue;\n if (['componentKey'].includes(key)) {\n if (!tabOld.items) return true;\n const tabItemOld = tabOld.items.find(item => item[key] === tabNew[key]);\n if (!tabItemOld) return true;\n for (const key2 of ['fullPath', 'keepAlive']) {\n if (tabItemOld[key2] !== tabNew[key2]) return true;\n }\n const recentItemIndex = tabOld.items.findIndex(item => item[key] !== tabItemOld[key] && (item.updatedAt ?? 0) >= (tabItemOld.updatedAt ?? 0));\n if (recentItemIndex > -1) return true;\n } else if (tabNew[key] !== tabOld[key]) {\n return true;\n }\n }\n const recentTabIndex = this.tabs.findIndex(item => item.tabKey !== tabOld.tabKey && (item.updatedAt ?? 0) >= (tabOld.updatedAt ?? 0));\n if (recentTabIndex > -1) return true;\n return false;\n }\n\n private _getKeepAliveInclude() {\n const include: string[] = [];\n for (const tab of this.tabs) {\n if (!tab.items) continue;\n for (const item of tab.items) {\n if (item.keepAlive !== false && item.componentKey) {\n if (!include.includes(item.componentKey)) {\n include.push(item.componentKey);\n }\n }\n }\n }\n return include;\n }\n\n private _getInitialTabs() {\n const tabs = this.tabsOptions.getInitialTabs?.() ?? [];\n if (!this.tabsOptions.getTabInfo) return tabs;\n return tabs.map(tab => {\n return {\n ...tab,\n info: this.tabsOptions.getTabInfo?.(tab.tabKey) ?? tab.info,\n };\n });\n }\n\n backRoute(route: RouteLocationNormalizedLoadedGeneric) {\n const [tabKey, componentKey] = this.findTabItemByFullPath(route.fullPath);\n this.deleteTabItem(tabKey, componentKey, true);\n }\n\n forwardRoute(route: RouteLocationNormalizedLoadedGeneric) {\n const routeMeta = this.prepareRouteMeta(route);\n this.addTab(routeMeta);\n }\n\n public setPageMeta(route: RouteLocationNormalizedLoadedGeneric, pageMeta: IPageMeta) {\n const [tabKey, componentKey] = this.findTabItemByFullPath(route.fullPath);\n this.updateTabItemPageMeta(tabKey, componentKey, pageMeta);\n }\n\n prepareRouteMeta(route: RouteLocationNormalizedLoadedGeneric): IRouteViewRouteMeta {\n // fullPath\n const fullPath = route.fullPath;\n // componentKey\n const componentKey = this.__handleRoutePropComponentKey(route);\n // tabKey\n const tabKey = this._handleRouteProp(route, 'tabKey') || componentKey;\n // keepAlive\n const keepAlive = this._handleRouteProp(route, 'keepAlive');\n // tab\n return { tabKey, componentKey, fullPath, keepAlive };\n }\n\n private _handleRouteProp(route: RouteLocationNormalizedLoaded, prop: 'componentKey' | 'tabKey'): string;\n private _handleRouteProp(route: RouteLocationNormalizedLoaded, prop: 'keepAlive'): boolean;\n private _handleRouteProp(route: RouteLocationNormalizedLoaded, prop) {\n let value = route.meta[prop];\n if (typeof value === 'function') {\n value = value.call(this.app, route);\n }\n return value;\n }\n\n private __handleRoutePropComponentKey(route: RouteLocationNormalizedLoaded) {\n const componentKey = this._handleRouteProp(route, 'componentKey');\n if (componentKey) return componentKey;\n // name\n const name = this.$router.getRealRouteName(route.name);\n // path\n if (!name) return route.path;\n // name: nameOnly\n if (route.meta.componentKeyMode === 'nameOnly') return name;\n // name: withParams\n return route.path;\n }\n}\n","import { RouteLocationNormalizedLoadedGeneric } from '@cabloy/vue-router';\nimport { Use } from 'zova';\nimport { Controller } from 'zova-module-a-bean';\nimport { BeanRouterViewBase, IPageMeta, IRouterViewPropsBase, IRouteViewRouteMeta } from 'zova-module-a-router';\n\nimport type { ModelTabs } from '../../model/tabs.js';\n\nexport interface ControllerRouterViewTabsProps extends IRouterViewPropsBase {}\n\n@Controller()\nexport class ControllerRouterViewTabs extends BeanRouterViewBase {\n static $propsDefault = {};\n\n @Use({ injectionScope: 'skipSelf' })\n $$modelTabs: ModelTabs;\n\n public backRoute(route: RouteLocationNormalizedLoadedGeneric) {\n this.$$modelTabs.backRoute(route);\n return true;\n }\n\n public forwardRoute(route: RouteLocationNormalizedLoadedGeneric) {\n this.$$modelTabs.forwardRoute(route);\n return true;\n }\n\n public setPageMeta(route: RouteLocationNormalizedLoadedGeneric, pageMeta: IPageMeta) {\n this.$$modelTabs.setPageMeta(route, pageMeta);\n }\n\n protected prepareRouteMeta(route: RouteLocationNormalizedLoadedGeneric): IRouteViewRouteMeta {\n return this.$$modelTabs.prepareRouteMeta(route);\n }\n\n protected getKeepAliveInclude(): string[] | undefined {\n return this.$$modelTabs.keepAliveInclude;\n }\n}\n","import type { TypeControllerInnerProps } from 'zova';\n\nimport { defineComponent } from 'vue';\nimport { prepareComponentOptions, useController } from 'zova';\n\nimport type { ControllerRouterViewTabsProps } from '../../component/routerViewTabs/controller.jsx';\n\nimport { ControllerRouterViewTabs } from '../../component/routerViewTabs/controller.jsx';\nexport type TypeControllerRouterViewTabsPublicProps = {\n controllerRef?: (ref: ControllerRouterViewTabs) => void;\n} & ControllerRouterViewTabsProps;\n\ntype ControllerInnerProps = TypeControllerInnerProps<ControllerRouterViewTabsProps, keyof typeof ControllerRouterViewTabs.$propsDefault>;\ndeclare module 'zova-module-a-routertabs' {\n export interface ControllerRouterViewTabs {\n $props: ControllerInnerProps;\n }\n}\n\nexport const ZRouterViewTabs = defineComponent((_props: TypeControllerRouterViewTabsPublicProps) => {\n useController(ControllerRouterViewTabs, undefined, undefined);\n return () => {};\n}, prepareComponentOptions());\n","// eslint-disable\n/** model: begin */\nexport * from '../model/tabs.js';\nimport { IModelOptionsTabs } from '../model/tabs.js';\nimport 'zova-module-a-model';\ndeclare module 'zova-module-a-model' {\n \n export interface IModelRecord {\n 'a-routertabs:tabs': IModelOptionsTabs;\n }\n\n \n}\ndeclare module 'zova-module-a-routertabs' {\n \n export interface ModelTabs {\n /** @internal */\n get scope(): ScopeModuleARoutertabs;\n }\n\n export interface ModelTabs {\n get $beanFullName(): 'a-routertabs.model.tabs';\n get $onionName(): 'a-routertabs:tabs';\n get $onionOptions(): IModelOptionsTabs;\n } \n}\n/** model: end */\n/** model: begin */\nimport { ModelTabs } from '../model/tabs.js';\nimport 'zova';\ndeclare module 'zova' {\n export interface IBeanRecordGeneral {\n 'a-routertabs.model.tabs': ModelTabs;\n }\n}\n/** model: end */\n/** controller: begin */\nexport * from '../component/routerViewTabs/controller.jsx';\n\nimport 'zova';\ndeclare module 'zova' {\n \n \n}\ndeclare module 'zova-module-a-routertabs' {\n \n export interface ControllerRouterViewTabs {\n /** @internal */\n get scope(): ScopeModuleARoutertabs;\n } \n}\n/** controller: end */\n/** controller: begin */\nimport { ControllerRouterViewTabs } from '../component/routerViewTabs/controller.jsx';\nimport 'zova';\ndeclare module 'zova' {\n export interface IBeanRecordLocal {\n 'a-routertabs.controller.routerViewTabs': ControllerRouterViewTabs;\n }\n}\n/** controller: end */\n\n/** components: begin */\nexport * from './component/routerViewTabs.js';\nimport { ZRouterViewTabs } from './component/routerViewTabs.js';\nexport const components = {\n 'routerViewTabs': ZRouterViewTabs,\n};\nimport 'zova';\ndeclare module 'zova' {\nexport interface IComponentRecord {\n 'a-routertabs:routerViewTabs': ControllerRouterViewTabs;\n}\nexport interface IZovaComponentRecord {\n 'a-routertabs:routerViewTabs': typeof ZRouterViewTabs;\n}\n}\n/** components: end */\n/** scope: begin */\nimport { BeanScopeBase, type BeanScopeUtil } from 'zova';\nimport { Scope } from 'zova-module-a-bean';\n\n@Scope()\nexport class ScopeModuleARoutertabs extends BeanScopeBase {}\n\nexport interface ScopeModuleARoutertabs {\n util: BeanScopeUtil;\n}\n\nimport 'zova';\ndeclare module 'zova' {\n export interface IBeanScopeRecord {\n 'a-routertabs': ScopeModuleARoutertabs;\n }\n \n \n\n \n\n \n}\n \n/** scope: end */\n"],"mappings":";;;;;;;AAAA,IAAA,QAAO,SAAO;AAKd,IAAS,eAAe,SAAO,MAAM;CACrC,gBAAkB;;CAElB,UAAS;;CAET,CAAA,EAAA,UAAO,SAAU,EAAA,QAAA,gBAEhB,CAAA,EAAA,OAAM,WAAA,QAAiB,WAAE,MAAA,kBAAA,cAAA;CACxB,YAAA,GAAe,MAAK;AACpB,QAAO,GAAA,KAAA;AACP,OAAA,cAAY,KAAA;AACZ,OAAO,OAAK,KAAA;AACb,OAAA,sBAAA,KAAA;AACD,OAAO,gBAAgB,KAAO;AAC5B,OAAA,kBAAa,KAAgB;AAC7B,OAAM,aAAU,KAAA;AAChB,OAAA,mBAAsB,KAAM;AAC5B,OAAA,qBAAsB,KAAA;;CAEtB,MAAA,SAAa,OAAQ,SAAA;AACrB,QAAA,MAAA,SAAkB,MAAQ;AAC1B,OAAO,KAAC,SAAA,eAAoB,KAAY;AAExC,OAAA,cAAgB,WAAgB,EAAA,EAAA,KAAQ,eAAU,QAAA;AAEhD,OAAK,kBAAiB,kBAAiB;GACrC,MAAC,CAAA,SAAA,KAAA,QAAA,KAAA,cAAA;AACH,UAAK;IACH;AACF,OAAK,aAAA,kBAA+B;GAClC,MAAM,GAAC,OAAS,KAAK,QAAQ,KAAK,cAAc;AAChD,UAAO;IACP;AACF,OAAK,mBAAa,kBAAkB;AAClC,UAAO,KAAK,sBAAsB;IAClC;AAKF,OAAG,sBAAA,KAAA,aAHqC,EACtC,UAAO,CAAI,sBAAsB,EAClC,CACE;AAKH,OAAG,gBAAA,KAAA,aAH+B,EACjC,UAAA,CAAA,gBAAA,EACD,CACG;EAOH,MAAK,mBAAK;GACR,UAAQ,CAAA,OAAA;GACR,MAAC,EACA,aAAA,KAAA,iBAAA,EACH;GACC;AACD,MAAE,KAAM,YAAA,MACN,MAAE,OAAA,KAAa,YAAK,iBAAiB;MAEtC,MAAA,OAAA,KAAA,aAAA,iBAAA;AAGD,MAAE,KAAK,YAAA,MAEP,OAAA,KAAA,aAAA,KAAA,KAAA;AAGA,MAAI,KAAC,cACH,MAAK,aAAO,KAAW,cAAW;AAGpC,MAAI,QAAM,IAAA,UAAc,KAAA,IAAA,IAAA,YAAA,OACtB,MAAK,qBAAmB,KAAA,IAAA,KAAa,MAAA,GAAA,mBAAA,OAAA,OAAA,SAAA;AACvC,QAAA,mBAAA;AACG,UAAA,MAAA;IACC;AAGJ,OAAI,aAAa;AACf,UAAE,KAAA,IAAA,KAAA,OAAA;WACJ;AACE,QAAC,mBAAA;IACH;;CAEF,cAAa;AACX,MAAG,KAAA,mBACD,MAAK,oBAAC;;CAGV,IAAG,QAAA;AACH,SAAA,KAAA,YAAA;;CAIA,OAAI,KAAK,OAAA;EACP,MAAA,MAAA,KAAA,QAAA,KAAA,MAAA;;AAGF,OAAI,sBAAQ,MAAA,IAAA,eAAA,KAAA;AACV,SAAO;;CAIT,QAAO,KAAK,OAAA;EACV,MAAM,SAAM,IAAK;AACjB,MAAG,CAAA,OAAA,QAAA;EAEH,MAAK,CAAA,OAAA,UAAmB,KAAG,QAAU,OAAA;EAEvC,MAAA,UAAA,KAAA,YAAA,aAAA,OAAA,IAAA,QAAA;;AAGA,MAAA,UAAa,IAAO;GAQhB,MAAC,SAAA;IACC;IACA;IACF,OATW,IAAO,eAAK,CAAA;KACtB,cAAA,IAAA;KACH,UAAc,IAAA;KACX,WAAA,IAAA;KACH,WAAe,KAAK,KAAC;KAClB,CAAC,GAAC,EAAA;IAKD,WAAE,KAAA,KAAA;IACF,MAAI;IACL;AACD,OAAI,KAAI,oBAAc,GACpB,MAAK,OAAC,OAAW,KAAI,OAAS,cAAA;AAC5B,cAAI,KAAW,OAAK;KACpB;OAEF,MAAI,OAAA,OAAA,KAAA,OAAA,cAAA;AACN,cAAc,OAAA,KAAW,kBAAA,GAAA,GAAA,OAAA;KACvB;AAGF,QAAE,WAAW;SACX;AAEF,OAAI,CAAA,UAAK,SAAe,QAAQ,KAAC,CAC/B,MAAK,cAAc,OAAK;AAG1B,OAAE,CAAA,KAAK,sBAAA,QAAA,IAAA,CACL,QAAK;AAEP,QAAI,UAAA,IAAA;AAEJ,QAAG,cAAS,OAAA;;AAEd,SAAO;;CAET,kBAAkB,aAAU;AAC1B,OAAI,MAAK,OAAA,KAAc,MAAM;GAC3B,MAAA,aAAA,aAAA,MAAA,SAAA,KAAA,WAAA,IAAA,OAAA;AACA,QAAG,cAAA,IAAA,QAAA,WAAA;;;CAGP,cAAI,QAAA,YAAA;AACF,MAAE,CAAA,OAAK;EAEP,MAAM,CAAC,OAAA,UAAc,KAAO,QAAA,OAAA;AAC5B,MAAA,UAAA,GAAA;EAEF,MAAA,UAAA,KAAA,YAAA,aAAA,KAAA,YAAA,WAAA,OAAA,GAAA,YAAA,QAAA,QAAA;;EAGE,MAAK,SAAU;GACb,GAAA;GACA,MAAK;GACP;AACF,OAAA,UAAA,OAAA;;CAEA,sBAAsB,QAAQ,cAAc,UAAA;AAC1C,MAAI,CAAC,UAAQ,CAAA,aAAM,QAAA;EAEnB,MAAM,CAAC,OAAO,OAAO,KAAG,QAAK,OAAQ;AACrC,MAAI,UAAU,MAAI,CAAA,IAAM,QAAA;AAExB,MAAA,CAAK,IAAC,MAAU,QAAK;EACrB,MAAK,YAAS,IAAM,MAAA,WAAA,SAAA,KAAA,iBAAA,aAAA;AACpB,MAAG,cAAA,GAAA,QAAA;EACH,MAAM,UAAU,IAAI,MAAM;EAE5B,MAAA,cAAA;;GAEA,GAAA;GACE;EACA,MAAG,aAAA;GACH,GAAK;GACH,UAAU;GACX;EACD,MAAK,QAAS,OAAE,IAAO,QAAK,cAAA;AAC5B,aAAM,OAAY,WAAU,GAAA,WAAgB;IAC1C;EACF,MAAM,SAAS;GACb,GAAC;GACH;GACA;AACA,OAAK,OAAO,OAAE,KAAU,OAAM,cAAa;AACzC,aAAU,OAAO,OAAA,GAAU,OAAI;IAC/B;AACF,SAAM;;CAER,MAAI,UAAU,QAAO,cAAiB;AACpC,MAAE,CAAA,OAAA;EAEJ,MAAA,CAAA,SAAA,KAAA,QAAA,OAAA;;EAGE,IAAI;AACJ,MAAG,CAAA,gBAAA,UAAA,KAAA,iBAAA;GAED,MAAE,kBAAoB,QAAA,IAAA,KAAA,QAAA,IAAA,QAAA,IAAA,KAAA,KAAA,SAAA,QAAA,IAAA;AACtB,OAAC,kBAAA,GACC,oBAAgB,KAAA,KAAA,kBAAA;;AAIpB,OAAK,OAAC,OAAA,KAAkB,OAAI,cAAA;AAC1B,aAAE,OAAA,OAAmB,EAAK;IAC1B;AAEF,MAAG,iBACH,OAAK,KAAO,UAAW,iBAAiB;;CAG1C,MAAK,cAAO,QAAA,cAAA,cAAA;AACV,MAAI,CAAA,UAAA,CAAA,aAAkB,QAAA;AACtB,MAAE,WAAW,aAAU,QAAA;EAEzB,MAAA,CAAA,OAAA,OAAA,KAAA,QAAA,OAAA;;AAGE,MAAI,CAAC,IAAA,MAAW,QAAA;EAChB,MAAI,YAAW,IAAA,MAAa,WAAQ,SAAU,KAAI,iBAAa,aAAA;AAC/D,MAAG,cAAA,GAAA,QAAA;AACH,MAAA,IAAO,MAAO,WAAW,KAAC,CAAA,IAAQ,MAEhC,OAAC,KAAA,UAAA,QAAA,aAAA;OACE;GAEH,MAAE,QAAY,OAAM,IAAA,QAAY,cAAA;AAC9B,cAAU,OAAO,WAAU,EAAG;KAC9B;GACF,MAAM,SAAK;IACX,GAAK;IACH;IACF;AACA,QAAE,OAAU,OAAO,KAAA,OAAW,cAAE;AAC9B,cAAA,OAAA,OAAA,GAAA,OAAA;KACF;;AAEF,SAAI;;CAEN,sBAAE,UAAA;AACA,OAAA,MAAW,OAAA,KAAA,MAAA;AACb,OAAA,CAAA,IAAA,MAAA;gCAEA,KAAA,KAAA,aAAsB,SACf,QAAM,CAAG,IAAI,QAAK,KAAM,aAAA;;AAI7B,SAAM,EAAA;;CAER,UAAI,KAAA;EACF,MAAA,SAAA,IAAA;EACA,MAAM,CAAC,OAAE,UAAA,KAAA,QAAA,OAAA;AACX,MAAA,UAAA,MAAA,CAAA,OAAA;;AAEA,MAAA,IAAU,cAAa;GACrB,MAAM,UAAY;IAClB,cAAc,IAAQ;IAClB,UAAU,IAAI;IAClB,WAAa,IAAA;IACT,WAAI,KAAY,KAAE;IACpB;GACA,MAAE,QAAY,MAAM,WAAA,SAAY,KAAA,iBAAA,IAAA,aAAA;AAChC,OAAE,UAAU,GACV,OAAA,KAAW,QAAI;QACf;IACD,MAAA,aAAA;KACD,GAAM,MAAO;KACT,GAAA;KACF;AACA,UAAK,OAAA,OAAA,GAAA,WAAA;;AAGP,SAAA,MAAA,GAAA,OAAA,EAAA,iBAAA,SAAA,IAAA,MAAA,EAAA,iBAAA,SAAA,IAAA,GAAA;;EAEF,MAAE,SAAa;GACf,GAAA;GACA,GAAK;GACH;GACA;GACA,WAAM,KAAA,KAAA;GACP;AACD,OAAE,OAAU,OAAM,KAAK,OAAA,cAAA;AACtB,aAAA,OAAA,OAAA,GAAA,OAAA;IACD;;CAEF,MAAI,UAAA,QAAA;AACJ,MAAA,CAAA,OAAA;;AAEA,MAAM,CAAA,IAAA;EAKJ,MAAG,eAAiB,IAAA,QAAS;EAC7B,MAAG,OAAK,cAAgB,iBAAM,SAAA,aAAA,WAAA;AAC9B,QAAG,KAAM,QAAU,KAAK,KAAK;;CAE/B,MAAE,cAAa,QAAa,cAAc;AACxC,MAAA,CAAK,UAAO,CAAA,aAAiB;EAC/B,MAAA,CAAA,GAAA,OAAA,KAAA,QAAA,OAAA;;EAEA,MAAM,UAAA,IAAc,OAAS,MAAA,SAAQ,KAAA,iBAAuB,aAAA;AAC1D,MAAI,CAAC,QAAS;EAEd,MAAK,OAAK,QAAM;AAChB,QAAM,KAAA,QAAa,KAAC,KAAO;;CAE7B,QAAG,QAAA;AACD,MAAA,CAAK,OAAQ,QAAO,CAAC,IAAA,KAAA,EAAQ;EAC7B,MAAM,QAAM,KAAO,KAAK,WAAK,SAAA,KAAA,WAAA,OAAA;AAC/B,MAAA,UAAA,GAAA,QAAA,CAAA,OAAA,KAAA,EAAA;;;CAGA,MAAM,YAAS;EACb,IAAA,MAAM,KAAQ,YAAU;AACxB,MAAI,QAAQ,KAAA,KAAa,QAAQ,GAAA;AACjC,MAAA,MAAQ,EAAK,OAAM;AACrB,SAAA,MAAA;;AAEA,OAAM,KAAA,KAAY,SAAA,cAAA,IAAA;GAChB,IAAI;GACF,IAAE,YAAQ,KAAW,KAAK;AAC1B,QAAK,MAAM,OAAO,KAAA,KACpB,KAAO,CAAA,IAAM,SAAA,IAAA,YAAA,WAAA;AACX,aAAM,IAAW;AACb,gBAAU,IAAM;;AAGpB,OAAI,CAAC,OAAM;AACX,SAAM,KAAK,UAAS,QAAI,KAAU;;;CAGtC,MAAM,cAAA,QAAA;AACJ,MAAE,CAAA,OAAA;EACF,IAAI,WAAW,KAAK,YAAA;AACpB,MAAE,aAAW,KAAA,KAAiB,aAAM,GAAA;AACpC,MAAA,WAAA,EAAA,YAAA;AACF,SAAA,MAAA;;AAEA,OAAM,CAAA,OAAA,CAAA,IAAc,MAAQ;GACxB,MAAG,cAAc,IAAA,MAAA,QAAA,SAAA,KAAA,iBAAA,OAAA,CAAA;AACnB,OAAI,IAAA,MAAW,SAAK,eAAoB,SAAA;GACtC,IAAE;GACF,IAAE,YAAc,KAAA,KAAU;AAC5B,QAAO,MAAM,WAAA,IAAA,MACX,KAAM,QAAQ,iBAAgB,UAAO,QAAA,YAAA,WAAA;AACjC,mBAAa,QAAO;AACxB,gBAAM,QAAkB;;AAGxB,OAAI,CAAA,aAAY;AAChB,SAAK,KAAM,cAAc,QAAQ,cAAA,KAAA;;;CAKrC,sBAAI,QAAA,QAAA;AACF,OAAK,MAAE,OAAA,QAAmB;AACxB,OAAA;IAAK;IAAM;IAAc;IAAQ,CAAA,SAAmB,IAAA,CAAA;AACtD,OAAA,CAAA,eAAA,CAAA,SAAA,IAAA,EAAA;AACF,QAAA,CAAA,OAAA,MAAA,QAAA;;AAEG,QAAO,CAAC,WAAI,QAAA;AACf,SAAQ,MAAA,QAAA,CAAA,YAA8B,YAAU,CACzC,KAAK,WAAQ,UAAQ,OAAA,MAAA,QAAA;AAGtB,QADmB,OAAY,MAAG,WAAA,SAAA,KAAA,SAAA,WAAA,SAAA,KAAA,aAAA,OAAA,WAAA,aAAA,GAAA,GACf,GAAO,QAAI;cACxB,OAAU,SAAS,OAAO,KAChC,QAAK;;AAIT,MADI,KAAA,KAAA,WAAA,SAAA,KAAA,WAAA,OAAA,WAAA,KAAA,aAAA,OAAA,OAAA,aAAA,GAAA,GACM,GAAe,QAAG;AAC5B,SAAO;;CAET,uBAAiB;EACf,MAAE,UAAA,EAAA;AACF,OAAA,MAAA,OAAA,KAAA,MAAA;AACA,OAAM,CAAA,IAAA,MAAA;AACJ,QAAE,MAAA,QAAiB,IAAI,MACzB,KAAO,KAAK,cAAA,SAAA,KAAA;QACd,CAAA,QAAA,SAAA,KAAA,aAAA,CAAA,SAAA,KAAA,KAAA,aAAA;;;AAME,SAAO;;CAET,kBAAa;EACX,MAAM,OAAE,KAAQ,YAAU,kBAAa,IAAA,EAAA;AACvC,MAAI,CAAC,KAAC,YAAA,WAAA,QAAA;AACN,SAAI,KAAA,KAAA,QAAA;AACF,UAAA;IACF,GAAA;IACA,MAAO,KAAO,YAAA,aAAA,IAAA,OAAA,IAAA,IAAA;IAChB;;;CAGA,UAAQ,OAAO;EACb,MAAK,CAAA,QAAK,gBAAY,KAAY,sBAAW,MAAA,SAAA;AAC7C,OAAA,cAAmB,QAAI,cAAA,KAAA;;CAEzB,aAAY,OAAA;EACV,MAAI,YAAW,KAAA,iBAAyB,MAAI;AAC5C,OAAG,OAAA,UAAA;;CAEL,YAAA,OAAA,UAAA;;AAEA,OAAA,sBAAiB,QAAA,cAAA,SAAsC;;CAEvD,iBAAO,OAAc;;EAInB,MAAM,eAAY,KAAK,8BAAuB,MAAA;AAM9C,SAAK;GACP,QALA,KAAA,iBAAA,OAAA,SAAA,IAAA;;GAOA;GACI,WANe,KAAM,iBAAC,OAAA,YAAA;GAOxB;;CAEF,iBAAQ,OAAe,MAAK;EAC1B,IAAG,QAAA,MAAA,KAAA;AACH,MAAA,OAAM,UAAc,WAClB,SAAC,MAAA,KAAA,KAAA,KAAA,MAAA;AAEH,SAAG;;CAEL,8BAAA,OAAA;;AAEA,MAAA,aAAQ,QAAiB;EAEzB,MAAQ,OAAA,KAAA,QAAiB,iBAAO,MAAA,KAAA;AAE9B,MAAI,CAAA,KAAO,QAAO,MAAI;AAEtB,MAAA,MAAA,KAAA,qBAAA,WAAA,QAAA;AAEF,SAAA,MAAA;;EAEA,IAAA,SAAQ,IAAA;;;;;;;;;;;;;;;;;;;;AChdV,IACaG,4BAAwBC,SADpCH,YAAY,EAAAI,UAAAC,SAAA,EAAAC,QAAA,gBAAA,CAAA,EAAAC,QAIVR,IAAI,EAAES,gBAAgB,YAAY,CAAC,EAAAC,QAAAC,QAAAC,SAAA,eAAA,OAAAC,cAAA,cAAAC,SAAAD,UAAA,EAAAT,OAAAW,WAAAV,QAAAU,YAAAC,WAAAC,4BAJtC,MACad,iCAAiCD,mBAAmB;CAAAgB,YAAA,GAAAC,MAAA;AAAA,QAAA,GAAAA,KAAA;AAAAC,6BAAA,MAAA,eAAAC,aAAA,KAAA;;CAMxDC,UAAUC,OAA6C;AAC5D,OAAKC,YAAYF,UAAUC,MAAM;AACjC,SAAO;;CAGFE,aAAaF,OAA6C;AAC/D,OAAKC,YAAYC,aAAaF,MAAM;AACpC,SAAO;;CAGFG,YAAYH,OAA6CI,UAAqB;AACnF,OAAKH,YAAYE,YAAYH,OAAOI,SAAS;;CAGrCC,iBAAiBL,OAAkE;AAC3F,SAAO,KAAKC,YAAYI,iBAAiBL,MAAM;;CAGvCM,sBAA4C;AACpD,SAAO,KAAKL,YAAYM;;GAE3Bb,0BA1BQc,gBAAgB,EAAE,EAAAd,4BAAAI,cAAAW,0BAAAhB,QAAAiB,WAAA,eAAA,CAAAzB,OAAAE,MAAA,EAAA;CAAAwB,cAAA;CAAAC,YAAA;CAAAC,UAAA;CAAAC,aAAA;CAAA,CAAA,EAAArB,SAAA,IAAAD,SAAA,IAAAA;;;ACR3B,IAAS,kBAAA,iBAAsC,WAAS;;AAExD,cAAc;;;;;;ACLd,IAAG,MAAO,OAAA;AAuBV,IAAa,aAAE,EACb,kBAAO,iBACT;AAMA,IAAS,0BAA4B,OAAC,OAAA,EAAA,QAAA,SAAA,EACpC,QAAK,gBACN,CAAC,EAAA,KAAA,SAAA,MAAA,SAAA,MAAA,+BAAA,cAAA,GAAA,IAAA,OAAA,IAAA"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "zova-module-a-routertabs",
3
+ "version": "5.1.0",
4
+ "gitHead": "bf1ceb4582381c74ba41ccf11b89d3b9e7b73628",
5
+ "description": "routertabs",
6
+ "keywords": [
7
+ "Zova Module"
8
+ ],
9
+ "author": "zhennann",
10
+ "files": [
11
+ "dist",
12
+ "mock",
13
+ "rest",
14
+ "src",
15
+ "icons",
16
+ "assets"
17
+ ],
18
+ "type": "module",
19
+ "exports": {
20
+ ".": {
21
+ "types": [
22
+ "./src/index.ts",
23
+ "./dist/index.d.ts"
24
+ ],
25
+ "default": "./dist/index.js"
26
+ },
27
+ "./*": "./*"
28
+ },
29
+ "scripts": {
30
+ "clean": "rimraf dist tsconfig.build.tsbuildinfo",
31
+ "tsc:publish": "npm run clean && zova :bin:buildModule --sourcemap",
32
+ "prepublishOnly": "npm run tsc:publish",
33
+ "prepack": "clean-package",
34
+ "postpack": "clean-package restore && npm run clean"
35
+ },
36
+ "title": "a-routertabs"
37
+ }
@@ -0,0 +1,8 @@
1
+ import type { TypeRenderComponentJsxPropsPublic } from 'zova-jsx';
2
+
3
+ import type { ControllerRouterViewTabsProps } from '../../src/component/routerViewTabs/controller.jsx';
4
+
5
+ type TypeControllerRouterViewTabsPublicProps = TypeRenderComponentJsxPropsPublic & ControllerRouterViewTabsProps;
6
+ export function ZZRoutertabsRouterViewTabs(_props: TypeControllerRouterViewTabsPublicProps) {
7
+ return 'a-routertabs:routerViewTabs';
8
+ }
@@ -0,0 +1 @@
1
+ export * from './component/routerViewTabs.js';
package/rest/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './components.js';
@@ -0,0 +1,23 @@
1
+ import type { TypeControllerInnerProps } from 'zova';
2
+
3
+ import { defineComponent } from 'vue';
4
+ import { prepareComponentOptions, useController } from 'zova';
5
+
6
+ import type { ControllerRouterViewTabsProps } from '../../component/routerViewTabs/controller.jsx';
7
+
8
+ import { ControllerRouterViewTabs } from '../../component/routerViewTabs/controller.jsx';
9
+ export type TypeControllerRouterViewTabsPublicProps = {
10
+ controllerRef?: (ref: ControllerRouterViewTabs) => void;
11
+ } & ControllerRouterViewTabsProps;
12
+
13
+ type ControllerInnerProps = TypeControllerInnerProps<ControllerRouterViewTabsProps, keyof typeof ControllerRouterViewTabs.$propsDefault>;
14
+ declare module 'zova-module-a-routertabs' {
15
+ export interface ControllerRouterViewTabs {
16
+ $props: ControllerInnerProps;
17
+ }
18
+ }
19
+
20
+ export const ZRouterViewTabs = defineComponent((_props: TypeControllerRouterViewTabsPublicProps) => {
21
+ useController(ControllerRouterViewTabs, undefined, undefined);
22
+ return () => {};
23
+ }, prepareComponentOptions());
@@ -0,0 +1,103 @@
1
+ // eslint-disable
2
+ /** model: begin */
3
+ export * from '../model/tabs.js';
4
+ import { IModelOptionsTabs } from '../model/tabs.js';
5
+ import 'zova-module-a-model';
6
+ declare module 'zova-module-a-model' {
7
+
8
+ export interface IModelRecord {
9
+ 'a-routertabs:tabs': IModelOptionsTabs;
10
+ }
11
+
12
+
13
+ }
14
+ declare module 'zova-module-a-routertabs' {
15
+
16
+ export interface ModelTabs {
17
+ /** @internal */
18
+ get scope(): ScopeModuleARoutertabs;
19
+ }
20
+
21
+ export interface ModelTabs {
22
+ get $beanFullName(): 'a-routertabs.model.tabs';
23
+ get $onionName(): 'a-routertabs:tabs';
24
+ get $onionOptions(): IModelOptionsTabs;
25
+ }
26
+ }
27
+ /** model: end */
28
+ /** model: begin */
29
+ import { ModelTabs } from '../model/tabs.js';
30
+ import 'zova';
31
+ declare module 'zova' {
32
+ export interface IBeanRecordGeneral {
33
+ 'a-routertabs.model.tabs': ModelTabs;
34
+ }
35
+ }
36
+ /** model: end */
37
+ /** controller: begin */
38
+ export * from '../component/routerViewTabs/controller.jsx';
39
+
40
+ import 'zova';
41
+ declare module 'zova' {
42
+
43
+
44
+ }
45
+ declare module 'zova-module-a-routertabs' {
46
+
47
+ export interface ControllerRouterViewTabs {
48
+ /** @internal */
49
+ get scope(): ScopeModuleARoutertabs;
50
+ }
51
+ }
52
+ /** controller: end */
53
+ /** controller: begin */
54
+ import { ControllerRouterViewTabs } from '../component/routerViewTabs/controller.jsx';
55
+ import 'zova';
56
+ declare module 'zova' {
57
+ export interface IBeanRecordLocal {
58
+ 'a-routertabs.controller.routerViewTabs': ControllerRouterViewTabs;
59
+ }
60
+ }
61
+ /** controller: end */
62
+
63
+ /** components: begin */
64
+ export * from './component/routerViewTabs.js';
65
+ import { ZRouterViewTabs } from './component/routerViewTabs.js';
66
+ export const components = {
67
+ 'routerViewTabs': ZRouterViewTabs,
68
+ };
69
+ import 'zova';
70
+ declare module 'zova' {
71
+ export interface IComponentRecord {
72
+ 'a-routertabs:routerViewTabs': ControllerRouterViewTabs;
73
+ }
74
+ export interface IZovaComponentRecord {
75
+ 'a-routertabs:routerViewTabs': typeof ZRouterViewTabs;
76
+ }
77
+ }
78
+ /** components: end */
79
+ /** scope: begin */
80
+ import { BeanScopeBase, type BeanScopeUtil } from 'zova';
81
+ import { Scope } from 'zova-module-a-bean';
82
+
83
+ @Scope()
84
+ export class ScopeModuleARoutertabs extends BeanScopeBase {}
85
+
86
+ export interface ScopeModuleARoutertabs {
87
+ util: BeanScopeUtil;
88
+ }
89
+
90
+ import 'zova';
91
+ declare module 'zova' {
92
+ export interface IBeanScopeRecord {
93
+ 'a-routertabs': ScopeModuleARoutertabs;
94
+ }
95
+
96
+
97
+
98
+
99
+
100
+
101
+ }
102
+
103
+ /** scope: end */
@@ -0,0 +1,2 @@
1
+ export const __ThisModule__ = 'a-routertabs';
2
+ export { ScopeModuleARoutertabs as ScopeModule } from './index.js';
@@ -0,0 +1,38 @@
1
+ import { RouteLocationNormalizedLoadedGeneric } from '@cabloy/vue-router';
2
+ import { Use } from 'zova';
3
+ import { Controller } from 'zova-module-a-bean';
4
+ import { BeanRouterViewBase, IPageMeta, IRouterViewPropsBase, IRouteViewRouteMeta } from 'zova-module-a-router';
5
+
6
+ import type { ModelTabs } from '../../model/tabs.js';
7
+
8
+ export interface ControllerRouterViewTabsProps extends IRouterViewPropsBase {}
9
+
10
+ @Controller()
11
+ export class ControllerRouterViewTabs extends BeanRouterViewBase {
12
+ static $propsDefault = {};
13
+
14
+ @Use({ injectionScope: 'skipSelf' })
15
+ $$modelTabs: ModelTabs;
16
+
17
+ public backRoute(route: RouteLocationNormalizedLoadedGeneric) {
18
+ this.$$modelTabs.backRoute(route);
19
+ return true;
20
+ }
21
+
22
+ public forwardRoute(route: RouteLocationNormalizedLoadedGeneric) {
23
+ this.$$modelTabs.forwardRoute(route);
24
+ return true;
25
+ }
26
+
27
+ public setPageMeta(route: RouteLocationNormalizedLoadedGeneric, pageMeta: IPageMeta) {
28
+ this.$$modelTabs.setPageMeta(route, pageMeta);
29
+ }
30
+
31
+ protected prepareRouteMeta(route: RouteLocationNormalizedLoadedGeneric): IRouteViewRouteMeta {
32
+ return this.$$modelTabs.prepareRouteMeta(route);
33
+ }
34
+
35
+ protected getKeepAliveInclude(): string[] | undefined {
36
+ return this.$$modelTabs.keepAliveInclude;
37
+ }
38
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './.metadata/index.js';
2
+ export * from './types/index.js';
@@ -0,0 +1,486 @@
1
+ import type { IDecoratorModelOptions, UseQueryOptions } from 'zova-module-a-model';
2
+
3
+ import { RouteLocationNormalizedLoaded, RouteLocationNormalizedLoadedGeneric } from '@cabloy/vue-router';
4
+ import { mutate } from 'mutate-on-copy';
5
+ import { deepEqual, deepExtend, TypeEventOff, useComputed } from 'zova';
6
+ import { BeanModelBase, Model } from 'zova-module-a-model';
7
+ import { IPageMeta, IRouteViewRouteItem, IRouteViewRouteMeta } from 'zova-module-a-router';
8
+
9
+ import { ModelTabsOptions, ModelTabsOptionsBase, RouteTab, RouteTabInitial, RouteTabTransient } from '../types/tabs.js';
10
+
11
+ export interface IModelOptionsTabs extends IDecoratorModelOptions, ModelTabsOptionsBase {}
12
+
13
+ @Model<IModelOptionsTabs>({
14
+ enableSelector: true,
15
+ max: -1,
16
+ maxItems: -1,
17
+ cache: false,
18
+ })
19
+ export class ModelTabs extends BeanModelBase {
20
+ tabsOptions: ModelTabsOptions;
21
+ tabs: RouteTab[];
22
+ componentKeyCurrent?: string;
23
+ tabKeyCurrent?: string;
24
+ tabCurrentIndex: number;
25
+ tabCurrent?: RouteTab;
26
+ keepAliveInclude: string[];
27
+ private _eventSsrHmrReload: TypeEventOff;
28
+
29
+ protected async __init__(scene: string, options?: ModelTabsOptions) {
30
+ await super.__init__(scene);
31
+ this.bean._setBean('$$modelTabs', this);
32
+ // options
33
+ this.tabsOptions = deepExtend({}, this.$onionOptions, options);
34
+ // computed
35
+ this.tabCurrentIndex = useComputed(() => {
36
+ const [index] = this.findTab(this.tabKeyCurrent);
37
+ return index;
38
+ });
39
+ this.tabCurrent = useComputed(() => {
40
+ const [, tab] = this.findTab(this.tabKeyCurrent);
41
+ return tab;
42
+ });
43
+ this.keepAliveInclude = useComputed(() => {
44
+ return this._getKeepAliveInclude();
45
+ });
46
+ // componentKeyCurrent
47
+ const queryOptionsComponentKeyCurrent: UseQueryOptions<string> = {
48
+ queryKey: ['componentKeyCurrent'],
49
+ };
50
+ this.componentKeyCurrent = this.$useStateMem(queryOptionsComponentKeyCurrent);
51
+ // tabKeyCurrent
52
+ const queryOptionsTabKeyCurrent: UseQueryOptions<string> = {
53
+ queryKey: ['tabKeyCurrent'],
54
+ };
55
+ this.tabKeyCurrent = this.$useStateMem(queryOptionsTabKeyCurrent);
56
+ // if (this.tabsOptions.cache) {
57
+ // this.tabKeyCurrent = this.$useStateDb(queryOptionsTabKeyCurrent);
58
+ // } else {
59
+ // this.tabKeyCurrent = this.$useStateMem(queryOptionsTabKeyCurrent);
60
+ // }
61
+ // tabs
62
+ const queryOptionsTabs: UseQueryOptions<RouteTab[]> = {
63
+ queryKey: ['tabs'],
64
+ meta: {
65
+ defaultData: this._getInitialTabs(),
66
+ },
67
+ };
68
+ if (this.tabsOptions.cache) {
69
+ this.tabs = this.$useStateDb(queryOptionsTabs);
70
+ } else {
71
+ this.tabs = this.$useStateMem(queryOptionsTabs);
72
+ }
73
+ // load cache
74
+ if (this.tabsOptions.cache) {
75
+ // await this.$loadStateDb(this.tabKeyCurrent);
76
+ await this.$loadStateDb(this.tabs);
77
+ }
78
+ // first route
79
+ if (this.$currentRoute) {
80
+ this.forwardRoute(this.$currentRoute);
81
+ }
82
+ // event
83
+ if (process.env.CLIENT && this.sys.env.SSR_HMR === 'true') {
84
+ this._eventSsrHmrReload = this.sys.meta.event.on('a-ssrhmr:reload', async (_data, next) => {
85
+ this.updateAllTabInfos();
86
+ return next();
87
+ });
88
+ }
89
+ // locale
90
+ this.$watch(
91
+ () => {
92
+ return this.app.meta.locale.current;
93
+ },
94
+ () => {
95
+ this.updateAllTabInfos();
96
+ },
97
+ );
98
+ }
99
+
100
+ protected __dispose__() {
101
+ if (this._eventSsrHmrReload) {
102
+ this._eventSsrHmrReload();
103
+ }
104
+ }
105
+
106
+ get cache() {
107
+ return this.tabsOptions.cache;
108
+ }
109
+
110
+ // need not async
111
+ addTab(tab: RouteTabTransient, affix?: boolean): boolean {
112
+ const res = this._addTab(tab, affix);
113
+ // current
114
+ this.tabKeyCurrent = res ? tab.tabKey : undefined;
115
+ this.componentKeyCurrent = res ? tab.componentKey : undefined;
116
+ return res;
117
+ }
118
+
119
+ // need not async
120
+ _addTab(tab: Partial<RouteTabTransient>, affix?: boolean): boolean {
121
+ const tabKey = tab.tabKey;
122
+ if (!tabKey) return false;
123
+ // tab
124
+ const [index, tabOld] = this.findTab(tabKey);
125
+ // tabInfo
126
+ const tabInfo = this.tabsOptions.getTabInfo?.(tabKey) ?? tabOld?.info;
127
+ if (!tabInfo) return false;
128
+ // tabs
129
+ if (index === -1) {
130
+ // new
131
+ const items: IRouteViewRouteItem[] = tab.componentKey
132
+ ? [
133
+ {
134
+ componentKey: tab.componentKey!,
135
+ fullPath: tab.fullPath!,
136
+ keepAlive: tab.keepAlive,
137
+ updatedAt: Date.now(),
138
+ },
139
+ ]
140
+ : [];
141
+ const tabNew: RouteTab = {
142
+ tabKey,
143
+ affix,
144
+ items,
145
+ updatedAt: Date.now(),
146
+ info: tabInfo,
147
+ };
148
+ if (this.tabCurrentIndex === -1) {
149
+ this.tabs = mutate(this.tabs, copyState => {
150
+ copyState.push(tabNew);
151
+ });
152
+ } else {
153
+ this.tabs = mutate(this.tabs, copyState => {
154
+ copyState.splice(this.tabCurrentIndex + 1, 0, tabNew);
155
+ });
156
+ }
157
+ // need not await
158
+ this.pruneTabs();
159
+ } else {
160
+ // update tabInfo
161
+ if (!deepEqual(tabInfo, tabOld?.info)) {
162
+ this.updateTabInfo(tabKey);
163
+ }
164
+ // update
165
+ if (!this._checkIfTabNeedUpdate(tabOld!, tab)) {
166
+ return true;
167
+ }
168
+ this.updateTab(tab);
169
+ // need not await
170
+ this.pruneTabItems(tabKey);
171
+ }
172
+ return true;
173
+ }
174
+
175
+ updateAllTabInfos(tabInitials?: RouteTabInitial[]) {
176
+ for (const tab of this.tabs) {
177
+ const tabInitial = tabInitials?.find(item => item.tabKey === tab.tabKey);
178
+ this.updateTabInfo(tab.tabKey, tabInitial);
179
+ }
180
+ }
181
+
182
+ updateTabInfo(tabKey?: string, tabInitial?: RouteTabInitial) {
183
+ if (!tabKey) return;
184
+ // tabs
185
+ const [index, tabOld] = this.findTab(tabKey);
186
+ if (index === -1) return;
187
+ // tabInfo
188
+ const tabInfo = this.tabsOptions.getTabInfo ? this.tabsOptions.getTabInfo(tabKey) : (tabInitial?.info ?? tabOld?.info);
189
+ if (!tabInfo) return;
190
+ // update
191
+ const tabNew = { ...tabOld, info: tabInfo };
192
+ this.updateTab(tabNew);
193
+ }
194
+
195
+ updateTabItemPageMeta(tabKey?: string, componentKey?: string, pageMeta?: IPageMeta) {
196
+ if (!tabKey || !componentKey) return false;
197
+ // tab
198
+ const [index, tab] = this.findTab(tabKey);
199
+ if (index === -1 || !tab) return false;
200
+ // tabItem
201
+ if (!tab.items) return false;
202
+ const indexItem = tab.items.findIndex(item => item.componentKey === componentKey);
203
+ if (indexItem === -1) return false;
204
+ const tabItem = tab.items[indexItem];
205
+ // change tab item
206
+ const pageMetaNew: IPageMeta = { ...tabItem.pageMeta, ...pageMeta };
207
+ const tabItemNew: IRouteViewRouteItem = { ...tabItem, pageMeta: pageMetaNew };
208
+ const items = mutate(tab.items, copyState => {
209
+ copyState.splice(indexItem, 1, tabItemNew);
210
+ });
211
+ const tabNew: RouteTab = { ...tab, items };
212
+ this.tabs = mutate(this.tabs, copyState => {
213
+ copyState.splice(index, 1, tabNew);
214
+ });
215
+ return true;
216
+ }
217
+
218
+ async deleteTab(tabKey?: string, noActiveNext?: boolean) {
219
+ if (!tabKey) return;
220
+ // tabs
221
+ const [index] = this.findTab(tabKey);
222
+ if (index === -1) return;
223
+ // current
224
+ let tabKeyActiveNext;
225
+ if (!noActiveNext && index === this.tabCurrentIndex) {
226
+ // prev/next
227
+ const tabCurrentIndex = index - 1 > -1 ? index - 1 : index + 1 < this.tabs.length ? index + 1 : -1;
228
+ if (tabCurrentIndex > -1) {
229
+ tabKeyActiveNext = this.tabs[tabCurrentIndex]?.tabKey;
230
+ }
231
+ }
232
+ // tabs
233
+ this.tabs = mutate(this.tabs, copyState => {
234
+ copyState.splice(index, 1);
235
+ });
236
+ // active next
237
+ if (tabKeyActiveNext) {
238
+ await this.activeTab(tabKeyActiveNext);
239
+ }
240
+ }
241
+
242
+ async deleteTabItem(tabKey?: string, componentKey?: string, noActiveNext?: boolean) {
243
+ if (!tabKey || !componentKey) return false;
244
+ if (tabKey === componentKey) return false; // not delete first tabItem
245
+ // tab
246
+ const [index, tab] = this.findTab(tabKey);
247
+ if (index === -1 || !tab) return false;
248
+ // indexItem
249
+ if (!tab.items) return false;
250
+ const indexItem = tab.items.findIndex(item => item.componentKey === componentKey);
251
+ if (indexItem === -1) return false;
252
+ if (tab.items.length === 1 && !tab.affix) {
253
+ // delete tab
254
+ await this.deleteTab(tabKey, noActiveNext);
255
+ } else {
256
+ // delete tab item
257
+ const items = mutate(tab.items, copyState => {
258
+ copyState.splice(indexItem, 1);
259
+ });
260
+ const tabNew: RouteTab = { ...tab, items };
261
+ this.tabs = mutate(this.tabs, copyState => {
262
+ copyState.splice(index, 1, tabNew);
263
+ });
264
+ }
265
+ return true;
266
+ }
267
+
268
+ findTabItemByFullPath(fullPath: string) {
269
+ for (const tab of this.tabs) {
270
+ if (!tab.items) continue;
271
+ for (const item of tab.items) {
272
+ if (item.fullPath === fullPath) {
273
+ return [tab.tabKey, item.componentKey];
274
+ }
275
+ }
276
+ }
277
+ return [];
278
+ }
279
+
280
+ updateTab(tab: Partial<RouteTabTransient>) {
281
+ const tabKey = tab.tabKey!;
282
+ const [index, tabOld] = this.findTab(tabKey);
283
+ if (index === -1 || !tabOld) return;
284
+ const items: IRouteViewRouteItem[] = tabOld.items ? ([] as IRouteViewRouteItem[]).concat(tabOld.items) : [];
285
+ if (tab.componentKey) {
286
+ const tabItem: IRouteViewRouteItem = {
287
+ componentKey: tab.componentKey,
288
+ fullPath: tab.fullPath!,
289
+ keepAlive: tab.keepAlive,
290
+ updatedAt: Date.now(),
291
+ };
292
+ const index = items.findIndex(item => item.componentKey === tab.componentKey);
293
+ if (index === -1) {
294
+ items.push(tabItem);
295
+ } else {
296
+ const tabItemNew: IRouteViewRouteItem = { ...items[index], ...tabItem };
297
+ items.splice(index, 1, tabItemNew);
298
+ }
299
+ // not use fullPath, because fullPath has query string
300
+ items.sort((a, b) => (a.componentKey === tabKey ? 0 : 1) - (b.componentKey === tabKey ? 0 : 1));
301
+ }
302
+ const tabNew: RouteTab = {
303
+ ...tabOld,
304
+ ...tab,
305
+ tabKey,
306
+ items,
307
+ updatedAt: Date.now(),
308
+ };
309
+ this.tabs = mutate(this.tabs, copyState => {
310
+ copyState.splice(index, 1, tabNew);
311
+ });
312
+ }
313
+
314
+ async activeTab(tabKey?: string) {
315
+ if (!tabKey) return;
316
+ const [_, tab] = this.findTab(tabKey);
317
+ if (!tab) return;
318
+ // should not updateTab here
319
+ // this.updateTab({ tabKey });
320
+ // this.tabKeyCurrent = tabKey;
321
+ // first check tab.items?.[0]?.fullPath, because fullPath maybe has query string
322
+ const tabItemFirst = tab.items?.[0];
323
+ const path = tabItemFirst?.componentKey === tabKey ? tabItemFirst.fullPath : tabKey;
324
+ await this.$router.push(path);
325
+ }
326
+
327
+ async activeTabItem(tabKey?: string, componentKey?: string) {
328
+ if (!tabKey || !componentKey) return;
329
+ const [_, tab] = this.findTab(tabKey);
330
+ if (!tab) return;
331
+ const tabItem = tab.items?.find(item => item.componentKey === componentKey);
332
+ if (!tabItem) return;
333
+ //
334
+ const path = tabItem.fullPath;
335
+ await this.$router.push(path);
336
+ }
337
+
338
+ findTab(tabKey?: string): [number, RouteTab | undefined] {
339
+ if (!tabKey) return [-1, undefined];
340
+ const index = this.tabs.findIndex(item => item.tabKey === tabKey);
341
+ if (index === -1) return [index, undefined];
342
+ return [index, this.tabs[index]];
343
+ }
344
+
345
+ async pruneTabs() {
346
+ let max = this.tabsOptions.max;
347
+ if (max === undefined || max === -1) return;
348
+ if (max < 1) max = 1;
349
+ while (true) {
350
+ const affixCount = this.tabs.filter(item => item.affix).length;
351
+ if (this.tabs.length - affixCount <= max) break;
352
+ let tabKey: string | undefined;
353
+ let updatedAt = Date.now();
354
+ for (const tab of this.tabs) {
355
+ if (!tab.affix && tab.updatedAt < updatedAt) {
356
+ tabKey = tab.tabKey;
357
+ updatedAt = tab.updatedAt;
358
+ }
359
+ }
360
+ if (!tabKey) break;
361
+ await this.deleteTab(tabKey, true);
362
+ }
363
+ }
364
+
365
+ async pruneTabItems(tabKey?: string) {
366
+ if (!tabKey) return;
367
+ let maxItems = this.tabsOptions.maxItems;
368
+ if (maxItems === undefined || maxItems === -1) return;
369
+ if (maxItems < 1) maxItems = 1;
370
+ while (true) {
371
+ const [_, tab] = this.findTab(tabKey);
372
+ if (!tab || !tab.items) break;
373
+ const ignoreCount = tab.items.filter(item => item.componentKey === tabKey).length;
374
+ if (tab.items.length - ignoreCount <= maxItems) break;
375
+ let componentKey: string | undefined;
376
+ let updatedAt = Date.now();
377
+ for (const tabItem of tab.items) {
378
+ if (tabItem.componentKey !== tabKey && tabItem.updatedAt < updatedAt) {
379
+ componentKey = tabItem.componentKey;
380
+ updatedAt = tabItem.updatedAt;
381
+ }
382
+ }
383
+ if (!componentKey) break;
384
+ await this.deleteTabItem(tabKey, componentKey, true);
385
+ }
386
+ }
387
+
388
+ // special for _addTab
389
+ private _checkIfTabNeedUpdate(tabOld: RouteTab, tabNew: Partial<RouteTabTransient>) {
390
+ for (const key in tabNew) {
391
+ if (['fullPath', 'keepAlive', 'updatedAt'].includes(key)) continue;
392
+ if (['componentKey'].includes(key)) {
393
+ if (!tabOld.items) return true;
394
+ const tabItemOld = tabOld.items.find(item => item[key] === tabNew[key]);
395
+ if (!tabItemOld) return true;
396
+ for (const key2 of ['fullPath', 'keepAlive']) {
397
+ if (tabItemOld[key2] !== tabNew[key2]) return true;
398
+ }
399
+ const recentItemIndex = tabOld.items.findIndex(item => item[key] !== tabItemOld[key] && (item.updatedAt ?? 0) >= (tabItemOld.updatedAt ?? 0));
400
+ if (recentItemIndex > -1) return true;
401
+ } else if (tabNew[key] !== tabOld[key]) {
402
+ return true;
403
+ }
404
+ }
405
+ const recentTabIndex = this.tabs.findIndex(item => item.tabKey !== tabOld.tabKey && (item.updatedAt ?? 0) >= (tabOld.updatedAt ?? 0));
406
+ if (recentTabIndex > -1) return true;
407
+ return false;
408
+ }
409
+
410
+ private _getKeepAliveInclude() {
411
+ const include: string[] = [];
412
+ for (const tab of this.tabs) {
413
+ if (!tab.items) continue;
414
+ for (const item of tab.items) {
415
+ if (item.keepAlive !== false && item.componentKey) {
416
+ if (!include.includes(item.componentKey)) {
417
+ include.push(item.componentKey);
418
+ }
419
+ }
420
+ }
421
+ }
422
+ return include;
423
+ }
424
+
425
+ private _getInitialTabs() {
426
+ const tabs = this.tabsOptions.getInitialTabs?.() ?? [];
427
+ if (!this.tabsOptions.getTabInfo) return tabs;
428
+ return tabs.map(tab => {
429
+ return {
430
+ ...tab,
431
+ info: this.tabsOptions.getTabInfo?.(tab.tabKey) ?? tab.info,
432
+ };
433
+ });
434
+ }
435
+
436
+ backRoute(route: RouteLocationNormalizedLoadedGeneric) {
437
+ const [tabKey, componentKey] = this.findTabItemByFullPath(route.fullPath);
438
+ this.deleteTabItem(tabKey, componentKey, true);
439
+ }
440
+
441
+ forwardRoute(route: RouteLocationNormalizedLoadedGeneric) {
442
+ const routeMeta = this.prepareRouteMeta(route);
443
+ this.addTab(routeMeta);
444
+ }
445
+
446
+ public setPageMeta(route: RouteLocationNormalizedLoadedGeneric, pageMeta: IPageMeta) {
447
+ const [tabKey, componentKey] = this.findTabItemByFullPath(route.fullPath);
448
+ this.updateTabItemPageMeta(tabKey, componentKey, pageMeta);
449
+ }
450
+
451
+ prepareRouteMeta(route: RouteLocationNormalizedLoadedGeneric): IRouteViewRouteMeta {
452
+ // fullPath
453
+ const fullPath = route.fullPath;
454
+ // componentKey
455
+ const componentKey = this.__handleRoutePropComponentKey(route);
456
+ // tabKey
457
+ const tabKey = this._handleRouteProp(route, 'tabKey') || componentKey;
458
+ // keepAlive
459
+ const keepAlive = this._handleRouteProp(route, 'keepAlive');
460
+ // tab
461
+ return { tabKey, componentKey, fullPath, keepAlive };
462
+ }
463
+
464
+ private _handleRouteProp(route: RouteLocationNormalizedLoaded, prop: 'componentKey' | 'tabKey'): string;
465
+ private _handleRouteProp(route: RouteLocationNormalizedLoaded, prop: 'keepAlive'): boolean;
466
+ private _handleRouteProp(route: RouteLocationNormalizedLoaded, prop) {
467
+ let value = route.meta[prop];
468
+ if (typeof value === 'function') {
469
+ value = value.call(this.app, route);
470
+ }
471
+ return value;
472
+ }
473
+
474
+ private __handleRoutePropComponentKey(route: RouteLocationNormalizedLoaded) {
475
+ const componentKey = this._handleRouteProp(route, 'componentKey');
476
+ if (componentKey) return componentKey;
477
+ // name
478
+ const name = this.$router.getRealRouteName(route.name);
479
+ // path
480
+ if (!name) return route.path;
481
+ // name: nameOnly
482
+ if (route.meta.componentKeyMode === 'nameOnly') return name;
483
+ // name: withParams
484
+ return route.path;
485
+ }
486
+ }
@@ -0,0 +1 @@
1
+ export * from './tabs.js';
@@ -0,0 +1,40 @@
1
+ import type { IRouteViewRouteItem, IRouteViewRouteMeta } from 'zova-module-a-router';
2
+
3
+ export interface RouteTabInfo {
4
+ title?: string;
5
+ icon?: string;
6
+ link?: string;
7
+ external?: boolean;
8
+ target?: string;
9
+ folder?: boolean;
10
+ children?: RouteTabInfo[];
11
+ }
12
+
13
+ export interface RouteTabBase {
14
+ tabKey: string;
15
+ affix?: boolean;
16
+ }
17
+
18
+ export interface RouteTabInitial extends RouteTabBase {
19
+ info?: RouteTabInfo;
20
+ }
21
+
22
+ export interface RouteTabTransient extends IRouteViewRouteMeta {}
23
+
24
+ export interface RouteTab extends RouteTabBase {
25
+ items?: IRouteViewRouteItem[];
26
+ updatedAt: number;
27
+ info: RouteTabInfo;
28
+ }
29
+
30
+ export interface ModelTabsOptionsBase {
31
+ /** -1: infinite 0: Affix Only */
32
+ max?: number;
33
+ maxItems?: number;
34
+ cache?: boolean;
35
+ }
36
+
37
+ export interface ModelTabsOptions extends ModelTabsOptionsBase {
38
+ getInitialTabs?: () => RouteTabInitial[] | undefined;
39
+ getTabInfo?: (tabKey: string) => RouteTabInfo | undefined;
40
+ }