vue3-router-tab 1.1.1 → 1.1.2
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/dist/vue3-router-tab.js +199 -199
- package/dist/vue3-router-tab.umd.cjs +1 -1
- package/index.d.ts +96 -0
- package/lib/components/RouterTab.vue +8 -4
- package/lib/persistence.ts +3 -1
- package/package.json +1 -1
package/dist/vue3-router-tab.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import './vue3-router-tab.css';
|
|
2
|
-
import { reactive as
|
|
3
|
-
import { RouterView as
|
|
4
|
-
function
|
|
2
|
+
import { reactive as ye, ref as Z, shallowRef as _e, computed as I, watch as P, nextTick as oe, inject as ae, getCurrentInstance as ge, onMounted as ee, defineComponent as Te, provide as Pe, onBeforeUnmount as xe, resolveComponent as $e, createElementBlock as g, openBlock as m, createElementVNode as R, createCommentVNode as w, renderSlot as Y, createVNode as E, TransitionGroup as Ke, mergeProps as j, withCtx as z, Fragment as q, renderList as le, withModifiers as O, normalizeClass as se, createTextVNode as Ie, toDisplayString as re, normalizeProps as Se, Transition as ce, createBlock as W, KeepAlive as Le, resolveDynamicComponent as ue, normalizeStyle as Me } from "vue";
|
|
3
|
+
import { RouterView as Ee } from "vue-router";
|
|
4
|
+
function je(e = {}) {
|
|
5
5
|
return {
|
|
6
6
|
initialTabs: e.initialTabs ?? [],
|
|
7
7
|
keepAlive: e.keepAlive ?? !0,
|
|
@@ -11,13 +11,13 @@ function Ee(e = {}) {
|
|
|
11
11
|
defaultRoute: e.defaultRoute ?? "/"
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
|
-
function A(e,
|
|
15
|
-
const o = e.resolve(
|
|
14
|
+
function A(e, i) {
|
|
15
|
+
const o = e.resolve(i);
|
|
16
16
|
if (!o || !o.matched.length)
|
|
17
|
-
throw new Error(`[RouterTabs] Unable to resolve route: ${String(
|
|
17
|
+
throw new Error(`[RouterTabs] Unable to resolve route: ${String(i)}`);
|
|
18
18
|
return o;
|
|
19
19
|
}
|
|
20
|
-
const
|
|
20
|
+
const ze = {
|
|
21
21
|
path: (e) => e.path,
|
|
22
22
|
fullpath: (e) => e.fullPath,
|
|
23
23
|
fullname: (e) => e.fullPath,
|
|
@@ -25,65 +25,65 @@ const je = {
|
|
|
25
25
|
name: (e) => e.name ? String(e.name) : e.fullPath
|
|
26
26
|
};
|
|
27
27
|
function _(e) {
|
|
28
|
-
const
|
|
29
|
-
if (typeof
|
|
30
|
-
const o =
|
|
28
|
+
const i = e.meta?.key;
|
|
29
|
+
if (typeof i == "function") {
|
|
30
|
+
const o = i(e);
|
|
31
31
|
if (typeof o == "string" && o.length) return o;
|
|
32
|
-
} else if (typeof
|
|
33
|
-
const o =
|
|
34
|
-
return o ? o(e) :
|
|
32
|
+
} else if (typeof i == "string" && i.length) {
|
|
33
|
+
const o = ze[i.toLowerCase()];
|
|
34
|
+
return o ? o(e) : i;
|
|
35
35
|
}
|
|
36
36
|
return e.fullPath;
|
|
37
37
|
}
|
|
38
|
-
function
|
|
38
|
+
function te(e, i) {
|
|
39
39
|
const o = e.meta?.keepAlive;
|
|
40
|
-
return typeof o == "boolean" ? o :
|
|
40
|
+
return typeof o == "boolean" ? o : i;
|
|
41
41
|
}
|
|
42
|
-
function
|
|
42
|
+
function ne(e, i) {
|
|
43
43
|
const o = e.meta?.reuse;
|
|
44
|
-
return typeof o == "boolean" ? o :
|
|
44
|
+
return typeof o == "boolean" ? o : i;
|
|
45
45
|
}
|
|
46
|
-
function
|
|
47
|
-
const
|
|
48
|
-
return "title" in
|
|
46
|
+
function ke(e) {
|
|
47
|
+
const i = e.meta ?? {}, o = {};
|
|
48
|
+
return "title" in i && (o.title = i.title), "tips" in i && (o.tips = i.tips), "icon" in i && (o.icon = i.icon), "closable" in i && (o.closable = i.closable), "tabClass" in i && (o.tabClass = i.tabClass), "target" in i && (o.target = i.target), "href" in i && (o.href = i.href), o;
|
|
49
49
|
}
|
|
50
|
-
function V(e,
|
|
51
|
-
const t =
|
|
50
|
+
function V(e, i, o) {
|
|
51
|
+
const t = ke(e);
|
|
52
52
|
return {
|
|
53
53
|
id: _(e),
|
|
54
54
|
to: e.fullPath,
|
|
55
55
|
fullPath: e.fullPath,
|
|
56
56
|
matched: e,
|
|
57
|
-
alive:
|
|
58
|
-
reusable:
|
|
57
|
+
alive: te(e, o),
|
|
58
|
+
reusable: ne(e, !1),
|
|
59
59
|
closable: t.closable ?? !0,
|
|
60
60
|
...t,
|
|
61
|
-
...
|
|
61
|
+
...i
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
-
function
|
|
65
|
-
if (!e.find((d) => d.id ===
|
|
64
|
+
function X(e, i, o, t) {
|
|
65
|
+
if (!e.find((d) => d.id === i.id)) {
|
|
66
66
|
if (o === "next" && t) {
|
|
67
67
|
const d = e.findIndex((b) => b.id === t);
|
|
68
68
|
if (d > -1) {
|
|
69
|
-
e.splice(d + 1, 0,
|
|
69
|
+
e.splice(d + 1, 0, i);
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
e.push(
|
|
73
|
+
e.push(i);
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
-
function
|
|
77
|
-
if (!
|
|
76
|
+
function fe(e, i, o) {
|
|
77
|
+
if (!i || i <= 0) return;
|
|
78
78
|
const t = e.filter((r) => r.alive);
|
|
79
|
-
for (; t.length >
|
|
79
|
+
for (; t.length > i; ) {
|
|
80
80
|
const r = t.shift();
|
|
81
81
|
if (!r || r.id === o) continue;
|
|
82
82
|
const d = e.findIndex((b) => b.id === r.id);
|
|
83
83
|
d > -1 && (e[d].alive = !1);
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
function
|
|
86
|
+
function Oe(e) {
|
|
87
87
|
return {
|
|
88
88
|
to: e.to,
|
|
89
89
|
title: e.title,
|
|
@@ -93,31 +93,31 @@ function ze(e) {
|
|
|
93
93
|
closable: e.closable
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
|
-
function
|
|
97
|
-
const
|
|
98
|
-
return "title" in e && (
|
|
96
|
+
function Ve(e) {
|
|
97
|
+
const i = {};
|
|
98
|
+
return "title" in e && (i.title = e.title), "tips" in e && (i.tips = e.tips), "icon" in e && (i.icon = e.icon), "tabClass" in e && (i.tabClass = e.tabClass), "closable" in e && (i.closable = e.closable), i;
|
|
99
99
|
}
|
|
100
|
-
function
|
|
101
|
-
const o =
|
|
100
|
+
function De(e, i = {}) {
|
|
101
|
+
const o = je(i), t = ye([]), r = Z(null), d = _e(), b = Z(null), l = I(() => t.filter((a) => a.alive).map((a) => a.id));
|
|
102
102
|
let u = !1;
|
|
103
103
|
function T(a) {
|
|
104
104
|
const s = typeof a.matched == "object" ? a : A(e, a);
|
|
105
105
|
return {
|
|
106
106
|
key: _(s),
|
|
107
107
|
fullPath: s.fullPath,
|
|
108
|
-
alive:
|
|
109
|
-
reusable:
|
|
108
|
+
alive: te(s, o.keepAlive),
|
|
109
|
+
reusable: ne(s, !1),
|
|
110
110
|
matched: s
|
|
111
111
|
};
|
|
112
112
|
}
|
|
113
113
|
function C(a) {
|
|
114
114
|
const s = _(a);
|
|
115
115
|
let c = t.find((p) => p.id === s);
|
|
116
|
-
return c ? (c.fullPath = a.fullPath, c.to = a.fullPath, c.matched = a, c.alive =
|
|
116
|
+
return c ? (c.fullPath = a.fullPath, c.to = a.fullPath, c.matched = a, c.alive = te(a, o.keepAlive), c.reusable = ne(a, c.reusable), Object.assign(c, ke(a)), c) : (c = V(a, {}, o.keepAlive), X(t, c, o.appendPosition, r.value), fe(t, o.maxAlive, r.value), c);
|
|
117
117
|
}
|
|
118
118
|
async function S(a, s = !1, c = !0) {
|
|
119
|
-
const p = A(e, a), k = _(p),
|
|
120
|
-
c === "sameTab" && (c =
|
|
119
|
+
const p = A(e, a), k = _(p), n = r.value === k;
|
|
120
|
+
c === "sameTab" && (c = n), c && await v(k, !0), await e[s ? "replace" : "push"](p), n && await $();
|
|
121
121
|
}
|
|
122
122
|
function L(a) {
|
|
123
123
|
const s = t.findIndex((p) => p.id === a), c = t[s] || t[s - 1] || t[0];
|
|
@@ -139,13 +139,13 @@ function Ve(e, n = {}) {
|
|
|
139
139
|
c !== -1 && (t.splice(c, 1), b.value === a && (b.value = null), r.value === a && (r.value = null, d.value = void 0));
|
|
140
140
|
}
|
|
141
141
|
async function v(a = r.value ?? void 0, s = !1) {
|
|
142
|
-
a && (b.value = a, await
|
|
142
|
+
a && (b.value = a, await oe(), s || await oe(), b.value = null);
|
|
143
143
|
}
|
|
144
|
-
async function
|
|
144
|
+
async function U(a = !1) {
|
|
145
145
|
for (const s of t)
|
|
146
146
|
await v(s.id, a);
|
|
147
147
|
}
|
|
148
|
-
async function
|
|
148
|
+
async function B(a = o.defaultRoute) {
|
|
149
149
|
t.splice(0, t.length), r.value = null, d.value = void 0;
|
|
150
150
|
for (const s of o.initialTabs) {
|
|
151
151
|
const c = A(e, s.to), p = V(c, s, o.keepAlive);
|
|
@@ -157,23 +157,23 @@ function Ve(e, n = {}) {
|
|
|
157
157
|
const a = r.value;
|
|
158
158
|
a && await v(a, !0);
|
|
159
159
|
}
|
|
160
|
-
function
|
|
160
|
+
function F(a) {
|
|
161
161
|
return typeof a.matched == "object" ? _(a) : _(A(e, a));
|
|
162
162
|
}
|
|
163
|
-
function
|
|
163
|
+
function G() {
|
|
164
164
|
const a = t.find((s) => s.id === r.value);
|
|
165
165
|
return {
|
|
166
|
-
tabs: t.map(
|
|
166
|
+
tabs: t.map(Oe),
|
|
167
167
|
active: a ? a.to : null
|
|
168
168
|
};
|
|
169
169
|
}
|
|
170
|
-
async function
|
|
170
|
+
async function K(a) {
|
|
171
171
|
u = !0, t.splice(0, t.length), r.value = null, d.value = void 0;
|
|
172
172
|
const s = a?.tabs ?? [];
|
|
173
173
|
for (const p of s)
|
|
174
174
|
try {
|
|
175
|
-
const k = A(e, p.to),
|
|
176
|
-
|
|
175
|
+
const k = A(e, p.to), n = Ve(p), f = V(k, n, o.keepAlive);
|
|
176
|
+
X(t, f, "last", null);
|
|
177
177
|
} catch {
|
|
178
178
|
}
|
|
179
179
|
u = !1;
|
|
@@ -189,12 +189,12 @@ function Ve(e, n = {}) {
|
|
|
189
189
|
(a) => {
|
|
190
190
|
if (u) return;
|
|
191
191
|
const s = C(a);
|
|
192
|
-
r.value = s.id, d.value = s,
|
|
192
|
+
r.value = s.id, d.value = s, fe(t, o.maxAlive, r.value);
|
|
193
193
|
},
|
|
194
194
|
{ immediate: !0 }
|
|
195
195
|
), o.initialTabs.length && o.initialTabs.forEach((a) => {
|
|
196
196
|
const s = A(e, a.to), c = V(s, a, o.keepAlive);
|
|
197
|
-
|
|
197
|
+
X(t, c, "last", null);
|
|
198
198
|
}), {
|
|
199
199
|
options: o,
|
|
200
200
|
tabs: t,
|
|
@@ -206,40 +206,40 @@ function Ve(e, n = {}) {
|
|
|
206
206
|
closeTab: x,
|
|
207
207
|
removeTab: M,
|
|
208
208
|
refreshTab: v,
|
|
209
|
-
refreshAll:
|
|
210
|
-
reset:
|
|
209
|
+
refreshAll: U,
|
|
210
|
+
reset: B,
|
|
211
211
|
reload: $,
|
|
212
|
-
getRouteKey:
|
|
212
|
+
getRouteKey: F,
|
|
213
213
|
matchRoute: T,
|
|
214
|
-
snapshot:
|
|
215
|
-
hydrate:
|
|
214
|
+
snapshot: G,
|
|
215
|
+
hydrate: K
|
|
216
216
|
};
|
|
217
217
|
}
|
|
218
|
-
function
|
|
218
|
+
function de(e) {
|
|
219
219
|
return e ? typeof e == "string" ? { name: e } : e : {};
|
|
220
220
|
}
|
|
221
|
-
const
|
|
222
|
-
function
|
|
223
|
-
const { optional:
|
|
221
|
+
const N = Symbol("RouterTabsContext"), D = "router-tabs:snapshot";
|
|
222
|
+
function be(e = {}) {
|
|
223
|
+
const { optional: i = !1 } = e, o = ae(N, null);
|
|
224
224
|
if (o) return o;
|
|
225
|
-
const t =
|
|
225
|
+
const t = ae("$tabs", null);
|
|
226
226
|
if (t) return t;
|
|
227
|
-
const d =
|
|
227
|
+
const d = ge()?.appContext.config.globalProperties.$tabs;
|
|
228
228
|
if (d) return d;
|
|
229
|
-
if (!
|
|
229
|
+
if (!i)
|
|
230
230
|
throw new Error("[RouterTabs] useRouterTabs must be used within <router-tab>.");
|
|
231
231
|
return null;
|
|
232
232
|
}
|
|
233
233
|
const Ne = 864e5;
|
|
234
234
|
function Ue(e) {
|
|
235
235
|
if (typeof document > "u") return null;
|
|
236
|
-
const
|
|
236
|
+
const i = `${encodeURIComponent(e)}=`, o = document.cookie ? document.cookie.split("; ") : [];
|
|
237
237
|
for (const t of o)
|
|
238
|
-
if (t.startsWith(
|
|
239
|
-
return decodeURIComponent(t.slice(
|
|
238
|
+
if (t.startsWith(i))
|
|
239
|
+
return decodeURIComponent(t.slice(i.length));
|
|
240
240
|
return null;
|
|
241
241
|
}
|
|
242
|
-
function
|
|
242
|
+
function pe(e, i, o) {
|
|
243
243
|
if (typeof document > "u") return;
|
|
244
244
|
const {
|
|
245
245
|
expiresInDays: t = 7,
|
|
@@ -247,16 +247,16 @@ function be(e, n, o) {
|
|
|
247
247
|
domain: d,
|
|
248
248
|
secure: b,
|
|
249
249
|
sameSite: l = "lax"
|
|
250
|
-
} = o, u = [`${encodeURIComponent(e)}=${encodeURIComponent(
|
|
250
|
+
} = o, u = [`${encodeURIComponent(e)}=${encodeURIComponent(i)}`];
|
|
251
251
|
if (t !== 1 / 0) {
|
|
252
252
|
const T = new Date(Date.now() + t * Ne).toUTCString();
|
|
253
253
|
u.push(`Expires=${T}`);
|
|
254
254
|
}
|
|
255
255
|
r && u.push(`Path=${r}`), d && u.push(`Domain=${d}`), b && u.push("Secure"), l && u.push(`SameSite=${l.charAt(0).toUpperCase()}${l.slice(1)}`), document.cookie = u.join("; ");
|
|
256
256
|
}
|
|
257
|
-
function
|
|
257
|
+
function he(e, i) {
|
|
258
258
|
if (typeof document > "u") return;
|
|
259
|
-
const { path: o = "/", domain: t } =
|
|
259
|
+
const { path: o = "/", domain: t } = i, r = [`${encodeURIComponent(e)}=`];
|
|
260
260
|
r.push("Expires=Thu, 01 Jan 1970 00:00:01 GMT"), o && r.push(`Path=${o}`), t && r.push(`Domain=${t}`), document.cookie = r.join("; ");
|
|
261
261
|
}
|
|
262
262
|
const Be = (e) => JSON.stringify(e ?? null), Fe = (e) => {
|
|
@@ -267,14 +267,14 @@ const Be = (e) => JSON.stringify(e ?? null), Fe = (e) => {
|
|
|
267
267
|
return null;
|
|
268
268
|
}
|
|
269
269
|
};
|
|
270
|
-
function
|
|
270
|
+
function Ce(e = {}) {
|
|
271
271
|
const {
|
|
272
|
-
cookieKey:
|
|
272
|
+
cookieKey: i = D,
|
|
273
273
|
serialize: o = Be,
|
|
274
274
|
deserialize: t = Fe
|
|
275
|
-
} = e, r =
|
|
276
|
-
|
|
277
|
-
const u = t(Ue(
|
|
275
|
+
} = e, r = be({ optional: !0 }), d = Z(!0), b = (l) => {
|
|
276
|
+
ee(async () => {
|
|
277
|
+
const u = t(Ue(i));
|
|
278
278
|
if (u && u.tabs?.length)
|
|
279
279
|
try {
|
|
280
280
|
d.value = !0, await l.hydrate(u);
|
|
@@ -290,7 +290,7 @@ function ke(e = {}) {
|
|
|
290
290
|
d.value = !1;
|
|
291
291
|
}
|
|
292
292
|
const T = l.snapshot();
|
|
293
|
-
T.tabs.length ?
|
|
293
|
+
T.tabs.length ? pe(i, o(T), e) : he(i, e), d.value = !1;
|
|
294
294
|
}), P(
|
|
295
295
|
() => ({
|
|
296
296
|
tabs: l.tabs.map((u) => ({
|
|
@@ -306,19 +306,19 @@ function ke(e = {}) {
|
|
|
306
306
|
() => {
|
|
307
307
|
if (d.value) return;
|
|
308
308
|
const u = l.snapshot();
|
|
309
|
-
u.tabs.length ?
|
|
309
|
+
u.tabs.length ? pe(i, o(u), e) : he(i, e);
|
|
310
310
|
},
|
|
311
311
|
{ deep: !0 }
|
|
312
312
|
);
|
|
313
313
|
};
|
|
314
|
-
r ? b(r) :
|
|
315
|
-
const l =
|
|
314
|
+
r ? b(r) : ee(() => {
|
|
315
|
+
const l = be({ optional: !0 });
|
|
316
316
|
l && b(l);
|
|
317
317
|
});
|
|
318
318
|
}
|
|
319
|
-
const Ge =
|
|
319
|
+
const Ge = Te({
|
|
320
320
|
name: "RouterTab",
|
|
321
|
-
components: { RouterView:
|
|
321
|
+
components: { RouterView: Ee },
|
|
322
322
|
props: {
|
|
323
323
|
tabs: {
|
|
324
324
|
type: Array,
|
|
@@ -358,7 +358,7 @@ const Ge = ge({
|
|
|
358
358
|
},
|
|
359
359
|
cookieKey: {
|
|
360
360
|
type: String,
|
|
361
|
-
default:
|
|
361
|
+
default: D
|
|
362
362
|
},
|
|
363
363
|
persistence: {
|
|
364
364
|
type: Object,
|
|
@@ -366,13 +366,13 @@ const Ge = ge({
|
|
|
366
366
|
}
|
|
367
367
|
},
|
|
368
368
|
setup(e) {
|
|
369
|
-
const
|
|
370
|
-
if (!
|
|
369
|
+
const i = ge();
|
|
370
|
+
if (!i)
|
|
371
371
|
throw new Error("[RouterTab] component must be used within a Vue application context.");
|
|
372
|
-
const o =
|
|
372
|
+
const o = i.appContext.app.config.globalProperties.$router;
|
|
373
373
|
if (!o)
|
|
374
374
|
throw new Error("[RouterTab] Vue Router is required. Make sure to call app.use(router) before RouterTab.");
|
|
375
|
-
const t =
|
|
375
|
+
const t = De(o, {
|
|
376
376
|
initialTabs: e.tabs,
|
|
377
377
|
keepAlive: e.keepAlive,
|
|
378
378
|
maxAlive: e.maxAlive,
|
|
@@ -380,15 +380,15 @@ const Ge = ge({
|
|
|
380
380
|
appendPosition: e.append,
|
|
381
381
|
defaultRoute: e.defaultPage
|
|
382
382
|
});
|
|
383
|
-
|
|
384
|
-
const r =
|
|
385
|
-
if (e.cookieKey || e.persistence) {
|
|
386
|
-
const
|
|
383
|
+
Pe(N, t), i.appContext.config.globalProperties.$tabs = t;
|
|
384
|
+
const r = I(() => !!i?.slots?.default);
|
|
385
|
+
if (e.cookieKey !== null || e.persistence) {
|
|
386
|
+
const n = {
|
|
387
387
|
...e.persistence ?? {}
|
|
388
388
|
};
|
|
389
|
-
e.cookieKey
|
|
389
|
+
e.cookieKey !== null ? n.cookieKey = e.cookieKey || D : n.cookieKey || (n.cookieKey = D), Ce(n);
|
|
390
390
|
}
|
|
391
|
-
const d =
|
|
391
|
+
const d = I(() => de(e.tabTransition)), b = I(() => de(e.pageTransition)), l = ye({
|
|
392
392
|
visible: !1,
|
|
393
393
|
target: null,
|
|
394
394
|
position: { x: 0, y: 0 }
|
|
@@ -400,22 +400,22 @@ const Ge = ge({
|
|
|
400
400
|
"closeRights",
|
|
401
401
|
"closeOthers"
|
|
402
402
|
];
|
|
403
|
-
function T(
|
|
404
|
-
return t.tabs.findIndex((f) => f.id ===
|
|
403
|
+
function T(n) {
|
|
404
|
+
return t.tabs.findIndex((f) => f.id === n);
|
|
405
405
|
}
|
|
406
|
-
function C(
|
|
407
|
-
const f = T(
|
|
406
|
+
function C(n) {
|
|
407
|
+
const f = T(n.id);
|
|
408
408
|
return f > 0 ? t.tabs.slice(0, f) : [];
|
|
409
409
|
}
|
|
410
|
-
function S(
|
|
411
|
-
const f = T(
|
|
410
|
+
function S(n) {
|
|
411
|
+
const f = T(n.id);
|
|
412
412
|
return f > -1 ? t.tabs.slice(f + 1) : [];
|
|
413
413
|
}
|
|
414
|
-
function L(
|
|
415
|
-
return t.tabs.filter((f) => f.id !==
|
|
414
|
+
function L(n) {
|
|
415
|
+
return t.tabs.filter((f) => f.id !== n.id);
|
|
416
416
|
}
|
|
417
|
-
async function x(
|
|
418
|
-
const h =
|
|
417
|
+
async function x(n, f) {
|
|
418
|
+
const h = n.filter((y) => y.closable !== !1);
|
|
419
419
|
if (h.length) {
|
|
420
420
|
for (const y of h)
|
|
421
421
|
t.activeId.value === y.id ? await t.closeTab(y.id, { redirect: f.to, force: !0 }) : await t.removeTab(y.id, { force: !0 });
|
|
@@ -425,8 +425,8 @@ const Ge = ge({
|
|
|
425
425
|
const M = {
|
|
426
426
|
refresh: {
|
|
427
427
|
label: "Refresh",
|
|
428
|
-
handler: async ({ target:
|
|
429
|
-
await t.refreshTab(
|
|
428
|
+
handler: async ({ target: n }) => {
|
|
429
|
+
await t.refreshTab(n.id, !0);
|
|
430
430
|
}
|
|
431
431
|
},
|
|
432
432
|
refreshAll: {
|
|
@@ -437,108 +437,108 @@ const Ge = ge({
|
|
|
437
437
|
},
|
|
438
438
|
close: {
|
|
439
439
|
label: "Close",
|
|
440
|
-
handler: async ({ target:
|
|
441
|
-
await t.closeTab(
|
|
440
|
+
handler: async ({ target: n }) => {
|
|
441
|
+
await t.closeTab(n.id);
|
|
442
442
|
},
|
|
443
|
-
enable: ({ target:
|
|
443
|
+
enable: ({ target: n }) => K(n)
|
|
444
444
|
},
|
|
445
445
|
closeLefts: {
|
|
446
446
|
label: "Close to the Left",
|
|
447
|
-
handler: async ({ target:
|
|
448
|
-
await x(C(
|
|
447
|
+
handler: async ({ target: n }) => {
|
|
448
|
+
await x(C(n), n);
|
|
449
449
|
},
|
|
450
|
-
enable: ({ target:
|
|
450
|
+
enable: ({ target: n }) => C(n).some((f) => f.closable !== !1)
|
|
451
451
|
},
|
|
452
452
|
closeRights: {
|
|
453
453
|
label: "Close to the Right",
|
|
454
|
-
handler: async ({ target:
|
|
455
|
-
await x(S(
|
|
454
|
+
handler: async ({ target: n }) => {
|
|
455
|
+
await x(S(n), n);
|
|
456
456
|
},
|
|
457
|
-
enable: ({ target:
|
|
457
|
+
enable: ({ target: n }) => S(n).some((f) => f.closable !== !1)
|
|
458
458
|
},
|
|
459
459
|
closeOthers: {
|
|
460
460
|
label: "Close Others",
|
|
461
|
-
handler: async ({ target:
|
|
462
|
-
await x(L(
|
|
461
|
+
handler: async ({ target: n }) => {
|
|
462
|
+
await x(L(n), n);
|
|
463
463
|
},
|
|
464
|
-
enable: ({ target:
|
|
464
|
+
enable: ({ target: n }) => L(n).some((f) => f.closable !== !1)
|
|
465
465
|
}
|
|
466
466
|
};
|
|
467
467
|
function v() {
|
|
468
468
|
l.visible = !1, l.target = null;
|
|
469
469
|
}
|
|
470
|
-
function
|
|
471
|
-
e.contextmenu && (l.visible = !0, l.target =
|
|
470
|
+
function U(n, f) {
|
|
471
|
+
e.contextmenu && (l.visible = !0, l.target = n, l.position.x = f.clientX, l.position.y = f.clientY, document.addEventListener("click", v, { once: !0 }));
|
|
472
472
|
}
|
|
473
|
-
function
|
|
474
|
-
const h = typeof
|
|
475
|
-
if (!(typeof
|
|
476
|
-
const
|
|
477
|
-
if (!
|
|
478
|
-
const
|
|
479
|
-
await Promise.resolve(
|
|
473
|
+
function B(n, f) {
|
|
474
|
+
const h = typeof n == "string" ? { id: n } : n, y = M[h.id], Re = h.label ?? y?.label ?? String(h.id), J = h.visible ?? y?.visible ?? !0;
|
|
475
|
+
if (!(typeof J == "function" ? J(f) : J !== !1)) return null;
|
|
476
|
+
const H = h.enable ?? y?.enable ?? !0, we = typeof H == "function" ? H(f) : H !== !1, ie = h.handler ?? y?.handler;
|
|
477
|
+
if (!ie) return null;
|
|
478
|
+
const Ae = async () => {
|
|
479
|
+
await Promise.resolve(ie(f));
|
|
480
480
|
};
|
|
481
481
|
return {
|
|
482
482
|
id: String(h.id),
|
|
483
|
-
label:
|
|
484
|
-
disabled: !
|
|
485
|
-
action:
|
|
483
|
+
label: Re,
|
|
484
|
+
disabled: !we,
|
|
485
|
+
action: Ae
|
|
486
486
|
};
|
|
487
487
|
}
|
|
488
|
-
const $ =
|
|
488
|
+
const $ = I(() => {
|
|
489
489
|
if (!l.visible || !l.target || e.contextmenu === !1) return [];
|
|
490
|
-
const
|
|
491
|
-
return
|
|
490
|
+
const n = Array.isArray(e.contextmenu) ? e.contextmenu : u, f = { target: l.target, controller: t };
|
|
491
|
+
return n.map((h) => B(h, f)).filter((h) => !!h);
|
|
492
492
|
});
|
|
493
|
-
async function
|
|
494
|
-
|
|
493
|
+
async function F(n) {
|
|
494
|
+
n.disabled || (v(), await n.action());
|
|
495
495
|
}
|
|
496
|
-
function
|
|
497
|
-
return typeof
|
|
496
|
+
function G(n) {
|
|
497
|
+
return typeof n.title == "string" ? n.title : Array.isArray(n.title) && n.title.length ? String(n.title[0]) : n.fullPath;
|
|
498
498
|
}
|
|
499
|
-
function
|
|
500
|
-
return !(
|
|
499
|
+
function K(n) {
|
|
500
|
+
return !(n.closable === !1 || t.options.keepLastTab && t.tabs.length <= 1);
|
|
501
501
|
}
|
|
502
|
-
async function a(
|
|
503
|
-
await t.closeTab(
|
|
502
|
+
async function a(n) {
|
|
503
|
+
await t.closeTab(n.id);
|
|
504
504
|
}
|
|
505
|
-
function s(
|
|
506
|
-
t.activeId.value !==
|
|
505
|
+
function s(n) {
|
|
506
|
+
t.activeId.value !== n.id && t.openTab(n.to, !1);
|
|
507
507
|
}
|
|
508
|
-
function c(
|
|
508
|
+
function c(n) {
|
|
509
509
|
return [
|
|
510
510
|
"router-tab__item",
|
|
511
511
|
{
|
|
512
|
-
"is-active": t.activeId.value ===
|
|
513
|
-
"is-closable":
|
|
512
|
+
"is-active": t.activeId.value === n.id,
|
|
513
|
+
"is-closable": K(n)
|
|
514
514
|
},
|
|
515
|
-
|
|
515
|
+
n.tabClass
|
|
516
516
|
];
|
|
517
517
|
}
|
|
518
|
-
function p(
|
|
519
|
-
return t.refreshingKey.value === t.getRouteKey(
|
|
518
|
+
function p(n) {
|
|
519
|
+
return t.refreshingKey.value === t.getRouteKey(n);
|
|
520
520
|
}
|
|
521
|
-
|
|
521
|
+
ee(() => {
|
|
522
522
|
document.addEventListener("keydown", v);
|
|
523
|
-
}),
|
|
524
|
-
document.removeEventListener("keydown", v),
|
|
523
|
+
}), xe(() => {
|
|
524
|
+
document.removeEventListener("keydown", v), i.appContext.config.globalProperties.$tabs = null;
|
|
525
525
|
}), P(
|
|
526
526
|
() => e.keepAlive,
|
|
527
|
-
(
|
|
528
|
-
t.options.keepAlive =
|
|
527
|
+
(n) => {
|
|
528
|
+
t.options.keepAlive = n;
|
|
529
529
|
}
|
|
530
530
|
), P(
|
|
531
531
|
() => t.activeId.value,
|
|
532
532
|
() => v()
|
|
533
533
|
), P(
|
|
534
534
|
() => e.contextmenu,
|
|
535
|
-
(
|
|
536
|
-
|
|
535
|
+
(n) => {
|
|
536
|
+
n || v();
|
|
537
537
|
}
|
|
538
538
|
), P(
|
|
539
539
|
() => $.value.length,
|
|
540
|
-
(
|
|
541
|
-
l.visible &&
|
|
540
|
+
(n) => {
|
|
541
|
+
l.visible && n === 0 && v();
|
|
542
542
|
}
|
|
543
543
|
);
|
|
544
544
|
const k = t.includeKeys;
|
|
@@ -553,37 +553,37 @@ const Ge = ge({
|
|
|
553
553
|
close: a,
|
|
554
554
|
context: l,
|
|
555
555
|
menuItems: $,
|
|
556
|
-
handleMenuAction:
|
|
557
|
-
showContextMenu:
|
|
556
|
+
handleMenuAction: F,
|
|
557
|
+
showContextMenu: U,
|
|
558
558
|
hideContextMenu: v,
|
|
559
|
-
tabTitle:
|
|
560
|
-
isClosable:
|
|
559
|
+
tabTitle: G,
|
|
560
|
+
isClosable: K,
|
|
561
561
|
isRefreshing: p,
|
|
562
562
|
hasCustomSlot: r
|
|
563
563
|
};
|
|
564
564
|
}
|
|
565
|
-
}), Je = (e,
|
|
565
|
+
}), Je = (e, i) => {
|
|
566
566
|
const o = e.__vccOpts || e;
|
|
567
|
-
for (const [t, r] of
|
|
567
|
+
for (const [t, r] of i)
|
|
568
568
|
o[t] = r;
|
|
569
569
|
return o;
|
|
570
570
|
}, He = { class: "router-tab" }, Ye = { class: "router-tab__header" }, qe = { class: "router-tab__slot-start" }, We = { class: "router-tab__scroll" }, Xe = ["onClick", "onAuxclick", "onContextmenu"], Qe = ["title"], Ze = ["onClick"], et = { class: "router-tab__slot-end" }, tt = { class: "router-tab__container" }, nt = ["aria-disabled", "onClick"];
|
|
571
|
-
function it(e,
|
|
572
|
-
const b =
|
|
571
|
+
function it(e, i, o, t, r, d) {
|
|
572
|
+
const b = $e("RouterView");
|
|
573
573
|
return m(), g("div", He, [
|
|
574
574
|
R("header", Ye, [
|
|
575
575
|
R("div", qe, [
|
|
576
|
-
|
|
576
|
+
Y(e.$slots, "start")
|
|
577
577
|
]),
|
|
578
578
|
R("div", We, [
|
|
579
|
-
E(
|
|
579
|
+
E(Ke, j({
|
|
580
580
|
tag: "ul",
|
|
581
581
|
class: "router-tab__nav"
|
|
582
582
|
}, e.tabTransitionProps), {
|
|
583
583
|
default: z(() => [
|
|
584
|
-
(m(!0), g(
|
|
584
|
+
(m(!0), g(q, null, le(e.tabs, (l) => (m(), g("li", {
|
|
585
585
|
key: l.id,
|
|
586
|
-
class:
|
|
586
|
+
class: se(e.buildTabClass(l)),
|
|
587
587
|
onClick: (u) => e.activate(l),
|
|
588
588
|
onAuxclick: O((u) => e.close(l), ["middle", "prevent"]),
|
|
589
589
|
onContextmenu: O((u) => e.showContextMenu(l, u), ["prevent"])
|
|
@@ -594,9 +594,9 @@ function it(e, n, o, t, r, d) {
|
|
|
594
594
|
}, [
|
|
595
595
|
l.icon ? (m(), g("i", {
|
|
596
596
|
key: 0,
|
|
597
|
-
class:
|
|
597
|
+
class: se(["router-tab__item-icon", l.icon])
|
|
598
598
|
}, null, 2)) : w("", !0),
|
|
599
|
-
Ie(" " +
|
|
599
|
+
Ie(" " + re(e.tabTitle(l)), 1)
|
|
600
600
|
], 8, Qe),
|
|
601
601
|
e.isClosable(l) ? (m(), g("a", {
|
|
602
602
|
key: 0,
|
|
@@ -610,21 +610,21 @@ function it(e, n, o, t, r, d) {
|
|
|
610
610
|
}, 16)
|
|
611
611
|
]),
|
|
612
612
|
R("div", et, [
|
|
613
|
-
|
|
613
|
+
Y(e.$slots, "end")
|
|
614
614
|
])
|
|
615
615
|
]),
|
|
616
616
|
R("div", tt, [
|
|
617
617
|
E(b, null, {
|
|
618
618
|
default: z((l) => [
|
|
619
|
-
e.hasCustomSlot ?
|
|
620
|
-
E(
|
|
619
|
+
e.hasCustomSlot ? Y(e.$slots, "default", Se(j({ key: 0 }, { ...l, controller: e.controller }))) : (m(), g(q, { key: 1 }, [
|
|
620
|
+
E(ce, j(e.pageTransitionProps, { appear: "" }), {
|
|
621
621
|
default: z(() => [
|
|
622
|
-
e.controller.options.keepAlive ? (m(),
|
|
622
|
+
e.controller.options.keepAlive ? (m(), W(Le, {
|
|
623
623
|
key: 0,
|
|
624
624
|
include: e.includeKeys,
|
|
625
625
|
max: e.controller.options.maxAlive || void 0
|
|
626
626
|
}, [
|
|
627
|
-
e.isRefreshing(l.route) ? w("", !0) : (m(),
|
|
627
|
+
e.isRefreshing(l.route) ? w("", !0) : (m(), W(ue(l.Component), {
|
|
628
628
|
key: e.controller.getRouteKey(l.route),
|
|
629
629
|
class: "router-tab-page"
|
|
630
630
|
}))
|
|
@@ -632,9 +632,9 @@ function it(e, n, o, t, r, d) {
|
|
|
632
632
|
]),
|
|
633
633
|
_: 2
|
|
634
634
|
}, 1040),
|
|
635
|
-
E(
|
|
635
|
+
E(ce, j(e.pageTransitionProps, { appear: "" }), {
|
|
636
636
|
default: z(() => [
|
|
637
|
-
!e.controller.options.keepAlive || e.isRefreshing(l.route) ? (m(),
|
|
637
|
+
!e.controller.options.keepAlive || e.isRefreshing(l.route) ? (m(), W(ue(l.Component), {
|
|
638
638
|
key: e.controller.getRouteKey(l.route) + (e.isRefreshing(l.route) ? "-refresh" : ""),
|
|
639
639
|
class: "router-tab-page"
|
|
640
640
|
})) : w("", !0)
|
|
@@ -649,21 +649,21 @@ function it(e, n, o, t, r, d) {
|
|
|
649
649
|
e.context.visible && e.context.target ? (m(), g("div", {
|
|
650
650
|
key: 0,
|
|
651
651
|
class: "router-tab__contextmenu",
|
|
652
|
-
style:
|
|
652
|
+
style: Me({ left: e.context.position.x + "px", top: e.context.position.y + "px" })
|
|
653
653
|
}, [
|
|
654
|
-
(m(!0), g(
|
|
654
|
+
(m(!0), g(q, null, le(e.menuItems, (l) => (m(), g("a", {
|
|
655
655
|
key: l.id,
|
|
656
656
|
class: "router-tab__contextmenu-item",
|
|
657
657
|
"aria-disabled": l.disabled,
|
|
658
658
|
onClick: O((u) => e.handleMenuAction(l), ["prevent"])
|
|
659
|
-
},
|
|
659
|
+
}, re(l.label), 9, nt))), 128))
|
|
660
660
|
], 4)) : w("", !0)
|
|
661
661
|
]);
|
|
662
662
|
}
|
|
663
|
-
const
|
|
663
|
+
const ve = /* @__PURE__ */ Je(Ge, [["render", it]]), ot = {
|
|
664
664
|
class: "router-tabs",
|
|
665
665
|
"aria-hidden": "true"
|
|
666
|
-
},
|
|
666
|
+
}, Q = /* @__PURE__ */ Te({
|
|
667
667
|
name: "RouterTabs",
|
|
668
668
|
__name: "RouterTabs",
|
|
669
669
|
props: {
|
|
@@ -678,30 +678,30 @@ const he = /* @__PURE__ */ Je(Ge, [["render", it]]), ot = {
|
|
|
678
678
|
fallbackRoute: {}
|
|
679
679
|
},
|
|
680
680
|
setup(e) {
|
|
681
|
-
return
|
|
681
|
+
return Ce(e), (o, t) => (m(), g("span", ot));
|
|
682
682
|
}
|
|
683
|
-
}),
|
|
683
|
+
}), me = {
|
|
684
684
|
install(e) {
|
|
685
|
-
if (
|
|
686
|
-
|
|
687
|
-
const
|
|
688
|
-
e.component(
|
|
685
|
+
if (me._installed) return;
|
|
686
|
+
me._installed = !0;
|
|
687
|
+
const i = ve.name || "RouterTab", o = Q.name || "RouterTabs";
|
|
688
|
+
e.component(i, ve), e.component(o, Q), o !== "router-tabs" && e.component("router-tabs", Q), Object.defineProperty(e.config.globalProperties, "$tabs", {
|
|
689
689
|
configurable: !0,
|
|
690
690
|
enumerable: !1,
|
|
691
691
|
get() {
|
|
692
|
-
return e._context.provides[
|
|
692
|
+
return e._context.provides[N];
|
|
693
693
|
},
|
|
694
694
|
set(t) {
|
|
695
|
-
t && e.provide(
|
|
695
|
+
t && e.provide(N, t);
|
|
696
696
|
}
|
|
697
697
|
});
|
|
698
698
|
}
|
|
699
699
|
};
|
|
700
700
|
export {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
701
|
+
ve as RouterTab,
|
|
702
|
+
Q as RouterTabs,
|
|
703
|
+
me as default,
|
|
704
|
+
N as routerTabsKey,
|
|
705
|
+
be as useRouterTabs,
|
|
706
|
+
Ce as useRouterTabsPersistence
|
|
707
707
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(y,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue"),require("vue-router")):typeof define=="function"&&define.amd?define(["exports","vue","vue-router"],t):(y=typeof globalThis<"u"?globalThis:y||self,t(y["vue3-router-tab"]={},y.Vue,y.VueRouter))})(this,(function(y,t,Z){"use strict";function ee(e={}){return{initialTabs:e.initialTabs??[],keepAlive:e.keepAlive??!0,maxAlive:e.maxAlive??0,keepLastTab:e.keepLastTab??!0,appendPosition:e.appendPosition??"last",defaultRoute:e.defaultRoute??"/"}}function w(e,o){const a=e.resolve(o);if(!a||!a.matched.length)throw new Error(`[RouterTabs] Unable to resolve route: ${String(o)}`);return a}const te={path:e=>e.path,fullpath:e=>e.fullPath,fullname:e=>e.fullPath,full:e=>e.fullPath,name:e=>e.name?String(e.name):e.fullPath};function R(e){const o=e.meta?.key;if(typeof o=="function"){const a=o(e);if(typeof a=="string"&&a.length)return a}else if(typeof o=="string"&&o.length){const a=te[o.toLowerCase()];return a?a(e):o}return e.fullPath}function I(e,o){const a=e.meta?.keepAlive;return typeof a=="boolean"?a:o}function K(e,o){const a=e.meta?.reuse;return typeof a=="boolean"?a:o}function J(e){const o=e.meta??{},a={};return"title"in o&&(a.title=o.title),"tips"in o&&(a.tips=o.tips),"icon"in o&&(a.icon=o.icon),"closable"in o&&(a.closable=o.closable),"tabClass"in o&&(a.tabClass=o.tabClass),"target"in o&&(a.target=o.target),"href"in o&&(a.href=o.href),a}function B(e,o,a){const n=J(e);return{id:R(e),to:e.fullPath,fullPath:e.fullPath,matched:e,alive:I(e,a),reusable:K(e,!1),closable:n.closable??!0,...n,...o}}function N(e,o,a,n){if(!e.find(b=>b.id===o.id)){if(a==="next"&&n){const b=e.findIndex(p=>p.id===n);if(b>-1){e.splice(b+1,0,o);return}}e.push(o)}}function H(e,o,a){if(!o||o<=0)return;const n=e.filter(c=>c.alive);for(;n.length>o;){const c=n.shift();if(!c||c.id===a)continue;const b=e.findIndex(p=>p.id===c.id);b>-1&&(e[b].alive=!1)}}function ne(e){return{to:e.to,title:e.title,tips:e.tips,icon:e.icon,tabClass:e.tabClass,closable:e.closable}}function oe(e){const o={};return"title"in e&&(o.title=e.title),"tips"in e&&(o.tips=e.tips),"icon"in e&&(o.icon=e.icon),"tabClass"in e&&(o.tabClass=e.tabClass),"closable"in e&&(o.closable=e.closable),o}function ie(e,o={}){const a=ee(o),n=t.reactive([]),c=t.ref(null),b=t.shallowRef(),p=t.ref(null),s=t.computed(()=>n.filter(l=>l.alive).map(l=>l.id));let f=!1;function T(l){const r=typeof l.matched=="object"?l:w(e,l);return{key:R(r),fullPath:r.fullPath,alive:I(r,a.keepAlive),reusable:K(r,!1),matched:r}}function A(l){const r=R(l);let u=n.find(m=>m.id===r);return u?(u.fullPath=l.fullPath,u.to=l.fullPath,u.matched=l,u.alive=I(l,a.keepAlive),u.reusable=K(l,u.reusable),Object.assign(u,J(l)),u):(u=B(l,{},a.keepAlive),N(n,u,a.appendPosition,c.value),H(n,a.maxAlive,c.value),u)}async function E(l,r=!1,u=!0){const m=w(e,l),C=R(m),i=c.value===C;u==="sameTab"&&(u=i),u&&await g(C,!0),await e[r?"replace":"push"](m),i&&await v()}function S(l){const r=n.findIndex(m=>m.id===l),u=n[r]||n[r-1]||n[0];return u?u.to:a.defaultRoute}async function P(l=c.value,r={}){if(l){if(!r.force&&a.keepLastTab&&n.length===1)throw new Error("[RouterTabs] Unable to close the final tab when keepLastTab is true.");if(await V(l,{force:r.force}),r.redirect!==null)if(c.value===l){const u=r.redirect??S(l);u&&await e.replace(u)}else r.redirect&&await e.replace(r.redirect)}}async function V(l,r={}){const u=n.findIndex(m=>m.id===l);u!==-1&&(n.splice(u,1),p.value===l&&(p.value=null),c.value===l&&(c.value=null,b.value=void 0))}async function g(l=c.value??void 0,r=!1){l&&(p.value=l,await t.nextTick(),r||await t.nextTick(),p.value=null)}async function D(l=!1){for(const r of n)await g(r.id,l)}async function O(l=a.defaultRoute){n.splice(0,n.length),c.value=null,b.value=void 0;for(const r of a.initialTabs){const u=w(e,r.to),m=B(u,r,a.keepAlive);n.push(m)}await e.replace(l)}async function v(){const l=c.value;l&&await g(l,!0)}function U(l){return typeof l.matched=="object"?R(l):R(w(e,l))}function F(){const l=n.find(r=>r.id===c.value);return{tabs:n.map(ne),active:l?l.to:null}}async function x(l){f=!0,n.splice(0,n.length),c.value=null,b.value=void 0;const r=l?.tabs??[];for(const m of r)try{const C=w(e,m.to),i=oe(m),d=B(C,i,a.keepAlive);N(n,d,"last",null)}catch{}f=!1;const u=l?.active??r[r.length-1]?.to??a.defaultRoute;if(u)try{await e.replace(u)}catch{}}return t.watch(()=>e.currentRoute.value,l=>{if(f)return;const r=A(l);c.value=r.id,b.value=r,H(n,a.maxAlive,c.value)},{immediate:!0}),a.initialTabs.length&&a.initialTabs.forEach(l=>{const r=w(e,l.to),u=B(r,l,a.keepAlive);N(n,u,"last",null)}),{options:a,tabs:n,activeId:c,current:b,includeKeys:s,refreshingKey:p,openTab:E,closeTab:P,removeTab:V,refreshTab:g,refreshAll:D,reset:O,reload:v,getRouteKey:U,matchRoute:T,snapshot:F,hydrate:x}}function Y(e){return e?typeof e=="string"?{name:e}:e:{}}const _=Symbol("RouterTabsContext"),ae="router-tabs:snapshot";function M(e={}){const{optional:o=!1}=e,a=t.inject(_,null);if(a)return a;const n=t.inject("$tabs",null);if(n)return n;const b=t.getCurrentInstance()?.appContext.config.globalProperties.$tabs;if(b)return b;if(!o)throw new Error("[RouterTabs] useRouterTabs must be used within <router-tab>.");return null}const le=864e5;function se(e){if(typeof document>"u")return null;const o=`${encodeURIComponent(e)}=`,a=document.cookie?document.cookie.split("; "):[];for(const n of a)if(n.startsWith(o))return decodeURIComponent(n.slice(o.length));return null}function W(e,o,a){if(typeof document>"u")return;const{expiresInDays:n=7,path:c="/",domain:b,secure:p,sameSite:s="lax"}=a,f=[`${encodeURIComponent(e)}=${encodeURIComponent(o)}`];if(n!==1/0){const T=new Date(Date.now()+n*le).toUTCString();f.push(`Expires=${T}`)}c&&f.push(`Path=${c}`),b&&f.push(`Domain=${b}`),p&&f.push("Secure"),s&&f.push(`SameSite=${s.charAt(0).toUpperCase()}${s.slice(1)}`),document.cookie=f.join("; ")}function X(e,o){if(typeof document>"u")return;const{path:a="/",domain:n}=o,c=[`${encodeURIComponent(e)}=`];c.push("Expires=Thu, 01 Jan 1970 00:00:01 GMT"),a&&c.push(`Path=${a}`),n&&c.push(`Domain=${n}`),document.cookie=c.join("; ")}const re=e=>JSON.stringify(e??null),ce=e=>{if(!e)return null;try{return JSON.parse(e)}catch{return null}};function L(e={}){const{cookieKey:o=ae,serialize:a=re,deserialize:n=ce}=e,c=M({optional:!0}),b=t.ref(!1),p=s=>{t.onMounted(async()=>{const f=n(se(o));if(f&&f.tabs?.length)try{b.value=!0,await s.hydrate(f)}finally{b.value=!1}else try{b.value=!0;const A=e.fallbackRoute??s.options.defaultRoute;await s.reset(A)}finally{b.value=!1}const T=s.snapshot();T.tabs.length?W(o,a(T),e):X(o,e)}),t.watch(()=>({tabs:s.tabs.map(f=>({to:f.to,title:f.title,tips:f.tips,icon:f.icon,tabClass:f.tabClass,closable:f.closable})),active:s.activeId.value}),()=>{if(b.value)return;const f=s.snapshot();f.tabs.length?W(o,a(f),e):X(o,e)},{deep:!0})};c?p(c):t.onMounted(()=>{const s=M({optional:!0});s&&p(s)})}const ue=t.defineComponent({name:"RouterTab",components:{RouterView:Z.RouterView},props:{tabs:{type:Array,default:()=>[]},keepAlive:{type:Boolean,default:!0},maxAlive:{type:Number,default:0},keepLastTab:{type:Boolean,default:!0},append:{type:String,default:"last"},defaultPage:{type:[String,Object],default:"/"},tabTransition:{type:[String,Object],default:"router-tab-zoom"},pageTransition:{type:[String,Object],default:()=>({name:"router-tab-swap",mode:"out-in"})},contextmenu:{type:[Boolean,Array],default:!0},cookieKey:{type:String,default:null},persistence:{type:Object,default:null}},setup(e){const o=t.getCurrentInstance();if(!o)throw new Error("[RouterTab] component must be used within a Vue application context.");const a=o.appContext.app.config.globalProperties.$router;if(!a)throw new Error("[RouterTab] Vue Router is required. Make sure to call app.use(router) before RouterTab.");const n=ie(a,{initialTabs:e.tabs,keepAlive:e.keepAlive,maxAlive:e.maxAlive,keepLastTab:e.keepLastTab,appendPosition:e.append,defaultRoute:e.defaultPage});t.provide(_,n),o.appContext.config.globalProperties.$tabs=n;const c=t.computed(()=>!!o?.slots?.default);if(e.cookieKey||e.persistence){const i={...e.persistence??{}};e.cookieKey&&(i.cookieKey=e.cookieKey),L(i)}const b=t.computed(()=>Y(e.tabTransition)),p=t.computed(()=>Y(e.pageTransition)),s=t.reactive({visible:!1,target:null,position:{x:0,y:0}}),f=["refresh","refreshAll","close","closeLefts","closeRights","closeOthers"];function T(i){return n.tabs.findIndex(d=>d.id===i)}function A(i){const d=T(i.id);return d>0?n.tabs.slice(0,d):[]}function E(i){const d=T(i.id);return d>-1?n.tabs.slice(d+1):[]}function S(i){return n.tabs.filter(d=>d.id!==i.id)}async function P(i,d){const h=i.filter(k=>k.closable!==!1);if(h.length){for(const k of h)n.activeId.value===k.id?await n.closeTab(k.id,{redirect:d.to,force:!0}):await n.removeTab(k.id,{force:!0});n.activeId.value!==d.id&&await n.openTab(d.to,!0,!1)}}const V={refresh:{label:"Refresh",handler:async({target:i})=>{await n.refreshTab(i.id,!0)}},refreshAll:{label:"Refresh All",handler:async()=>{await n.refreshAll(!0)}},close:{label:"Close",handler:async({target:i})=>{await n.closeTab(i.id)},enable:({target:i})=>x(i)},closeLefts:{label:"Close to the Left",handler:async({target:i})=>{await P(A(i),i)},enable:({target:i})=>A(i).some(d=>d.closable!==!1)},closeRights:{label:"Close to the Right",handler:async({target:i})=>{await P(E(i),i)},enable:({target:i})=>E(i).some(d=>d.closable!==!1)},closeOthers:{label:"Close Others",handler:async({target:i})=>{await P(S(i),i)},enable:({target:i})=>S(i).some(d=>d.closable!==!1)}};function g(){s.visible=!1,s.target=null}function D(i,d){e.contextmenu&&(s.visible=!0,s.target=i,s.position.x=d.clientX,s.position.y=d.clientY,document.addEventListener("click",g,{once:!0}))}function O(i,d){const h=typeof i=="string"?{id:i}:i,k=V[h.id],Ae=h.label??k?.label??String(h.id),q=h.visible??k?.visible??!0;if(!(typeof q=="function"?q(d):q!==!1))return null;const G=h.enable??k?.enable??!0,_e=typeof G=="function"?G(d):G!==!1,Q=h.handler??k?.handler;if(!Q)return null;const Pe=async()=>{await Promise.resolve(Q(d))};return{id:String(h.id),label:Ae,disabled:!_e,action:Pe}}const v=t.computed(()=>{if(!s.visible||!s.target||e.contextmenu===!1)return[];const i=Array.isArray(e.contextmenu)?e.contextmenu:f,d={target:s.target,controller:n};return i.map(h=>O(h,d)).filter(h=>!!h)});async function U(i){i.disabled||(g(),await i.action())}function F(i){return typeof i.title=="string"?i.title:Array.isArray(i.title)&&i.title.length?String(i.title[0]):i.fullPath}function x(i){return!(i.closable===!1||n.options.keepLastTab&&n.tabs.length<=1)}async function l(i){await n.closeTab(i.id)}function r(i){n.activeId.value!==i.id&&n.openTab(i.to,!1)}function u(i){return["router-tab__item",{"is-active":n.activeId.value===i.id,"is-closable":x(i)},i.tabClass]}function m(i){return n.refreshingKey.value===n.getRouteKey(i)}t.onMounted(()=>{document.addEventListener("keydown",g)}),t.onBeforeUnmount(()=>{document.removeEventListener("keydown",g),o.appContext.config.globalProperties.$tabs=null}),t.watch(()=>e.keepAlive,i=>{n.options.keepAlive=i}),t.watch(()=>n.activeId.value,()=>g()),t.watch(()=>e.contextmenu,i=>{i||g()}),t.watch(()=>v.value.length,i=>{s.visible&&i===0&&g()});const C=n.includeKeys;return{controller:n,tabs:n.tabs,includeKeys:C,tabTransitionProps:b,pageTransitionProps:p,buildTabClass:u,activate:r,close:l,context:s,menuItems:v,handleMenuAction:U,showContextMenu:D,hideContextMenu:g,tabTitle:F,isClosable:x,isRefreshing:m,hasCustomSlot:c}}}),fe=(e,o)=>{const a=e.__vccOpts||e;for(const[n,c]of o)a[n]=c;return a},de={class:"router-tab"},be={class:"router-tab__header"},pe={class:"router-tab__slot-start"},me={class:"router-tab__scroll"},he=["onClick","onAuxclick","onContextmenu"],ye=["title"],ge=["onClick"],ke={class:"router-tab__slot-end"},Te={class:"router-tab__container"},Ce=["aria-disabled","onClick"];function we(e,o,a,n,c,b){const p=t.resolveComponent("RouterView");return t.openBlock(),t.createElementBlock("div",de,[t.createElementVNode("header",be,[t.createElementVNode("div",pe,[t.renderSlot(e.$slots,"start")]),t.createElementVNode("div",me,[t.createVNode(t.TransitionGroup,t.mergeProps({tag:"ul",class:"router-tab__nav"},e.tabTransitionProps),{default:t.withCtx(()=>[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(e.tabs,s=>(t.openBlock(),t.createElementBlock("li",{key:s.id,class:t.normalizeClass(e.buildTabClass(s)),onClick:f=>e.activate(s),onAuxclick:t.withModifiers(f=>e.close(s),["middle","prevent"]),onContextmenu:t.withModifiers(f=>e.showContextMenu(s,f),["prevent"])},[t.createElementVNode("span",{class:"router-tab__item-title",title:e.tabTitle(s)},[s.icon?(t.openBlock(),t.createElementBlock("i",{key:0,class:t.normalizeClass(["router-tab__item-icon",s.icon])},null,2)):t.createCommentVNode("",!0),t.createTextVNode(" "+t.toDisplayString(e.tabTitle(s)),1)],8,ye),e.isClosable(s)?(t.openBlock(),t.createElementBlock("a",{key:0,class:"router-tab__item-close",type:"button",onClick:t.withModifiers(f=>e.close(s),["stop"])},null,8,ge)):t.createCommentVNode("",!0)],42,he))),128))]),_:1},16)]),t.createElementVNode("div",ke,[t.renderSlot(e.$slots,"end")])]),t.createElementVNode("div",Te,[t.createVNode(p,null,{default:t.withCtx(s=>[e.hasCustomSlot?t.renderSlot(e.$slots,"default",t.normalizeProps(t.mergeProps({key:0},{...s,controller:e.controller}))):(t.openBlock(),t.createElementBlock(t.Fragment,{key:1},[t.createVNode(t.Transition,t.mergeProps(e.pageTransitionProps,{appear:""}),{default:t.withCtx(()=>[e.controller.options.keepAlive?(t.openBlock(),t.createBlock(t.KeepAlive,{key:0,include:e.includeKeys,max:e.controller.options.maxAlive||void 0},[e.isRefreshing(s.route)?t.createCommentVNode("",!0):(t.openBlock(),t.createBlock(t.resolveDynamicComponent(s.Component),{key:e.controller.getRouteKey(s.route),class:"router-tab-page"}))],1032,["include","max"])):t.createCommentVNode("",!0)]),_:2},1040),t.createVNode(t.Transition,t.mergeProps(e.pageTransitionProps,{appear:""}),{default:t.withCtx(()=>[!e.controller.options.keepAlive||e.isRefreshing(s.route)?(t.openBlock(),t.createBlock(t.resolveDynamicComponent(s.Component),{key:e.controller.getRouteKey(s.route)+(e.isRefreshing(s.route)?"-refresh":""),class:"router-tab-page"})):t.createCommentVNode("",!0)]),_:2},1040)],64))]),_:3})]),e.context.visible&&e.context.target?(t.openBlock(),t.createElementBlock("div",{key:0,class:"router-tab__contextmenu",style:t.normalizeStyle({left:e.context.position.x+"px",top:e.context.position.y+"px"})},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(e.menuItems,s=>(t.openBlock(),t.createElementBlock("a",{key:s.id,class:"router-tab__contextmenu-item","aria-disabled":s.disabled,onClick:t.withModifiers(f=>e.handleMenuAction(s),["prevent"])},t.toDisplayString(s.label),9,Ce))),128))],4)):t.createCommentVNode("",!0)])}const j=fe(ue,[["render",we]]),Re={class:"router-tabs","aria-hidden":"true"},$=t.defineComponent({name:"RouterTabs",__name:"RouterTabs",props:{cookieKey:{},expiresInDays:{},path:{},domain:{},secure:{type:Boolean},sameSite:{},serialize:{type:Function},deserialize:{type:Function},fallbackRoute:{}},setup(e){return L(e),(a,n)=>(t.openBlock(),t.createElementBlock("span",Re))}}),z={install(e){if(z._installed)return;z._installed=!0;const o=j.name||"RouterTab",a=$.name||"RouterTabs";e.component(o,j),e.component(a,$),a!=="router-tabs"&&e.component("router-tabs",$),Object.defineProperty(e.config.globalProperties,"$tabs",{configurable:!0,enumerable:!1,get(){return e._context.provides[_]},set(n){n&&e.provide(_,n)}})}};y.RouterTab=j,y.RouterTabs=$,y.default=z,y.routerTabsKey=_,y.useRouterTabs=M,y.useRouterTabsPersistence=L,Object.defineProperties(y,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
|
1
|
+
(function(y,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue"),require("vue-router")):typeof define=="function"&&define.amd?define(["exports","vue","vue-router"],t):(y=typeof globalThis<"u"?globalThis:y||self,t(y["vue3-router-tab"]={},y.Vue,y.VueRouter))})(this,(function(y,t,ee){"use strict";function te(e={}){return{initialTabs:e.initialTabs??[],keepAlive:e.keepAlive??!0,maxAlive:e.maxAlive??0,keepLastTab:e.keepLastTab??!0,appendPosition:e.appendPosition??"last",defaultRoute:e.defaultRoute??"/"}}function w(e,i){const a=e.resolve(i);if(!a||!a.matched.length)throw new Error(`[RouterTabs] Unable to resolve route: ${String(i)}`);return a}const ne={path:e=>e.path,fullpath:e=>e.fullPath,fullname:e=>e.fullPath,full:e=>e.fullPath,name:e=>e.name?String(e.name):e.fullPath};function R(e){const i=e.meta?.key;if(typeof i=="function"){const a=i(e);if(typeof a=="string"&&a.length)return a}else if(typeof i=="string"&&i.length){const a=ne[i.toLowerCase()];return a?a(e):i}return e.fullPath}function I(e,i){const a=e.meta?.keepAlive;return typeof a=="boolean"?a:i}function N(e,i){const a=e.meta?.reuse;return typeof a=="boolean"?a:i}function H(e){const i=e.meta??{},a={};return"title"in i&&(a.title=i.title),"tips"in i&&(a.tips=i.tips),"icon"in i&&(a.icon=i.icon),"closable"in i&&(a.closable=i.closable),"tabClass"in i&&(a.tabClass=i.tabClass),"target"in i&&(a.target=i.target),"href"in i&&(a.href=i.href),a}function B(e,i,a){const n=H(e);return{id:R(e),to:e.fullPath,fullPath:e.fullPath,matched:e,alive:I(e,a),reusable:N(e,!1),closable:n.closable??!0,...n,...i}}function M(e,i,a,n){if(!e.find(b=>b.id===i.id)){if(a==="next"&&n){const b=e.findIndex(p=>p.id===n);if(b>-1){e.splice(b+1,0,i);return}}e.push(i)}}function Y(e,i,a){if(!i||i<=0)return;const n=e.filter(c=>c.alive);for(;n.length>i;){const c=n.shift();if(!c||c.id===a)continue;const b=e.findIndex(p=>p.id===c.id);b>-1&&(e[b].alive=!1)}}function oe(e){return{to:e.to,title:e.title,tips:e.tips,icon:e.icon,tabClass:e.tabClass,closable:e.closable}}function ie(e){const i={};return"title"in e&&(i.title=e.title),"tips"in e&&(i.tips=e.tips),"icon"in e&&(i.icon=e.icon),"tabClass"in e&&(i.tabClass=e.tabClass),"closable"in e&&(i.closable=e.closable),i}function ae(e,i={}){const a=te(i),n=t.reactive([]),c=t.ref(null),b=t.shallowRef(),p=t.ref(null),s=t.computed(()=>n.filter(l=>l.alive).map(l=>l.id));let f=!1;function T(l){const r=typeof l.matched=="object"?l:w(e,l);return{key:R(r),fullPath:r.fullPath,alive:I(r,a.keepAlive),reusable:N(r,!1),matched:r}}function A(l){const r=R(l);let u=n.find(m=>m.id===r);return u?(u.fullPath=l.fullPath,u.to=l.fullPath,u.matched=l,u.alive=I(l,a.keepAlive),u.reusable=N(l,u.reusable),Object.assign(u,H(l)),u):(u=B(l,{},a.keepAlive),M(n,u,a.appendPosition,c.value),Y(n,a.maxAlive,c.value),u)}async function K(l,r=!1,u=!0){const m=w(e,l),C=R(m),o=c.value===C;u==="sameTab"&&(u=o),u&&await k(C,!0),await e[r?"replace":"push"](m),o&&await P()}function S(l){const r=n.findIndex(m=>m.id===l),u=n[r]||n[r-1]||n[0];return u?u.to:a.defaultRoute}async function v(l=c.value,r={}){if(l){if(!r.force&&a.keepLastTab&&n.length===1)throw new Error("[RouterTabs] Unable to close the final tab when keepLastTab is true.");if(await V(l,{force:r.force}),r.redirect!==null)if(c.value===l){const u=r.redirect??S(l);u&&await e.replace(u)}else r.redirect&&await e.replace(r.redirect)}}async function V(l,r={}){const u=n.findIndex(m=>m.id===l);u!==-1&&(n.splice(u,1),p.value===l&&(p.value=null),c.value===l&&(c.value=null,b.value=void 0))}async function k(l=c.value??void 0,r=!1){l&&(p.value=l,await t.nextTick(),r||await t.nextTick(),p.value=null)}async function O(l=!1){for(const r of n)await k(r.id,l)}async function U(l=a.defaultRoute){n.splice(0,n.length),c.value=null,b.value=void 0;for(const r of a.initialTabs){const u=w(e,r.to),m=B(u,r,a.keepAlive);n.push(m)}await e.replace(l)}async function P(){const l=c.value;l&&await k(l,!0)}function F(l){return typeof l.matched=="object"?R(l):R(w(e,l))}function q(){const l=n.find(r=>r.id===c.value);return{tabs:n.map(oe),active:l?l.to:null}}async function x(l){f=!0,n.splice(0,n.length),c.value=null,b.value=void 0;const r=l?.tabs??[];for(const m of r)try{const C=w(e,m.to),o=ie(m),d=B(C,o,a.keepAlive);M(n,d,"last",null)}catch{}f=!1;const u=l?.active??r[r.length-1]?.to??a.defaultRoute;if(u)try{await e.replace(u)}catch{}}return t.watch(()=>e.currentRoute.value,l=>{if(f)return;const r=A(l);c.value=r.id,b.value=r,Y(n,a.maxAlive,c.value)},{immediate:!0}),a.initialTabs.length&&a.initialTabs.forEach(l=>{const r=w(e,l.to),u=B(r,l,a.keepAlive);M(n,u,"last",null)}),{options:a,tabs:n,activeId:c,current:b,includeKeys:s,refreshingKey:p,openTab:K,closeTab:v,removeTab:V,refreshTab:k,refreshAll:O,reset:U,reload:P,getRouteKey:F,matchRoute:T,snapshot:q,hydrate:x}}function W(e){return e?typeof e=="string"?{name:e}:e:{}}const _=Symbol("RouterTabsContext"),$="router-tabs:snapshot";function L(e={}){const{optional:i=!1}=e,a=t.inject(_,null);if(a)return a;const n=t.inject("$tabs",null);if(n)return n;const b=t.getCurrentInstance()?.appContext.config.globalProperties.$tabs;if(b)return b;if(!i)throw new Error("[RouterTabs] useRouterTabs must be used within <router-tab>.");return null}const le=864e5;function se(e){if(typeof document>"u")return null;const i=`${encodeURIComponent(e)}=`,a=document.cookie?document.cookie.split("; "):[];for(const n of a)if(n.startsWith(i))return decodeURIComponent(n.slice(i.length));return null}function X(e,i,a){if(typeof document>"u")return;const{expiresInDays:n=7,path:c="/",domain:b,secure:p,sameSite:s="lax"}=a,f=[`${encodeURIComponent(e)}=${encodeURIComponent(i)}`];if(n!==1/0){const T=new Date(Date.now()+n*le).toUTCString();f.push(`Expires=${T}`)}c&&f.push(`Path=${c}`),b&&f.push(`Domain=${b}`),p&&f.push("Secure"),s&&f.push(`SameSite=${s.charAt(0).toUpperCase()}${s.slice(1)}`),document.cookie=f.join("; ")}function Q(e,i){if(typeof document>"u")return;const{path:a="/",domain:n}=i,c=[`${encodeURIComponent(e)}=`];c.push("Expires=Thu, 01 Jan 1970 00:00:01 GMT"),a&&c.push(`Path=${a}`),n&&c.push(`Domain=${n}`),document.cookie=c.join("; ")}const re=e=>JSON.stringify(e??null),ce=e=>{if(!e)return null;try{return JSON.parse(e)}catch{return null}};function j(e={}){const{cookieKey:i=$,serialize:a=re,deserialize:n=ce}=e,c=L({optional:!0}),b=t.ref(!0),p=s=>{t.onMounted(async()=>{const f=n(se(i));if(f&&f.tabs?.length)try{b.value=!0,await s.hydrate(f)}finally{b.value=!1}else try{b.value=!0;const A=e.fallbackRoute??s.options.defaultRoute;await s.reset(A)}finally{b.value=!1}const T=s.snapshot();T.tabs.length?X(i,a(T),e):Q(i,e),b.value=!1}),t.watch(()=>({tabs:s.tabs.map(f=>({to:f.to,title:f.title,tips:f.tips,icon:f.icon,tabClass:f.tabClass,closable:f.closable})),active:s.activeId.value}),()=>{if(b.value)return;const f=s.snapshot();f.tabs.length?X(i,a(f),e):Q(i,e)},{deep:!0})};c?p(c):t.onMounted(()=>{const s=L({optional:!0});s&&p(s)})}const ue=t.defineComponent({name:"RouterTab",components:{RouterView:ee.RouterView},props:{tabs:{type:Array,default:()=>[]},keepAlive:{type:Boolean,default:!0},maxAlive:{type:Number,default:0},keepLastTab:{type:Boolean,default:!0},append:{type:String,default:"last"},defaultPage:{type:[String,Object],default:"/"},tabTransition:{type:[String,Object],default:"router-tab-zoom"},pageTransition:{type:[String,Object],default:()=>({name:"router-tab-swap",mode:"out-in"})},contextmenu:{type:[Boolean,Array],default:!0},cookieKey:{type:String,default:$},persistence:{type:Object,default:null}},setup(e){const i=t.getCurrentInstance();if(!i)throw new Error("[RouterTab] component must be used within a Vue application context.");const a=i.appContext.app.config.globalProperties.$router;if(!a)throw new Error("[RouterTab] Vue Router is required. Make sure to call app.use(router) before RouterTab.");const n=ae(a,{initialTabs:e.tabs,keepAlive:e.keepAlive,maxAlive:e.maxAlive,keepLastTab:e.keepLastTab,appendPosition:e.append,defaultRoute:e.defaultPage});t.provide(_,n),i.appContext.config.globalProperties.$tabs=n;const c=t.computed(()=>!!i?.slots?.default);if(e.cookieKey!==null||e.persistence){const o={...e.persistence??{}};e.cookieKey!==null?o.cookieKey=e.cookieKey||$:o.cookieKey||(o.cookieKey=$),j(o)}const b=t.computed(()=>W(e.tabTransition)),p=t.computed(()=>W(e.pageTransition)),s=t.reactive({visible:!1,target:null,position:{x:0,y:0}}),f=["refresh","refreshAll","close","closeLefts","closeRights","closeOthers"];function T(o){return n.tabs.findIndex(d=>d.id===o)}function A(o){const d=T(o.id);return d>0?n.tabs.slice(0,d):[]}function K(o){const d=T(o.id);return d>-1?n.tabs.slice(d+1):[]}function S(o){return n.tabs.filter(d=>d.id!==o.id)}async function v(o,d){const h=o.filter(g=>g.closable!==!1);if(h.length){for(const g of h)n.activeId.value===g.id?await n.closeTab(g.id,{redirect:d.to,force:!0}):await n.removeTab(g.id,{force:!0});n.activeId.value!==d.id&&await n.openTab(d.to,!0,!1)}}const V={refresh:{label:"Refresh",handler:async({target:o})=>{await n.refreshTab(o.id,!0)}},refreshAll:{label:"Refresh All",handler:async()=>{await n.refreshAll(!0)}},close:{label:"Close",handler:async({target:o})=>{await n.closeTab(o.id)},enable:({target:o})=>x(o)},closeLefts:{label:"Close to the Left",handler:async({target:o})=>{await v(A(o),o)},enable:({target:o})=>A(o).some(d=>d.closable!==!1)},closeRights:{label:"Close to the Right",handler:async({target:o})=>{await v(K(o),o)},enable:({target:o})=>K(o).some(d=>d.closable!==!1)},closeOthers:{label:"Close Others",handler:async({target:o})=>{await v(S(o),o)},enable:({target:o})=>S(o).some(d=>d.closable!==!1)}};function k(){s.visible=!1,s.target=null}function O(o,d){e.contextmenu&&(s.visible=!0,s.target=o,s.position.x=d.clientX,s.position.y=d.clientY,document.addEventListener("click",k,{once:!0}))}function U(o,d){const h=typeof o=="string"?{id:o}:o,g=V[h.id],Ae=h.label??g?.label??String(h.id),G=h.visible??g?.visible??!0;if(!(typeof G=="function"?G(d):G!==!1))return null;const J=h.enable??g?.enable??!0,_e=typeof J=="function"?J(d):J!==!1,Z=h.handler??g?.handler;if(!Z)return null;const ve=async()=>{await Promise.resolve(Z(d))};return{id:String(h.id),label:Ae,disabled:!_e,action:ve}}const P=t.computed(()=>{if(!s.visible||!s.target||e.contextmenu===!1)return[];const o=Array.isArray(e.contextmenu)?e.contextmenu:f,d={target:s.target,controller:n};return o.map(h=>U(h,d)).filter(h=>!!h)});async function F(o){o.disabled||(k(),await o.action())}function q(o){return typeof o.title=="string"?o.title:Array.isArray(o.title)&&o.title.length?String(o.title[0]):o.fullPath}function x(o){return!(o.closable===!1||n.options.keepLastTab&&n.tabs.length<=1)}async function l(o){await n.closeTab(o.id)}function r(o){n.activeId.value!==o.id&&n.openTab(o.to,!1)}function u(o){return["router-tab__item",{"is-active":n.activeId.value===o.id,"is-closable":x(o)},o.tabClass]}function m(o){return n.refreshingKey.value===n.getRouteKey(o)}t.onMounted(()=>{document.addEventListener("keydown",k)}),t.onBeforeUnmount(()=>{document.removeEventListener("keydown",k),i.appContext.config.globalProperties.$tabs=null}),t.watch(()=>e.keepAlive,o=>{n.options.keepAlive=o}),t.watch(()=>n.activeId.value,()=>k()),t.watch(()=>e.contextmenu,o=>{o||k()}),t.watch(()=>P.value.length,o=>{s.visible&&o===0&&k()});const C=n.includeKeys;return{controller:n,tabs:n.tabs,includeKeys:C,tabTransitionProps:b,pageTransitionProps:p,buildTabClass:u,activate:r,close:l,context:s,menuItems:P,handleMenuAction:F,showContextMenu:O,hideContextMenu:k,tabTitle:q,isClosable:x,isRefreshing:m,hasCustomSlot:c}}}),fe=(e,i)=>{const a=e.__vccOpts||e;for(const[n,c]of i)a[n]=c;return a},de={class:"router-tab"},be={class:"router-tab__header"},pe={class:"router-tab__slot-start"},me={class:"router-tab__scroll"},he=["onClick","onAuxclick","onContextmenu"],ye=["title"],ke=["onClick"],ge={class:"router-tab__slot-end"},Te={class:"router-tab__container"},Ce=["aria-disabled","onClick"];function we(e,i,a,n,c,b){const p=t.resolveComponent("RouterView");return t.openBlock(),t.createElementBlock("div",de,[t.createElementVNode("header",be,[t.createElementVNode("div",pe,[t.renderSlot(e.$slots,"start")]),t.createElementVNode("div",me,[t.createVNode(t.TransitionGroup,t.mergeProps({tag:"ul",class:"router-tab__nav"},e.tabTransitionProps),{default:t.withCtx(()=>[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(e.tabs,s=>(t.openBlock(),t.createElementBlock("li",{key:s.id,class:t.normalizeClass(e.buildTabClass(s)),onClick:f=>e.activate(s),onAuxclick:t.withModifiers(f=>e.close(s),["middle","prevent"]),onContextmenu:t.withModifiers(f=>e.showContextMenu(s,f),["prevent"])},[t.createElementVNode("span",{class:"router-tab__item-title",title:e.tabTitle(s)},[s.icon?(t.openBlock(),t.createElementBlock("i",{key:0,class:t.normalizeClass(["router-tab__item-icon",s.icon])},null,2)):t.createCommentVNode("",!0),t.createTextVNode(" "+t.toDisplayString(e.tabTitle(s)),1)],8,ye),e.isClosable(s)?(t.openBlock(),t.createElementBlock("a",{key:0,class:"router-tab__item-close",type:"button",onClick:t.withModifiers(f=>e.close(s),["stop"])},null,8,ke)):t.createCommentVNode("",!0)],42,he))),128))]),_:1},16)]),t.createElementVNode("div",ge,[t.renderSlot(e.$slots,"end")])]),t.createElementVNode("div",Te,[t.createVNode(p,null,{default:t.withCtx(s=>[e.hasCustomSlot?t.renderSlot(e.$slots,"default",t.normalizeProps(t.mergeProps({key:0},{...s,controller:e.controller}))):(t.openBlock(),t.createElementBlock(t.Fragment,{key:1},[t.createVNode(t.Transition,t.mergeProps(e.pageTransitionProps,{appear:""}),{default:t.withCtx(()=>[e.controller.options.keepAlive?(t.openBlock(),t.createBlock(t.KeepAlive,{key:0,include:e.includeKeys,max:e.controller.options.maxAlive||void 0},[e.isRefreshing(s.route)?t.createCommentVNode("",!0):(t.openBlock(),t.createBlock(t.resolveDynamicComponent(s.Component),{key:e.controller.getRouteKey(s.route),class:"router-tab-page"}))],1032,["include","max"])):t.createCommentVNode("",!0)]),_:2},1040),t.createVNode(t.Transition,t.mergeProps(e.pageTransitionProps,{appear:""}),{default:t.withCtx(()=>[!e.controller.options.keepAlive||e.isRefreshing(s.route)?(t.openBlock(),t.createBlock(t.resolveDynamicComponent(s.Component),{key:e.controller.getRouteKey(s.route)+(e.isRefreshing(s.route)?"-refresh":""),class:"router-tab-page"})):t.createCommentVNode("",!0)]),_:2},1040)],64))]),_:3})]),e.context.visible&&e.context.target?(t.openBlock(),t.createElementBlock("div",{key:0,class:"router-tab__contextmenu",style:t.normalizeStyle({left:e.context.position.x+"px",top:e.context.position.y+"px"})},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(e.menuItems,s=>(t.openBlock(),t.createElementBlock("a",{key:s.id,class:"router-tab__contextmenu-item","aria-disabled":s.disabled,onClick:t.withModifiers(f=>e.handleMenuAction(s),["prevent"])},t.toDisplayString(s.label),9,Ce))),128))],4)):t.createCommentVNode("",!0)])}const z=fe(ue,[["render",we]]),Re={class:"router-tabs","aria-hidden":"true"},E=t.defineComponent({name:"RouterTabs",__name:"RouterTabs",props:{cookieKey:{},expiresInDays:{},path:{},domain:{},secure:{type:Boolean},sameSite:{},serialize:{type:Function},deserialize:{type:Function},fallbackRoute:{}},setup(e){return j(e),(a,n)=>(t.openBlock(),t.createElementBlock("span",Re))}}),D={install(e){if(D._installed)return;D._installed=!0;const i=z.name||"RouterTab",a=E.name||"RouterTabs";e.component(i,z),e.component(a,E),a!=="router-tabs"&&e.component("router-tabs",E),Object.defineProperty(e.config.globalProperties,"$tabs",{configurable:!0,enumerable:!1,get(){return e._context.provides[_]},set(n){n&&e.provide(_,n)}})}};y.RouterTab=z,y.RouterTabs=E,y.default=D,y.routerTabsKey=_,y.useRouterTabs=L,y.useRouterTabsPersistence=j,Object.defineProperties(y,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { App, Plugin, DefineComponent, PropType } from 'vue'
|
|
2
|
+
import type { RouteLocationRaw } from 'vue-router'
|
|
3
|
+
import type {
|
|
4
|
+
TabRecord,
|
|
5
|
+
TabInput,
|
|
6
|
+
RouterTabsOptions,
|
|
7
|
+
CloseTabOptions,
|
|
8
|
+
RouterTabsContext,
|
|
9
|
+
RouterTabsMenuConfig,
|
|
10
|
+
RouterTabsMenuItem,
|
|
11
|
+
RouterTabsMenuPreset,
|
|
12
|
+
RouterTabsSnapshot,
|
|
13
|
+
RouterTabsSnapshotTab,
|
|
14
|
+
RouterTabsPersistenceOptions
|
|
15
|
+
} from './lib/core/types'
|
|
16
|
+
|
|
17
|
+
export type {
|
|
18
|
+
TabRecord,
|
|
19
|
+
TabInput,
|
|
20
|
+
RouterTabsOptions,
|
|
21
|
+
CloseTabOptions,
|
|
22
|
+
RouterTabsContext,
|
|
23
|
+
RouterTabsMenuConfig,
|
|
24
|
+
RouterTabsMenuItem,
|
|
25
|
+
RouterTabsMenuPreset,
|
|
26
|
+
RouterTabsSnapshot,
|
|
27
|
+
RouterTabsSnapshotTab,
|
|
28
|
+
RouterTabsPersistenceOptions
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export declare const routerTabsKey: import('vue').InjectionKey<RouterTabsContext>
|
|
32
|
+
|
|
33
|
+
export declare function useRouterTabs(options?: { optional?: boolean }): RouterTabsContext | null
|
|
34
|
+
|
|
35
|
+
export declare function useRouterTabsPersistence(options?: RouterTabsPersistenceOptions): void
|
|
36
|
+
|
|
37
|
+
export declare const RouterTabs: DefineComponent<RouterTabsPersistenceOptions, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, Readonly<RouterTabsPersistenceOptions>, {}>
|
|
38
|
+
|
|
39
|
+
export declare const RouterTab: DefineComponent<{
|
|
40
|
+
tabs: {
|
|
41
|
+
type: PropType<TabInput[]>
|
|
42
|
+
default: () => TabInput[]
|
|
43
|
+
}
|
|
44
|
+
keepAlive: BooleanConstructor
|
|
45
|
+
maxAlive: NumberConstructor
|
|
46
|
+
keepLastTab: BooleanConstructor
|
|
47
|
+
append: PropType<'last' | 'next'>
|
|
48
|
+
defaultPage: PropType<RouteLocationRaw>
|
|
49
|
+
tabTransition: PropType<import('./lib/core/types').TransitionLike>
|
|
50
|
+
pageTransition: PropType<import('./lib/core/types').TransitionLike>
|
|
51
|
+
contextmenu: PropType<boolean | RouterTabsMenuConfig[]>
|
|
52
|
+
cookieKey: StringConstructor
|
|
53
|
+
persistence: PropType<RouterTabsPersistenceOptions | null>
|
|
54
|
+
}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, Record<string, any>, string, import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, Readonly<{
|
|
55
|
+
tabs?: TabInput[] | undefined
|
|
56
|
+
keepAlive?: boolean | undefined
|
|
57
|
+
maxAlive?: number | undefined
|
|
58
|
+
keepLastTab?: boolean | undefined
|
|
59
|
+
append?: 'last' | 'next' | undefined
|
|
60
|
+
defaultPage?: RouteLocationRaw | undefined
|
|
61
|
+
tabTransition?: import('./lib/core/types').TransitionLike | undefined
|
|
62
|
+
pageTransition?: import('./lib/core/types').TransitionLike | undefined
|
|
63
|
+
contextmenu?: boolean | RouterTabsMenuConfig[] | undefined
|
|
64
|
+
cookieKey?: string | undefined
|
|
65
|
+
persistence?: RouterTabsPersistenceOptions | null | undefined
|
|
66
|
+
}> & {
|
|
67
|
+
tabs?: TabInput[] | undefined
|
|
68
|
+
keepAlive?: boolean | undefined
|
|
69
|
+
maxAlive?: number | undefined
|
|
70
|
+
keepLastTab?: boolean | undefined
|
|
71
|
+
append?: 'last' | 'next' | undefined
|
|
72
|
+
defaultPage?: RouteLocationRaw | undefined
|
|
73
|
+
tabTransition?: import('./lib/core/types').TransitionLike | undefined
|
|
74
|
+
pageTransition?: import('./lib/core/types').TransitionLike | undefined
|
|
75
|
+
contextmenu?: boolean | RouterTabsMenuConfig[] | undefined
|
|
76
|
+
cookieKey?: string | undefined
|
|
77
|
+
persistence?: RouterTabsPersistenceOptions | null | undefined
|
|
78
|
+
}, {
|
|
79
|
+
tabs: TabInput[]
|
|
80
|
+
keepAlive: boolean
|
|
81
|
+
maxAlive: number
|
|
82
|
+
keepLastTab: boolean
|
|
83
|
+
append: 'last' | 'next'
|
|
84
|
+
defaultPage: RouteLocationRaw
|
|
85
|
+
tabTransition: import('./lib/core/types').TransitionLike
|
|
86
|
+
pageTransition: import('./lib/core/types').TransitionLike
|
|
87
|
+
contextmenu: boolean | RouterTabsMenuConfig[]
|
|
88
|
+
cookieKey: string
|
|
89
|
+
persistence: RouterTabsPersistenceOptions | null
|
|
90
|
+
}>
|
|
91
|
+
|
|
92
|
+
export interface RouterTabPlugin extends Plugin {}
|
|
93
|
+
|
|
94
|
+
declare const plugin: RouterTabPlugin
|
|
95
|
+
|
|
96
|
+
export default plugin
|
|
@@ -121,7 +121,7 @@ import type {
|
|
|
121
121
|
TransitionLike
|
|
122
122
|
} from '../core/types'
|
|
123
123
|
import { getTransOpt } from '../util/index'
|
|
124
|
-
import { routerTabsKey } from '../constants'
|
|
124
|
+
import { routerTabsKey, routerTabsCookie } from '../constants'
|
|
125
125
|
import { useRouterTabsPersistence } from '../persistence'
|
|
126
126
|
|
|
127
127
|
|
|
@@ -174,7 +174,7 @@ export default defineComponent({
|
|
|
174
174
|
},
|
|
175
175
|
cookieKey: {
|
|
176
176
|
type: String,
|
|
177
|
-
default:
|
|
177
|
+
default: routerTabsCookie
|
|
178
178
|
},
|
|
179
179
|
persistence: {
|
|
180
180
|
type: Object as PropType<RouterTabsPersistenceOptions | null>,
|
|
@@ -206,11 +206,15 @@ export default defineComponent({
|
|
|
206
206
|
|
|
207
207
|
const hasCustomSlot = computed(() => Boolean(instance?.slots?.default))
|
|
208
208
|
|
|
209
|
-
if (props.cookieKey || props.persistence) {
|
|
209
|
+
if (props.cookieKey !== null || props.persistence) {
|
|
210
210
|
const options: RouterTabsPersistenceOptions = {
|
|
211
211
|
...(props.persistence ?? {})
|
|
212
212
|
}
|
|
213
|
-
if (props.cookieKey
|
|
213
|
+
if (props.cookieKey !== null) {
|
|
214
|
+
options.cookieKey = props.cookieKey || routerTabsCookie
|
|
215
|
+
} else if (!options.cookieKey) {
|
|
216
|
+
options.cookieKey = routerTabsCookie
|
|
217
|
+
}
|
|
214
218
|
useRouterTabsPersistence(options)
|
|
215
219
|
}
|
|
216
220
|
|
package/lib/persistence.ts
CHANGED
|
@@ -98,7 +98,7 @@ export function useRouterTabsPersistence(options: RouterTabsPersistenceOptions =
|
|
|
98
98
|
} = options
|
|
99
99
|
|
|
100
100
|
const controller = useRouterTabs({ optional: true })
|
|
101
|
-
const hydrating = ref(
|
|
101
|
+
const hydrating = ref(true)
|
|
102
102
|
|
|
103
103
|
const setup = (ctrl: NonNullable<typeof controller>) => {
|
|
104
104
|
onMounted(async () => {
|
|
@@ -127,6 +127,8 @@ export function useRouterTabsPersistence(options: RouterTabsPersistenceOptions =
|
|
|
127
127
|
} else {
|
|
128
128
|
writeCookie(cookieKey, serialize(snapshot), options)
|
|
129
129
|
}
|
|
130
|
+
|
|
131
|
+
hydrating.value = false
|
|
130
132
|
})
|
|
131
133
|
|
|
132
134
|
watch(
|