vue3-router-tab 1.4.1 → 1.4.3

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.
@@ -1 +1 @@
1
- (function(E,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("vue"),require("vue-router")):typeof define=="function"&&define.amd?define(["exports","vue","vue-router"],n):(E=typeof globalThis<"u"?globalThis:E||self,n(E["vue3-router-tab"]={},E.Vue,E.VueRouter))})(this,(function(E,n,De){"use strict";function xe(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 I(e,a){const r=e.resolve(a);if(!r||!r.matched.length)throw new Error(`[RouterTabs] Unable to resolve route: ${String(a)}`);return r}const Me={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 V(e){const a=e.meta?.key;if(typeof a=="function"){const r=a(e);if(typeof r=="string"&&r.length)return r}else if(typeof a=="string"&&a.length){const r=Me[a.toLowerCase()];return r?r(e):a}return e.fullPath}function te(e,a){const r=e.meta?.keepAlive;return typeof r=="boolean"?r:a}function ne(e,a){const r=e.meta?.reuse;return typeof r=="boolean"?r:a}function he(e){const a=e.meta??{},r={};return"title"in a&&(r.title=a.title),"tips"in a&&(r.tips=a.tips),"icon"in a&&(r.icon=a.icon),"closable"in a&&(r.closable=a.closable),"tabClass"in a&&(r.tabClass=a.tabClass),"target"in a&&(r.target=a.target),"href"in a&&(r.href=a.href),r}function W(e,a,r){const c=he(e);return{id:V(e),to:e.fullPath,fullPath:e.fullPath,matched:e,alive:te(e,r),reusable:ne(e,!1),closable:c.closable??!0,renderKey:typeof a.renderKey=="number"?a.renderKey:0,...c,...a}}function oe(e,a,r,c){if(!e.find(h=>h.id===a.id)){if(r==="next"&&c){const h=e.findIndex(w=>w.id===c);if(h!==-1){e.splice(h+1,0,a);return}}e.push(a)}}function J(e,a,r,c){if(!a||a<=0)return;const i=e.filter(h=>h.alive);for(;i.length>a;){const h=i.shift();if(!h||h.id===r)continue;const w=e.findIndex(l=>l.id===h.id);if(w>-1){const l=e[w],g=`${l.id}::${l.renderKey??0}`;c.delete(g),l.alive=!1}}}function Le(e){return{to:e.to,title:e.title,tips:e.tips,icon:e.icon,tabClass:e.tabClass,closable:e.closable,renderKey:e.renderKey}}function Ve(e){const a={};return"title"in e&&(a.title=e.title),"tips"in e&&(a.tips=e.tips),"icon"in e&&(a.icon=e.icon),"tabClass"in e&&(a.tabClass=e.tabClass),"closable"in e&&(a.closable=e.closable),"renderKey"in e&&typeof e.renderKey=="number"&&(a.renderKey=e.renderKey),a}function Ne(e,a={}){const r=xe(a),c=n.reactive([]),i=n.ref(null),h=n.shallowRef(),w=n.ref(null),l=n.reactive(new Set),g=n.computed(()=>Array.from(l));let y=!1;function k(u){const b=typeof u.matched=="object"?u:I(e,u);return{key:V(b),fullPath:b.fullPath,alive:te(b,r.keepAlive),reusable:ne(b,!1),matched:b}}function S(u){const b=V(u);let d=c.find(v=>v.id===b);const T=te(u,r.keepAlive);if(d){d.fullPath=u.fullPath,d.to=u.fullPath,d.matched=u,d.reusable=ne(u,d.reusable),typeof d.renderKey!="number"&&(d.renderKey=0);const v=`${b}::${d.renderKey}`;return T?l.has(v)?d.alive||(d.alive=!0):(l.add(v),d.alive=!0):d.alive&&(l.delete(v),d.alive=!1),Object.assign(d,he(u)),d}if(d=W(u,{},r.keepAlive),d.alive){const v=`${b}::${d.renderKey??0}`;l.add(v)}return oe(c,d,r.appendPosition,i.value),J(c,r.maxAlive,i.value,l),d}async function P(u,b=!1,d="sameTab"){const T=I(e,u),v=V(T),B=i.value===v;d==="sameTab"&&(d=B),d&&await M(v,!0),await e[b?"replace":"push"](T),B&&await _()}function D(u){const b=c.findIndex(K=>K.id===u);if(b===-1)return r.defaultRoute;const d=c[b+1],T=c[b-1],v=c.find(K=>K.id!==u),B=d||T||v;return B?B.to:r.defaultRoute}async function x(u=i.value,b={}){if(!u)return;if(!b.force&&r.keepLastTab&&c.length===1)throw new Error("[RouterTabs] Unable to close the final tab when keepLastTab is true.");const T=i.value===u&&b.redirect!==null,v=T?b.redirect??D(u):null;await U(u,{force:b.force}),b.redirect!==null&&T&&v&&await e.replace(v)}async function U(u,b={}){const d=c.findIndex(B=>B.id===u);if(d===-1)return;const T=c[d],v=`${u}::${T.renderKey??0}`;l.delete(v),T.alive=!1,c.splice(d,1),w.value===u&&(w.value=null),i.value===u&&(i.value=null,h.value=void 0)}async function M(u=i.value??void 0,b=!1){if(!u)return;const d=c.find(K=>K.id===u);if(!d)return;const T=r.keepAlive&&d.alive,v=`${u}::${d.renderKey??0}`;T&&(l.delete(v),d.alive=!1,await n.nextTick()),d.renderKey=(d.renderKey??0)+1;const B=`${u}::${d.renderKey}`;T&&(l.add(B),d.alive=!0),w.value=u,await n.nextTick(),b||await n.nextTick(),w.value=null}async function se(u=!1){for(const b of c)await M(b.id,u)}function ce(u,b){const d=c.find(v=>v.id===u);if(!d)return;const T=`${u}::${d.renderKey??0}`;b?(l.add(T),d.alive=!0,J(c,r.maxAlive,i.value,l)):(l.delete(T),d.alive=!1)}function R(u){const b=c.find(T=>T.id===u);if(!b)return;const d=`${u}::${b.renderKey??0}`;l.delete(d),b.alive=!1,b.renderKey=(b.renderKey??0)+1}function Z(){l.clear(),c.forEach(u=>{u.alive=!1})}function L(){return g.value.slice()}async function A(u=r.defaultRoute){c.splice(0,c.length),i.value=null,h.value=void 0;for(const b of r.initialTabs){const d=I(e,b.to),T=W(d,b,r.keepAlive);c.push(T)}await e.replace(u)}async function _(){const u=i.value;u&&await M(u,!0)}function z(u){return typeof u.matched=="object"?V(u):V(I(e,u))}function C(){const u=c.find(b=>b.id===i.value);return{tabs:c.map(Le),active:u?u.to:null}}async function ue(u){y=!0,c.splice(0,c.length),i.value=null,h.value=void 0;const b=u?.tabs??[];for(const T of b)try{const v=I(e,T.to),B=Ve(T),K=W(v,B,r.keepAlive);oe(c,K,"last",null)}catch(v){console.warn("[RouterTabs] Failed to restore tab",T,v)}y=!1;const d=u?.active??b[b.length-1]?.to??r.defaultRoute;if(d)try{const T=I(e,d),v=e.currentRoute.value;if(T.fullPath===v.fullPath){const B=S(v);i.value=B.id,h.value=B,J(c,r.maxAlive,i.value,l);return}await e.replace(T)}catch(T){console.warn("[RouterTabs] Failed to navigate to restored route",d,T)}}return n.watch(()=>e.currentRoute.value,u=>{if(y)return;const b=S(u);i.value=b.id,h.value=b,J(c,r.maxAlive,i.value,l)},{immediate:!0}),r.initialTabs.length&&r.initialTabs.forEach(u=>{const b=I(e,u.to),d=W(b,u,r.keepAlive);oe(c,d,"last",null)}),{options:r,tabs:c,activeId:i,current:h,includeKeys:g,refreshingKey:w,openTab:P,closeTab:x,removeTab:U,refreshTab:M,refreshAll:se,setTabAlive:ce,evictCache:R,clearCache:Z,getCacheKeys:L,reset:A,reload:_,getRouteKey:z,matchRoute:k,snapshot:C,hydrate:ue,ensureTab:S}}function ye(e){return e?typeof e=="string"?{name:e}:e:{}}const O=Symbol("RouterTabsContext"),q="router-tabs:snapshot";function re(e={}){const{optional:a=!1}=e,r=n.inject(O,null);if(r)return r;const c=n.inject("$tabs",null);if(c)return c;const h=n.getCurrentInstance()?.appContext.config.globalProperties.$tabs;if(h)return h;if(!a)throw new Error("[RouterTabs] useRouterTabs must be used within <router-tab>.");return null}const Oe=864e5;function je(e){if(typeof document>"u")return null;const a=`${encodeURIComponent(e)}=`,r=document.cookie?document.cookie.split("; "):[];for(const c of r)if(c.startsWith(a))return decodeURIComponent(c.slice(a.length));return null}function Te(e,a,r){if(typeof document>"u")return;const{expiresInDays:c=7,path:i="/",domain:h,secure:w,sameSite:l="lax"}=r,g=[`${encodeURIComponent(e)}=${encodeURIComponent(a)}`];if(c!==1/0){const y=new Date(Date.now()+c*Oe).toUTCString();g.push(`Expires=${y}`)}i&&g.push(`Path=${i}`),h&&g.push(`Domain=${h}`),w&&g.push("Secure"),l&&g.push(`SameSite=${l.charAt(0).toUpperCase()}${l.slice(1)}`),document.cookie=g.join("; ")}function ve(e,a){if(typeof document>"u")return;const{path:r="/",domain:c}=a,i=[`${encodeURIComponent(e)}=`];i.push("Expires=Thu, 01 Jan 1970 00:00:01 GMT"),r&&i.push(`Path=${r}`),c&&i.push(`Domain=${c}`),document.cookie=i.join("; ")}const Ue=e=>JSON.stringify(e??null),_e=e=>{if(!e)return null;try{return JSON.parse(e)}catch{return null}};function ae(e={}){const{cookieKey:a=q,serialize:r=Ue,deserialize:c=_e}=e,i=re({optional:!0}),h=n.ref(!1),w=(l,g="hook")=>{const y=async()=>{h.value=!0;try{const k=c(je(a));if(k&&k.tabs?.length){if(await l.hydrate(k),k.active){await n.nextTick();const P=l.tabs.find(D=>D.to===k.active);P&&(l.activeId.value=P.id,l.current.value=P)}}else if(Object.prototype.hasOwnProperty.call(e,"fallbackRoute")){const P=e.fallbackRoute??l.options.defaultRoute;await l.reset(P)}const S=l.snapshot();S.tabs.length?Te(a,r(S),e):ve(a,e)}finally{h.value=!1}};g==="immediate"?y():n.onBeforeMount(()=>{y()}),n.watch(()=>({tabs:l.tabs.map(k=>({to:k.to,title:k.title,tips:k.tips,icon:k.icon,tabClass:k.tabClass,closable:k.closable,renderKey:k.renderKey})),active:l.activeId.value}),()=>{if(h.value)return;const k=l.snapshot();k.tabs.length?Te(a,r(k),e):ve(a,e)},{deep:!0})};return i?w(i):n.onMounted(()=>{const l=re({optional:!0});l&&w(l,"immediate")}),{hydrating:h}}const ze=n.defineComponent({name:"RouterTab",components:{RouterView:De.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:q},persistence:{type:Object,default:null},sortable:{type:Boolean,default:!0}},emits:["tab-sort","tab-sorted"],setup(e,{emit:a}){const r=n.getCurrentInstance();if(!r)throw new Error("[RouterTab] component must be used within a Vue application context.");const c=r.appContext.app.config.globalProperties.$router;if(!c)throw new Error("[RouterTab] Vue Router is required. Make sure to call app.use(router) before RouterTab.");const i=Ne(c,{initialTabs:e.tabs,keepAlive:e.keepAlive,maxAlive:e.maxAlive,keepLastTab:e.keepLastTab,appendPosition:e.append,defaultRoute:e.defaultPage});n.provide(O,i),r.appContext.config.globalProperties.$tabs=i;const h=n.computed(()=>!!r?.slots?.default),w=n.computed(()=>!!r?.slots?.start),l=n.computed(()=>!!r?.slots?.end),g=n.ref(0),y=n.computed(()=>{g.value;const t={};return i.tabs.forEach(o=>{const s=typeof o.title=="string"?o.title:String(o.title||de(o));t[o.id]=s}),t});function k(){g.value++}const S=new Map,P=new Map;function D(t,o){if(!(!o||S.has(t)))try{S.set(t,o);const s=i.tabs.find(p=>i.getRouteKey(p.to)===t);if(!s){console.warn(`[RouterTab] Cannot setup watching: tab not found for ${t}`);return}const m=[];if(o.routeTabTitle!==void 0)try{const p=n.watch(()=>{const f=o.routeTabTitle;return f&&typeof f=="object"&&"value"in f?f.value:f},f=>{if(f!=null){const N=String(f);s.title=N,k()}},{immediate:!0});m.push(p)}catch(p){console.error(`[RouterTab] Error watching routeTabTitle for ${t}:`,p)}if(o.routeTabIcon!==void 0)try{const p=n.watch(()=>{const f=o.routeTabIcon;return f&&typeof f=="object"&&"value"in f?f.value:f},f=>{f!=null&&(s.icon=String(f),k())},{immediate:!0});m.push(p)}catch(p){console.error(`[RouterTab] Error watching routeTabIcon for ${t}:`,p)}if(o.routeTabClosable!==void 0)try{const p=n.watch(()=>{const f=o.routeTabClosable;return f&&typeof f=="object"&&"value"in f?f.value:f},f=>{f!=null&&(s.closable=!!f,k())},{immediate:!0});m.push(p)}catch(p){console.error(`[RouterTab] Error watching routeTabClosable for ${t}:`,p)}if(o.routeTabMeta!==void 0)try{const p=n.watch(()=>{const f=o.routeTabMeta;return f&&typeof f=="object"&&"value"in f?f.value:f},f=>{f&&typeof f=="object"&&(Object.assign(s,f),k())},{immediate:!0,deep:!0});m.push(p)}catch(p){console.error(`[RouterTab] Error watching routeTabMeta for ${t}:`,p)}P.set(t,m)}catch(s){console.error(`[RouterTab] Error in setupComponentWatching for ${t}:`,s),x(t)}}function x(t){try{const o=P.get(t);o&&(o.forEach(s=>{try{s()}catch(m){console.error(`[RouterTab] Error cleaning up watcher for ${t}:`,m)}}),P.delete(t)),S.delete(t)}catch(o){console.error(`[RouterTab] Error in cleanupComponentWatching for ${t}:`,o)}}function U(t,o){try{t?t.routeTabTitle!==void 0||t.routeTabIcon!==void 0||t.routeTabClosable!==void 0?D(o,t):t.$&&(t.$.routeTabTitle!==void 0||t.$.routeTabIcon!==void 0||t.$.routeTabClosable!==void 0)&&D(o,t.$):t===null&&x(o)}catch(s){console.error(`[RouterTab] Error handling component ref for ${o}:`,s),x(o)}}n.onErrorCaptured((t,o,s)=>(console.error("[RouterTab] Error captured from component:",t,s),!1));let M=n.ref(!1);if(e.cookieKey!==null||e.persistence){const t={...e.persistence??{}};e.cookieKey!==null?t.cookieKey=e.cookieKey||q:t.cookieKey||(t.cookieKey=q),M=ae(t).hydrating}const se=n.computed(()=>ye(e.tabTransition)),ce=n.computed(()=>ye(e.pageTransition)),R=n.reactive({visible:!1,target:null,position:{x:0,y:0}}),Z=n.ref(null),L=n.ref([]),A=n.ref(-1),_=n.ref(null),z=new Map,C=n.reactive({dragging:!1,dragIndex:-1,dropIndex:-1,dragTab:null}),ue=["refresh","refreshAll","close","closeLefts","closeRights","closeOthers"];function u(t){return i.tabs.findIndex(o=>o.id===t)}function b(t){const o=u(t.id);return o>0?i.tabs.slice(0,o):[]}function d(t){const o=u(t.id);return o>-1?i.tabs.slice(o+1):[]}function T(t){return i.tabs.filter(o=>o.id!==t.id)}async function v(t,o){const s=t.filter(m=>m.closable!==!1);if(s.length){for(const m of s)i.activeId.value===m.id?await i.closeTab(m.id,{redirect:o.to,force:!0}):await i.removeTab(m.id,{force:!0});i.activeId.value!==o.id&&await i.openTab(o.to,!0,!1)}}const B={refresh:{label:"Refresh",handler:async({target:t})=>{await i.refreshTab(t.id,!0)}},refreshAll:{label:"Refresh All",handler:async()=>{await i.refreshAll(!0)}},close:{label:"Close",handler:async({target:t})=>{await i.closeTab(t.id)},enable:({target:t})=>be(t)},closeLefts:{label:"Close to the Left",handler:async({target:t})=>{await v(b(t),t)},enable:({target:t})=>b(t).some(o=>o.closable!==!1)},closeRights:{label:"Close to the Right",handler:async({target:t})=>{await v(d(t),t)},enable:({target:t})=>d(t).some(o=>o.closable!==!1)},closeOthers:{label:"Close Others",handler:async({target:t})=>{await v(T(t),t)},enable:({target:t})=>T(t).some(o=>o.closable!==!1)}};function K(){R.visible=!1,R.target=null,A.value=-1,L.value=[]}function dt(t,o){e.contextmenu&&(R.target=t,R.position.x=o.clientX,R.position.y=o.clientY,n.nextTick(()=>{R.visible=!0,document.addEventListener("click",K,{once:!0}),n.nextTick(()=>{bt()})}))}function ft(t,o){const s=typeof t=="string"?{id:t}:t,m=B[s.id],p=s.label??m?.label??String(s.id),f=s.visible??m?.visible??!0;if(!(typeof f=="function"?f(o):f!==!1))return null;const ge=s.enable??m?.enable??!0,Mt=typeof ge=="function"?ge(o):ge!==!1,Ie=s.handler??m?.handler;if(!Ie)return null;const Lt=async()=>{await Promise.resolve(Ie(o))};return{id:String(s.id),label:p,disabled:!Mt,action:Lt}}const F=n.computed(()=>{if(!R.visible||!R.target||e.contextmenu===!1)return[];const t=Array.isArray(e.contextmenu)?e.contextmenu:ue,o={target:R.target,controller:i};return t.map(s=>ft(s,o)).filter(s=>!!s)});function bt(){const t=Z.value;if(!t)return;const o=8,{innerWidth:s,innerHeight:m}=window,p=t.getBoundingClientRect();let f=R.position.x,N=R.position.y;p.right>s-o&&(f=Math.max(o,s-p.width-o)),p.bottom>m-o&&(N=Math.max(o,m-p.height-o)),(f!==R.position.x||N!==R.position.y)&&(R.position.x=f,R.position.y=N)}function mt(t,o){L.value[o]=t??null}function pt(t){if(t<0)return;L.value[t]?.focus({preventScroll:!0})}function ee(t,o,s=F.value){if(!s.length)return-1;const m=s.length;let p=t;for(let f=0;f<m;f++)if(p=(p+o+m)%m,!s[p].disabled)return p;return-1}function Y(t){A.value=t,!(t<0)&&n.nextTick(()=>pt(t))}function Be(t){const o=ee(A.value,t);o!==-1&&Y(o)}function gt(t){if(!R.visible)return;const o=t.key,s=F.value;if(!s.length)return;if(o==="Tab"){K();return}if(["ArrowDown","ArrowUp","ArrowRight","ArrowLeft","Home","End","Enter"," ","Spacebar","Escape"].includes(o))switch(t.preventDefault(),o){case"ArrowDown":case"ArrowRight":Be(1);break;case"ArrowUp":case"ArrowLeft":Be(-1);break;case"Home":Y(ee(-1,1));break;case"End":Y(ee(s.length,-1));break;case"Enter":case" ":case"Spacebar":{const p=A.value;if(p>-1){const f=s[p];f.disabled||$e(f)}break}case"Escape":K();break}}async function $e(t){t.disabled||(K(),await t.action())}function de(t){return typeof t.title=="string"&&t.title.trim()?t.title:Array.isArray(t.title)&&t.title.length&&String(t.title[0]).trim()?String(t.title[0]):"Untitled"}function ht(t){return y.value[t.id]||de(t)}function Pe(t,o){return n.defineComponent({name:o,setup(s,{attrs:m,slots:p}){return()=>n.h(t,m,p)}})}const H=new Map,fe=n.ref(0);function yt(t,o,s){H.has(s)||(H.set(s,o),fe.value++),t&&U(t,s)}function Tt(t,o){return t&&((!t.name||t.name!==o)&&(t.name=o),t)}function vt(t,o){if(!t)return t;const s=H.get(o);if(s)return s;const m=Pe(t,o);return H.set(o,m),fe.value++,m}function kt(t){const o=i.getRouteKey(t),s=c.currentRoute.value,m=i.getRouteKey(s);return o===m}function Se(t){const o=i.getRouteKey(t),s=i.tabs.find(f=>f.id===o);if(!s)return console.warn("[RouterTab] Tab not found for route:",o),`${o}::0`;const m=s.renderKey??0,p=`${o}::${m}`;return(o.includes("students")||o.includes("classroom")||o.includes("quiz"))&&console.log(`[getComponentCacheKey] Route: ${t.fullPath}`,{routeKey:o,renderKey:m,cacheKey:p,tabAlive:s.alive,includeKeys:pe.value,isIncluded:pe.value.includes(p)}),p}function wt(t){return`${Se(t)}::refresh`}function be(t){return!(t.closable===!1||i.options.keepLastTab&&i.tabs.length<=1)}async function Rt(t){await i.closeTab(t.id)}function Ct(t,o){o?z.set(t,o):z.delete(t)}function me(t){n.nextTick(()=>{const o=z.get(t),s=_.value;if(o&&s){const m=o.getBoundingClientRect(),p=s.getBoundingClientRect();(m.left<p.left||m.right>p.right)&&o.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"})}})}function Et(t){if(t.href&&typeof window<"u"){t.target&&t.target!=="_self"?window.open(t.href,t.target):window.location.assign(t.href);return}i.activeId.value!==t.id&&(i.openTab(t.to,!1),me(t.id))}function Kt(t){return["router-tab__item",{"is-active":i.activeId.value===t.id,"is-closable":be(t),"is-dragging":C.dragging&&C.dragTab?.id===t.id,"is-drag-over":C.dropIndex===u(t.id)},t.tabClass]}function Bt(t){return i.refreshingKey.value===i.getRouteKey(t)}function $t(t){const o=i.getRouteKey(t),s=i.tabs.find(m=>m.id===o);return s?s.alive:!1}function Pt(t){const o=i.getRouteKey(t);return!!i.tabs.find(m=>m.id===o)}function St(t,o,s){e.sortable&&(C.dragging=!0,C.dragIndex=o,C.dragTab=t,s.dataTransfer&&(s.dataTransfer.effectAllowed="move",s.dataTransfer.setData("text/plain",t.id)),a("tab-sort",{tab:t,index:o}))}function At(t,o){!e.sortable||!C.dragging||(o.preventDefault(),o.dataTransfer&&(o.dataTransfer.dropEffect="move"))}function It(t){!e.sortable||!C.dragging||(C.dropIndex=t)}function Dt(){!e.sortable||C.dragging}function xt(t,o){if(!(!e.sortable||!C.dragging)){if(o.preventDefault(),C.dragIndex!==-1&&C.dragIndex!==t){const s=i.tabs.splice(C.dragIndex,1)[0];i.tabs.splice(t,0,s),a("tab-sorted",{tab:s,fromIndex:C.dragIndex,toIndex:t})}Ae()}}function Ae(){C.dragging=!1,C.dragIndex=-1,C.dropIndex=-1,C.dragTab=null}n.onMounted(()=>{document.addEventListener("keydown",K)}),n.onBeforeUnmount(()=>{document.removeEventListener("keydown",K),r.appContext.config.globalProperties.$tabs=null,P.forEach(t=>{t.forEach(o=>{try{o()}catch(s){console.error("[RouterTab] Error during cleanup:",s)}})}),P.clear(),S.clear()}),n.watch(()=>e.keepAlive,t=>{i.options.keepAlive=t}),n.watch(()=>i.activeId.value,t=>{t&&me(t),K()}),n.watch(()=>i.tabs.length,()=>{const t=new Set(i.tabs.map(s=>s.id));Array.from(S.keys()).forEach(s=>{t.has(s)||(console.log(`[RouterTab] Cleaning up stale component instance: ${s}`),x(s))})}),n.watch(()=>e.contextmenu,t=>{t||K()}),n.watch(()=>F.value.length,t=>{R.visible&&t===0&&K()},{flush:"post"}),n.watch(F,t=>{if(!R.visible)return;L.value=new Array(t.length).fill(null);const o=ee(-1,1,t);Y(o)},{flush:"post"}),n.watch(()=>R.visible,t=>{t||(A.value=-1,L.value=[])});const pe=i.includeKeys;return{controller:i,tabs:i.tabs,includeKeys:pe,persistenceHydrating:M,componentCache:H,componentCacheTrigger:fe,cacheCurrentComponent:yt,tabTransitionProps:se,pageTransitionProps:ce,buildTabClass:Kt,activate:Et,close:Rt,context:R,menuItems:F,handleMenuAction:$e,showContextMenu:dt,hideContextMenu:K,getTabTitle:de,isClosable:be,isRefreshing:Bt,isTabCached:$t,isTabReady:Pt,hasCustomSlot:h,hasStartSlot:w,hasEndSlot:l,onDragStart:St,onDragOver:At,onDragEnter:It,onDragLeave:Dt,onDrop:xt,onDragEnd:Ae,setupComponentWatching:D,cleanupComponentWatching:x,handleComponentRef:U,getReactiveTabTitle:ht,getComponentCacheKey:Se,getRefreshComponentKey:wt,createNamedComponent:Pe,ensureNamedComponent:Tt,getNamedComponent:vt,shouldRenderRoute:kt,triggerTabUpdate:k,menuRef:Z,highlightedIndex:A,setMenuItemRef:mt,onMenuKeydown:gt,highlightMenuIndex:Y,scrollContainer:_,setTabRef:Ct,scrollTabIntoView:me}}}),Fe=(e,a)=>{const r=e.__vccOpts||e;for(const[c,i]of a)r[c]=i;return r},Ye={class:"router-tab"},He={class:"router-tab__header"},We={class:"router-tab__scroll",ref:"scrollContainer"},Je=["data-title","draggable","onClick","onAuxclick","onContextmenu","onDragstart","onDragover","onDragenter","onDrop"],qe=["title"],Ge=["onClick"],Xe={class:"router-tab__container"},Qe={key:1,class:"router-tab__hydrating","aria-hidden":"true"},Ze=["aria-disabled","disabled","tabindex","onMouseenter","onClick"];function et(e,a,r,c,i,h){const w=n.resolveComponent("RouterView");return n.openBlock(),n.createElementBlock("div",Ye,[n.createElementVNode("header",He,[n.createElementVNode("div",{class:n.normalizeClass(["router-tab__slot-start",{"has-content":e.hasStartSlot}])},[n.renderSlot(e.$slots,"start")],2),n.createElementVNode("div",We,[n.createVNode(n.TransitionGroup,n.mergeProps({tag:"ul",class:"router-tab__nav"},e.tabTransitionProps),{default:n.withCtx(()=>[(n.openBlock(!0),n.createElementBlock(n.Fragment,null,n.renderList(e.tabs,(l,g)=>(n.openBlock(),n.createElementBlock("li",{key:l.id,class:n.normalizeClass(e.buildTabClass(l)),"data-title":e.getTabTitle(l),draggable:e.sortable,ref_for:!0,ref:y=>e.setTabRef(l.id,y),onClick:y=>e.activate(l),onAuxclick:n.withModifiers(y=>e.close(l),["middle","prevent"]),onContextmenu:n.withModifiers(y=>e.showContextMenu(l,y),["prevent"]),onDragstart:y=>e.onDragStart(l,g,y),onDragover:y=>e.onDragOver(g,y),onDragenter:y=>e.onDragEnter(g),onDragleave:a[0]||(a[0]=(...y)=>e.onDragLeave&&e.onDragLeave(...y)),onDrop:y=>e.onDrop(g,y),onDragend:a[1]||(a[1]=(...y)=>e.onDragEnd&&e.onDragEnd(...y))},[l.icon?(n.openBlock(),n.createElementBlock("i",{key:0,class:n.normalizeClass(["router-tab__item-icon",l.icon])},null,2)):n.createCommentVNode("",!0),n.createElementVNode("span",{class:"router-tab__item-title",title:e.getReactiveTabTitle(l)},n.toDisplayString(e.getReactiveTabTitle(l)),9,qe),e.isClosable(l)?(n.openBlock(),n.createElementBlock("a",{key:1,class:"router-tab__item-close",onClick:n.withModifiers(y=>e.close(l),["stop"])},null,8,Ge)):n.createCommentVNode("",!0)],42,Je))),128))]),_:1},16)],512),n.createElementVNode("div",{class:n.normalizeClass(["router-tab__slot-end",{"has-content":e.hasEndSlot}])},[n.renderSlot(e.$slots,"end")],2)]),n.createElementVNode("div",Xe,[e.persistenceHydrating?(n.openBlock(),n.createElementBlock("div",Qe)):(n.openBlock(),n.createBlock(w,{key:0},{default:n.withCtx(({Component:l,route:g})=>[e.hasCustomSlot?n.renderSlot(e.$slots,"default",n.normalizeProps(n.mergeProps({key:0},{Component:l,route:g,controller:e.controller,pageRef:y=>e.handleComponentRef(y,e.controller.getRouteKey(g))}))):(n.openBlock(),n.createElementBlock(n.Fragment,{key:1},[e.controller.options.keepAlive?(n.openBlock(),n.createBlock(n.KeepAlive,{key:0,include:e.includeKeys},[l?(n.openBlock(),n.createBlock(n.resolveDynamicComponent(e.getNamedComponent(l,e.getComponentCacheKey(g))),{key:e.isRefreshing(g)?e.getRefreshComponentKey(g):e.getComponentCacheKey(g),ref:y=>e.handleComponentRef(y,e.controller.getRouteKey(g)),class:"router-tab-page"})):n.createCommentVNode("",!0)],1032,["include"])):(n.openBlock(),n.createBlock(n.Transition,n.mergeProps({key:1},e.pageTransitionProps,{appear:""}),{default:n.withCtx(()=>[l?(n.openBlock(),n.createBlock(n.resolveDynamicComponent(l),{key:e.controller.getRouteKey(g),ref:y=>e.handleComponentRef(y,e.controller.getRouteKey(g)),class:"router-tab-page"})):n.createCommentVNode("",!0)]),_:2},1040))],64))]),_:3}))]),n.withDirectives(n.createElementVNode("div",{ref:"menuRef",class:"router-tab__contextmenu",role:"menu",onKeydown:a[2]||(a[2]=(...l)=>e.onMenuKeydown&&e.onMenuKeydown(...l)),style:n.normalizeStyle({left:e.context.position.x+"px",top:e.context.position.y+"px"})},[(n.openBlock(!0),n.createElementBlock(n.Fragment,null,n.renderList(e.menuItems,(l,g)=>(n.openBlock(),n.createElementBlock("a",{key:l.id,role:"menuitem",class:n.normalizeClass(["router-tab__contextmenu-item",{"is-focused":g===e.highlightedIndex}]),"aria-disabled":l.disabled,disabled:l.disabled,tabindex:l.disabled?-1:g===e.highlightedIndex?0:-1,ref_for:!0,ref:y=>e.setMenuItemRef(y,g),onMouseenter:y=>!l.disabled&&e.highlightMenuIndex(g),onClick:y=>e.handleMenuAction(l)},n.toDisplayString(l.label),43,Ze))),128))],36),[[n.vShow,e.context.visible&&e.context.target]])])}const ie=Fe(ze,[["render",et]]),tt={class:"router-tabs","aria-hidden":"true"},G=n.defineComponent({name:"RouterTabs",__name:"RouterTabs",props:{cookieKey:{},expiresInDays:{},path:{},domain:{},secure:{type:Boolean},sameSite:{},serialize:{type:Function},deserialize:{type:Function},fallbackRoute:{}},setup(e){return ae(e),(r,c)=>(n.openBlock(),n.createElementBlock("span",tt))}}),ke="tab-theme-style",we="tab-theme-primary-color",nt="system",Re="(prefers-color-scheme: dark)";let j=null;const $={primary:"#034960",background:"#ffffff",text:"#1e293b",border:"#e2e8f0",activeBackground:"#034960",activeText:"#ffffff",activeBorder:"#034960",headerBackground:"#ffffff",buttonBackground:"#f8fafc",buttonColor:"#034960",activeButtonBackground:"#034960",activeButtonColor:"#ffffff",iconColor:"#475569"},ot={primary:"#38bdf8",background:"#0f172a",text:"#f1f5f9",border:"#334155",activeBackground:"#1e293b",activeText:"#38bdf8",activeBorder:"#38bdf8",headerBackground:"#0c4a6e",buttonBackground:"#1e293b",buttonColor:"#f1f5f9",activeButtonBackground:"#38bdf8",activeButtonColor:"#0f172a",iconColor:"#cbd5e1"};function rt(e){if(typeof window>"u")return null;const a=window.localStorage.getItem(e);if(!a)return null;try{const r=JSON.parse(a);return r&&typeof r=="object"?r:null}catch{return null}}function le(e){typeof document>"u"||(document.documentElement.style.setProperty("--router-tab-primary",e.primary??$.primary),document.documentElement.style.setProperty("--router-tab-header-bg",e.headerBackground??$.headerBackground),document.documentElement.style.setProperty("--router-tab-background",e.background??$.background),document.documentElement.style.setProperty("--router-tab-active-background",e.activeBackground??$.activeBackground),document.documentElement.style.setProperty("--router-tab-text",e.text??$.text),document.documentElement.style.setProperty("--router-tab-active-text",e.activeText??$.activeText),document.documentElement.style.setProperty("--router-tab-border",e.border??$.border),document.documentElement.style.setProperty("--router-tab-active-border",e.activeBorder??$.activeBorder),document.documentElement.style.setProperty("--router-tab-button-color",e.buttonColor??$.buttonColor),document.documentElement.style.setProperty("--router-tab-active-button-color",e.activeButtonColor??$.activeButtonColor),document.documentElement.style.setProperty("--router-tab-button-background",e.buttonBackground??$.buttonBackground),document.documentElement.style.setProperty("--router-tab-active-button-background",e.activeButtonBackground??$.activeButtonBackground),document.documentElement.style.setProperty("--router-tab-icon-color",e.iconColor??$.iconColor))}function Ce(e){if(typeof document>"u")return;const a=document.documentElement,r=window.matchMedia(Re),c=()=>{a.dataset.theme=r.matches?"dark":"light"};j&&(r.removeEventListener("change",j),j=null),e==="system"?(c(),j=()=>c(),r.addEventListener("change",j)):a.dataset.theme=e}function Ee(e={}){if(typeof window>"u")return;const{styleKey:a=ke,primaryKey:r=we,defaultStyle:c=nt,defaultPrimary:i}=e,h=window.localStorage.getItem(a)??c;Ce(h);const l=h==="dark"||h==="system"&&window.matchMedia(Re).matches?{...ot}:{...$};i&&(l.primary=i);const g=rt(r);le(g?{...l,...g}:l)}function at(e,a){if(typeof window>"u")return;const r=a?.styleKey??ke;window.localStorage.setItem(r,e),Ce(e)}function it(e,a){if(typeof window>"u")return;const r=a?.primaryKey??we;window.localStorage.setItem(r,JSON.stringify(e)),le(e)}function X(e,a){if(n.isRef(e)){const c=!n.isReadonly(e);return{value:e,update:c?i=>{e.value=i}:()=>{}}}if(typeof e=="function"){const c=e;return{value:n.computed(c),update:()=>{}}}const r=n.ref(e===void 0?a:e);return{value:r,update:c=>{r.value=c}}}function Q(e={}){const a=X(e.title,"Untitled"),r=X(e.icon,""),c=X(e.closable,!0),i=X(e.meta,{});return{routeTabTitle:a.value,routeTabIcon:r.value,routeTabClosable:c.value,routeTabMeta:i.value,updateTitle:a.update,updateIcon:r.update,updateClosable:c.update,updateMeta:i.update}}function lt(e,a="Page"){return Q({title:n.computed(()=>e.value?"Loading...":a),icon:n.computed(()=>e.value?"mdi-loading mdi-spin":"mdi-page"),closable:n.computed(()=>!e.value)})}function st(e,a="Page",r="mdi-page"){return Q({title:n.computed(()=>e.value>0?`${a} (${e.value})`:a),icon:n.computed(()=>e.value>0?"mdi-bell-badge":r)})}function ct(e,a="Page"){const r={normal:{suffix:"",icon:"mdi-page"},loading:{suffix:" - Loading",icon:"mdi-loading mdi-spin"},error:{suffix:" - Error",icon:"mdi-alert"},success:{suffix:" - Success",icon:"mdi-check-circle"}};return Q({title:n.computed(()=>a+r[e.value].suffix),icon:n.computed(()=>r[e.value].icon),closable:n.computed(()=>e.value!=="loading")})}let Ke=!1;const ut={install(e,a){if(Ke)return;Ke=!0;const{initTheme:r=!0,themeOptions:c,componentName:i=ie.name||"RouterTab",tabsComponentName:h=G.name||"RouterTabs"}=a??{};r&&Ee(c??{}),e.component(i,ie),e.component(h,G),h.toLowerCase()!=="router-tabs"&&e.component("router-tabs",G),Object.defineProperty(e.config.globalProperties,"$tabs",{configurable:!0,enumerable:!1,get(){return e._context.provides[O]},set(w){w&&e.provide(O,w)}})}};E.RouterTab=ie,E.RouterTabs=G,E.default=ut,E.initRouterTabsTheme=Ee,E.routerTabsKey=O,E.setRouterTabsPrimary=it,E.setRouterTabsTheme=at,E.useLoadingTab=lt,E.useNotificationTab=st,E.useReactiveTab=Q,E.useRouterTabs=re,E.useRouterTabsPersistence=ae,E.useStatusTab=ct,Object.defineProperties(E,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
1
+ (function(E,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("vue"),require("vue-router")):typeof define=="function"&&define.amd?define(["exports","vue","vue-router"],n):(E=typeof globalThis<"u"?globalThis:E||self,n(E["vue3-router-tab"]={},E.Vue,E.VueRouter))})(this,(function(E,n,xe){"use strict";function De(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 x(e,a){const r=e.resolve(a);if(!r||!r.matched.length)throw new Error(`[RouterTabs] Unable to resolve route: ${String(a)}`);return r}const Me={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 N(e){const a=e.meta?.key;if(typeof a=="function"){const r=a(e);if(typeof r=="string"&&r.length)return r}else if(typeof a=="string"&&a.length){const r=Me[a.toLowerCase()];return r?r(e):a}return e.fullPath}function oe(e,a){const r=e.meta?.keepAlive;return typeof r=="boolean"?r:a}function re(e,a){const r=e.meta?.reuse;return typeof r=="boolean"?r:a}function ye(e){const a=e.meta??{},r={};return"title"in a&&(r.title=a.title),"tips"in a&&(r.tips=a.tips),"icon"in a&&(r.icon=a.icon),"closable"in a&&(r.closable=a.closable),"tabClass"in a&&(r.tabClass=a.tabClass),"target"in a&&(r.target=a.target),"href"in a&&(r.href=a.href),r}function J(e,a,r){const s=ye(e);return{id:N(e),to:e.fullPath,fullPath:e.fullPath,matched:e,alive:oe(e,r),reusable:re(e,!1),closable:s.closable??!0,renderKey:typeof a.renderKey=="number"?a.renderKey:0,...s,...a}}function ae(e,a,r,s){if(!e.find(p=>p.id===a.id)){if(r==="next"&&s){const p=e.findIndex(w=>w.id===s);if(p!==-1){e.splice(p+1,0,a);return}}e.push(a)}}function q(e,a,r,s){if(!a||a<=0)return;const i=e.filter(p=>p.alive);for(;i.length>a;){const p=i.shift();if(!p||p.id===r)continue;const w=e.findIndex(l=>l.id===p.id);if(w>-1){const l=e[w],y=`${l.id}::${l.renderKey??0}`;s.delete(y),l.alive=!1}}}function Le(e){return{to:e.to,title:e.title,tips:e.tips,icon:e.icon,tabClass:e.tabClass,closable:e.closable,renderKey:e.renderKey}}function Ve(e){const a={};return"title"in e&&(a.title=e.title),"tips"in e&&(a.tips=e.tips),"icon"in e&&(a.icon=e.icon),"tabClass"in e&&(a.tabClass=e.tabClass),"closable"in e&&(a.closable=e.closable),"renderKey"in e&&typeof e.renderKey=="number"&&(a.renderKey=e.renderKey),a}function Ne(e,a={}){const r=De(a),s=n.reactive([]),i=n.ref(null),p=n.shallowRef(),w=n.ref(null),l=n.reactive(new Set),y=n.computed(()=>Array.from(l));let g=!1;function v(u){const b=typeof u.matched=="object"?u:x(e,u);return{key:N(b),fullPath:b.fullPath,alive:oe(b,r.keepAlive),reusable:re(b,!1),matched:b}}function S(u){const b=N(u);let f=s.find(k=>k.id===b);const T=oe(u,r.keepAlive);if(f){f.fullPath=u.fullPath,f.to=u.fullPath,f.matched=u,f.reusable=re(u,f.reusable),typeof f.renderKey!="number"&&(f.renderKey=0);const k=`${b}::${f.renderKey}`;return T?l.has(k)?f.alive||(f.alive=!0):(l.add(k),f.alive=!0):f.alive&&(l.delete(k),f.alive=!1),Object.assign(f,ye(u)),f}if(f=J(u,{},r.keepAlive),f.alive){const k=`${b}::${f.renderKey??0}`;l.add(k)}return ae(s,f,r.appendPosition,i.value),q(s,r.maxAlive,i.value,l),f}async function $(u,b=!1,f="sameTab"){const T=x(e,u),k=N(T),K=i.value===k;f==="sameTab"&&(f=K),f&&await L(k,!0),await e[b?"replace":"push"](T),K&&await U()}function D(u){const b=s.findIndex(B=>B.id===u);if(b===-1)return r.defaultRoute;const f=s[b+1],T=s[b-1],k=s.find(B=>B.id!==u),K=f||T||k;return K?K.to:r.defaultRoute}async function M(u=i.value,b={}){if(!u)return;if(!b.force&&r.keepLastTab&&s.length===1)throw new Error("[RouterTabs] Unable to close the final tab when keepLastTab is true.");const T=i.value===u&&b.redirect!==null,k=T?b.redirect??D(u):null;await _(u,{force:b.force}),b.redirect!==null&&T&&k&&await e.replace(k)}async function _(u,b={}){const f=s.findIndex(K=>K.id===u);if(f===-1)return;const T=s[f],k=`${u}::${T.renderKey??0}`;l.delete(k),T.alive=!1,s.splice(f,1),w.value===u&&(w.value=null),i.value===u&&(i.value=null,p.value=void 0)}async function L(u=i.value??void 0,b=!1){if(!u)return;const f=s.find(B=>B.id===u);if(!f)return;const T=r.keepAlive&&f.alive,k=`${u}::${f.renderKey??0}`;T&&(l.delete(k),f.alive=!1,await n.nextTick()),f.renderKey=(f.renderKey??0)+1;const K=`${u}::${f.renderKey}`;T&&(l.add(K),f.alive=!0),w.value=u,await n.nextTick(),b||await n.nextTick(),w.value=null}async function ue(u=!1){for(const b of s)await L(b.id,u)}function de(u,b){const f=s.find(k=>k.id===u);if(!f)return;const T=`${u}::${f.renderKey??0}`;b?(l.add(T),f.alive=!0,q(s,r.maxAlive,i.value,l)):(l.delete(T),f.alive=!1)}function C(u){const b=s.find(T=>T.id===u);if(!b)return;const f=`${u}::${b.renderKey??0}`;l.delete(f),b.alive=!1,b.renderKey=(b.renderKey??0)+1}function ee(){l.clear(),s.forEach(u=>{u.alive=!1})}function V(){return y.value.slice()}async function I(u=r.defaultRoute){s.splice(0,s.length),i.value=null,p.value=void 0;for(const b of r.initialTabs){const f=x(e,b.to),T=J(f,b,r.keepAlive);s.push(T)}await e.replace(u)}async function U(){const u=i.value;u&&await L(u,!0)}function z(u){return typeof u.matched=="object"?N(u):N(x(e,u))}function R(){const u=s.find(b=>b.id===i.value);return{tabs:s.map(Le),active:u?u.to:null}}async function fe(u){g=!0,s.splice(0,s.length),i.value=null,p.value=void 0;const b=u?.tabs??[];for(const T of b)try{const k=x(e,T.to),K=Ve(T),B=J(k,K,r.keepAlive);ae(s,B,"last",null)}catch(k){console.warn("[RouterTabs] Failed to restore tab",T,k)}g=!1;const f=u?.active??b[b.length-1]?.to??r.defaultRoute;if(f)try{const T=x(e,f),k=e.currentRoute.value;if(T.fullPath===k.fullPath){const K=S(k);i.value=K.id,p.value=K,q(s,r.maxAlive,i.value,l);return}await e.replace(T)}catch(T){console.warn("[RouterTabs] Failed to navigate to restored route",f,T)}}return n.watch(()=>e.currentRoute.value,u=>{if(g)return;const b=S(u);i.value=b.id,p.value=b,q(s,r.maxAlive,i.value,l)},{immediate:!0}),r.initialTabs.length&&r.initialTabs.forEach(u=>{const b=x(e,u.to),f=J(b,u,r.keepAlive);ae(s,f,"last",null)}),{options:r,tabs:s,activeId:i,current:p,includeKeys:y,refreshingKey:w,openTab:$,closeTab:M,removeTab:_,refreshTab:L,refreshAll:ue,setTabAlive:de,evictCache:C,clearCache:ee,getCacheKeys:V,reset:I,reload:U,getRouteKey:z,matchRoute:v,snapshot:R,hydrate:fe,ensureTab:S}}function Te(e){return e?typeof e=="string"?{name:e}:e:{}}const O=Symbol("RouterTabsContext"),G="router-tabs:snapshot";function ie(e={}){const{optional:a=!1}=e,r=n.inject(O,null);if(r)return r;const s=n.inject("$tabs",null);if(s)return s;const p=n.getCurrentInstance()?.appContext.config.globalProperties.$tabs;if(p)return p;if(!a)throw new Error("[RouterTabs] useRouterTabs must be used within <router-tab>.");return null}const Oe=864e5;function je(e){if(typeof document>"u")return null;const a=`${encodeURIComponent(e)}=`,r=document.cookie?document.cookie.split("; "):[];for(const s of r)if(s.startsWith(a))return decodeURIComponent(s.slice(a.length));return null}function ke(e,a,r){if(typeof document>"u")return;const{expiresInDays:s=7,path:i="/",domain:p,secure:w,sameSite:l="lax"}=r,y=[`${encodeURIComponent(e)}=${encodeURIComponent(a)}`];if(s!==1/0){const g=new Date(Date.now()+s*Oe).toUTCString();y.push(`Expires=${g}`)}i&&y.push(`Path=${i}`),p&&y.push(`Domain=${p}`),w&&y.push("Secure"),l&&y.push(`SameSite=${l.charAt(0).toUpperCase()}${l.slice(1)}`),document.cookie=y.join("; ")}function ve(e,a){if(typeof document>"u")return;const{path:r="/",domain:s}=a,i=[`${encodeURIComponent(e)}=`];i.push("Expires=Thu, 01 Jan 1970 00:00:01 GMT"),r&&i.push(`Path=${r}`),s&&i.push(`Domain=${s}`),document.cookie=i.join("; ")}const _e=e=>JSON.stringify(e??null),Ue=e=>{if(!e)return null;try{return JSON.parse(e)}catch{return null}};function le(e={}){const{cookieKey:a=G,serialize:r=_e,deserialize:s=Ue}=e,i=ie({optional:!0}),p=n.ref(!0),w=(l,y="hook")=>{const g=async()=>{p.value=!0;try{const v=s(je(a));if(v&&v.tabs?.length){if(await l.hydrate(v),v.active){await n.nextTick();const $=l.tabs.find(D=>D.to===v.active);$&&(l.activeId.value=$.id,l.current.value=$)}}else if(Object.prototype.hasOwnProperty.call(e,"fallbackRoute")){const $=e.fallbackRoute??l.options.defaultRoute;await l.reset($)}const S=l.snapshot();S.tabs.length?ke(a,r(S),e):ve(a,e)}finally{p.value=!1}};y==="immediate"?g():n.onBeforeMount(()=>{g()}),n.watch(()=>({tabs:l.tabs.map(v=>({to:v.to,title:v.title,tips:v.tips,icon:v.icon,tabClass:v.tabClass,closable:v.closable,renderKey:v.renderKey})),active:l.activeId.value}),()=>{if(p.value)return;const v=l.snapshot();v.tabs.length?ke(a,r(v),e):ve(a,e)},{deep:!0})};return i?w(i):n.onMounted(()=>{const l=ie({optional:!0});l&&w(l,"immediate")}),{hydrating:p}}const ze=n.defineComponent({name:"RouterTab",components:{RouterView:xe.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:G},persistence:{type:Object,default:null},sortable:{type:Boolean,default:!0}},emits:["tab-sort","tab-sorted"],setup(e,{emit:a}){const r=n.getCurrentInstance();if(!r)throw new Error("[RouterTab] component must be used within a Vue application context.");const s=r.appContext.app.config.globalProperties.$router;if(!s)throw new Error("[RouterTab] Vue Router is required. Make sure to call app.use(router) before RouterTab.");const i=Ne(s,{initialTabs:e.tabs,keepAlive:e.keepAlive,maxAlive:e.maxAlive,keepLastTab:e.keepLastTab,appendPosition:e.append,defaultRoute:e.defaultPage});n.provide(O,i),r.appContext.config.globalProperties.$tabs=i;const p=n.computed(()=>!!r?.slots?.default),w=n.computed(()=>!!r?.slots?.start),l=n.computed(()=>!!r?.slots?.end),y=n.ref(0),g=n.computed(()=>{y.value;const t={};return i.tabs.forEach(o=>{const c=typeof o.title=="string"?o.title:String(o.title||be(o));t[o.id]=c}),t});function v(){y.value++}const S=new Map,$=new Map;function D(t,o){if(!(!o||S.has(t)))try{S.set(t,o);const c=i.tabs.find(h=>i.getRouteKey(h.to)===t);if(!c){console.warn(`[RouterTab] Cannot setup watching: tab not found for ${t}`);return}const m=[];if(o.routeTabTitle!==void 0)try{const h=n.watch(()=>{const d=o.routeTabTitle;return d&&typeof d=="object"&&"value"in d?d.value:d},d=>{if(d!=null){const A=String(d);c.title=A,v()}},{immediate:!0});m.push(h)}catch(h){console.error(`[RouterTab] Error watching routeTabTitle for ${t}:`,h)}if(o.routeTabIcon!==void 0)try{const h=n.watch(()=>{const d=o.routeTabIcon;return d&&typeof d=="object"&&"value"in d?d.value:d},d=>{d!=null&&(c.icon=String(d),v())},{immediate:!0});m.push(h)}catch(h){console.error(`[RouterTab] Error watching routeTabIcon for ${t}:`,h)}if(o.routeTabClosable!==void 0)try{const h=n.watch(()=>{const d=o.routeTabClosable;return d&&typeof d=="object"&&"value"in d?d.value:d},d=>{d!=null&&(c.closable=!!d,v())},{immediate:!0});m.push(h)}catch(h){console.error(`[RouterTab] Error watching routeTabClosable for ${t}:`,h)}if(o.routeTabMeta!==void 0)try{const h=n.watch(()=>{const d=o.routeTabMeta;return d&&typeof d=="object"&&"value"in d?d.value:d},d=>{d&&typeof d=="object"&&(Object.assign(c,d),v())},{immediate:!0,deep:!0});m.push(h)}catch(h){console.error(`[RouterTab] Error watching routeTabMeta for ${t}:`,h)}$.set(t,m)}catch(c){console.error(`[RouterTab] Error in setupComponentWatching for ${t}:`,c),M(t)}}function M(t){try{const o=$.get(t);o&&(o.forEach(c=>{try{c()}catch(m){console.error(`[RouterTab] Error cleaning up watcher for ${t}:`,m)}}),$.delete(t)),S.delete(t)}catch(o){console.error(`[RouterTab] Error in cleanupComponentWatching for ${t}:`,o)}}function _(t,o){try{t?t.routeTabTitle!==void 0||t.routeTabIcon!==void 0||t.routeTabClosable!==void 0?D(o,t):t.$&&(t.$.routeTabTitle!==void 0||t.$.routeTabIcon!==void 0||t.$.routeTabClosable!==void 0)&&D(o,t.$):t===null&&M(o)}catch(c){console.error(`[RouterTab] Error handling component ref for ${o}:`,c),M(o)}}n.onErrorCaptured((t,o,c)=>(console.error("[RouterTab] Error captured from component:",t,c),!1));let L=n.ref(!1);if(e.cookieKey!==null||e.persistence){const t={...e.persistence??{}};e.cookieKey!==null?t.cookieKey=e.cookieKey||G:t.cookieKey||(t.cookieKey=G),L=le(t).hydrating}const ue=n.computed(()=>Te(e.tabTransition)),de=n.computed(()=>Te(e.pageTransition)),C=n.reactive({visible:!1,target:null,position:{x:0,y:0}}),ee=n.ref(null),V=n.ref([]),I=n.ref(-1),U=n.ref(null),z=new Map,R=n.reactive({dragging:!1,dragIndex:-1,dropIndex:-1,dragTab:null}),fe=["refresh","refreshAll","close","closeLefts","closeRights","closeOthers"];function u(t){return i.tabs.findIndex(o=>o.id===t)}function b(t){const o=u(t.id);return o>0?i.tabs.slice(0,o):[]}function f(t){const o=u(t.id);return o>-1?i.tabs.slice(o+1):[]}function T(t){return i.tabs.filter(o=>o.id!==t.id)}async function k(t,o){const c=t.filter(m=>m.closable!==!1);if(c.length){for(const m of c)i.activeId.value===m.id?await i.closeTab(m.id,{redirect:o.to,force:!0}):await i.removeTab(m.id,{force:!0});i.activeId.value!==o.id&&await i.openTab(o.to,!0,!1)}}const K={refresh:{label:"Refresh",handler:async({target:t})=>{await i.refreshTab(t.id,!0)}},refreshAll:{label:"Refresh All",handler:async()=>{await i.refreshAll(!0)}},close:{label:"Close",handler:async({target:t})=>{await i.closeTab(t.id)},enable:({target:t})=>pe(t)},closeLefts:{label:"Close to the Left",handler:async({target:t})=>{await k(b(t),t)},enable:({target:t})=>b(t).some(o=>o.closable!==!1)},closeRights:{label:"Close to the Right",handler:async({target:t})=>{await k(f(t),t)},enable:({target:t})=>f(t).some(o=>o.closable!==!1)},closeOthers:{label:"Close Others",handler:async({target:t})=>{await k(T(t),t)},enable:({target:t})=>T(t).some(o=>o.closable!==!1)}};function B(){C.visible=!1,C.target=null,I.value=-1,V.value=[]}function dt(t,o){e.contextmenu&&(C.target=t,C.position.x=o.clientX,C.position.y=o.clientY,n.nextTick(()=>{C.visible=!0,document.addEventListener("click",B,{once:!0}),n.nextTick(()=>{bt()})}))}function ft(t,o){const c=typeof t=="string"?{id:t}:t,m=K[c.id],h=c.label??m?.label??String(c.id),d=c.visible??m?.visible??!0;if(!(typeof d=="function"?d(o):d!==!1))return null;const W=c.enable??m?.enable??!0,Ie=typeof W=="function"?W(o):W!==!1,ne=c.handler??m?.handler;if(!ne)return null;const he=async()=>{await Promise.resolve(ne(o))};return{id:String(c.id),label:h,disabled:!Ie,action:he}}const F=n.computed(()=>{if(!C.visible||!C.target||e.contextmenu===!1)return[];const t=Array.isArray(e.contextmenu)?e.contextmenu:fe,o={target:C.target,controller:i};return t.map(c=>ft(c,o)).filter(c=>!!c)});function bt(){const t=ee.value;if(!t)return;const o=8,{innerWidth:c,innerHeight:m}=window,h=t.getBoundingClientRect();let d=C.position.x,A=C.position.y;h.right>c-o&&(d=Math.max(o,c-h.width-o)),h.bottom>m-o&&(A=Math.max(o,m-h.height-o)),(d!==C.position.x||A!==C.position.y)&&(C.position.x=d,C.position.y=A)}function mt(t,o){V.value[o]=t??null}function pt(t){if(t<0)return;V.value[t]?.focus({preventScroll:!0})}function te(t,o,c=F.value){if(!c.length)return-1;const m=c.length;let h=t;for(let d=0;d<m;d++)if(h=(h+o+m)%m,!c[h].disabled)return h;return-1}function Y(t){I.value=t,!(t<0)&&n.nextTick(()=>pt(t))}function Pe(t){const o=te(I.value,t);o!==-1&&Y(o)}function gt(t){if(!C.visible)return;const o=t.key,c=F.value;if(!c.length)return;if(o==="Tab"){B();return}if(["ArrowDown","ArrowUp","ArrowRight","ArrowLeft","Home","End","Enter"," ","Spacebar","Escape"].includes(o))switch(t.preventDefault(),o){case"ArrowDown":case"ArrowRight":Pe(1);break;case"ArrowUp":case"ArrowLeft":Pe(-1);break;case"Home":Y(te(-1,1));break;case"End":Y(te(c.length,-1));break;case"Enter":case" ":case"Spacebar":{const h=I.value;if(h>-1){const d=c[h];d.disabled||$e(d)}break}case"Escape":B();break}}async function $e(t){t.disabled||(B(),await t.action())}function be(t){return typeof t.title=="string"&&t.title.trim()?t.title:Array.isArray(t.title)&&t.title.length&&String(t.title[0]).trim()?String(t.title[0]):"Untitled"}function ht(t){return g.value[t.id]||be(t)}function Se(t,o){return n.defineComponent({name:o,setup(c,{attrs:m,slots:h}){const d=n.ref(),A=n.getCurrentInstance();if(A?.proxy){const W=A.proxy;Object.entries({routeTabTitle:()=>d.value?.routeTabTitle,routeTabIcon:()=>d.value?.routeTabIcon,routeTabClosable:()=>d.value?.routeTabClosable,routeTabMeta:()=>d.value?.routeTabMeta,$:()=>d.value}).forEach(([ne,he])=>{Object.defineProperty(W,ne,{get:he,configurable:!0})})}return()=>n.h(t,{...m,ref:d},h)}})}const H=new Map,me=n.ref(0);function yt(t,o,c){H.has(c)||(H.set(c,o),me.value++),t&&_(t,c)}function Tt(t,o){return t&&((!t.name||t.name!==o)&&(t.name=o),t)}function kt(t,o){if(!t)return t;const c=H.get(o);if(c)return c;const m=Se(t,o);return H.set(o,m),me.value++,m}function vt(t){const o=i.getRouteKey(t),c=s.currentRoute.value,m=i.getRouteKey(c);return o===m}function wt(t){const o=i.getRouteKey(t),c=i.tabs.find(d=>d.id===o);if(!c)return`${o}::0`;const m=c.renderKey??0;return`${o}::${m}`}function pe(t){return!(t.closable===!1||i.options.keepLastTab&&i.tabs.length<=1)}async function Ct(t){await i.closeTab(t.id)}function Rt(t,o){o?z.set(t,o):z.delete(t)}function ge(t){n.nextTick(()=>{const o=z.get(t),c=U.value;if(o&&c){const m=o.getBoundingClientRect(),h=c.getBoundingClientRect();(m.left<h.left||m.right>h.right)&&o.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"})}})}function Et(t){if(t.href&&typeof window<"u"){t.target&&t.target!=="_self"?window.open(t.href,t.target):window.location.assign(t.href);return}i.activeId.value!==t.id&&(i.openTab(t.to,!1),ge(t.id))}function Bt(t){return["router-tab__item",{"is-active":i.activeId.value===t.id,"is-closable":pe(t),"is-dragging":R.dragging&&R.dragTab?.id===t.id,"is-drag-over":R.dropIndex===u(t.id)},t.tabClass]}function Kt(t){const o=i.getRouteKey(t),c=i.tabs.find(m=>m.id===o);return c?c.alive:!1}function Pt(t){const o=i.getRouteKey(t);return!!i.tabs.find(m=>m.id===o)}function $t(t,o,c){e.sortable&&(R.dragging=!0,R.dragIndex=o,R.dragTab=t,c.dataTransfer&&(c.dataTransfer.effectAllowed="move",c.dataTransfer.setData("text/plain",t.id)),a("tab-sort",{tab:t,index:o}))}function St(t,o){!e.sortable||!R.dragging||(o.preventDefault(),o.dataTransfer&&(o.dataTransfer.dropEffect="move"))}function At(t){!e.sortable||!R.dragging||(R.dropIndex=t)}function It(){!e.sortable||R.dragging}function xt(t,o){if(!(!e.sortable||!R.dragging)){if(o.preventDefault(),R.dragIndex!==-1&&R.dragIndex!==t){const c=i.tabs.splice(R.dragIndex,1)[0];i.tabs.splice(t,0,c),a("tab-sorted",{tab:c,fromIndex:R.dragIndex,toIndex:t})}Ae()}}function Ae(){R.dragging=!1,R.dragIndex=-1,R.dropIndex=-1,R.dragTab=null}n.onMounted(()=>{document.addEventListener("keydown",B)}),n.onBeforeUnmount(()=>{document.removeEventListener("keydown",B),r.appContext.config.globalProperties.$tabs=null,$.forEach(t=>{t.forEach(o=>{try{o()}catch(c){console.error("[RouterTab] Error during cleanup:",c)}})}),$.clear(),S.clear()}),n.watch(()=>e.keepAlive,t=>{i.options.keepAlive=t}),n.watch(()=>i.activeId.value,t=>{t&&ge(t),B()}),n.watch(()=>i.tabs.length,()=>{const t=new Set(i.tabs.map(c=>c.id));Array.from(S.keys()).forEach(c=>{t.has(c)||M(c)})}),n.watch(()=>e.contextmenu,t=>{t||B()}),n.watch(()=>F.value.length,t=>{C.visible&&t===0&&B()},{flush:"post"}),n.watch(F,t=>{if(!C.visible)return;V.value=new Array(t.length).fill(null);const o=te(-1,1,t);Y(o)},{flush:"post"}),n.watch(()=>C.visible,t=>{t||(I.value=-1,V.value=[])});const Dt=i.includeKeys;return{controller:i,tabs:i.tabs,includeKeys:Dt,persistenceHydrating:L,componentCache:H,componentCacheTrigger:me,cacheCurrentComponent:yt,tabTransitionProps:ue,pageTransitionProps:de,buildTabClass:Bt,activate:Et,close:Ct,context:C,menuItems:F,handleMenuAction:$e,showContextMenu:dt,hideContextMenu:B,getTabTitle:be,isClosable:pe,isTabCached:Kt,isTabReady:Pt,hasCustomSlot:p,hasStartSlot:w,hasEndSlot:l,onDragStart:$t,onDragOver:St,onDragEnter:At,onDragLeave:It,onDrop:xt,onDragEnd:Ae,setupComponentWatching:D,cleanupComponentWatching:M,handleComponentRef:_,getReactiveTabTitle:ht,getComponentCacheKey:wt,createNamedComponent:Se,ensureNamedComponent:Tt,getNamedComponent:kt,shouldRenderRoute:vt,triggerTabUpdate:v,menuRef:ee,highlightedIndex:I,setMenuItemRef:mt,onMenuKeydown:gt,highlightMenuIndex:Y,scrollContainer:U,setTabRef:Rt,scrollTabIntoView:ge}}}),Fe=(e,a)=>{const r=e.__vccOpts||e;for(const[s,i]of a)r[s]=i;return r},Ye={class:"router-tab"},He={class:"router-tab__header"},We={class:"router-tab__scroll",ref:"scrollContainer"},Je=["data-title","draggable","onClick","onAuxclick","onContextmenu","onDragstart","onDragover","onDragenter","onDrop"],qe=["title"],Ge=["onClick"],Xe={class:"router-tab__container"},Qe={key:1,class:"router-tab__hydrating","aria-hidden":"true"},Ze=["aria-disabled","disabled","tabindex","onMouseenter","onClick"];function et(e,a,r,s,i,p){const w=n.resolveComponent("RouterView");return n.openBlock(),n.createElementBlock("div",Ye,[n.createElementVNode("header",He,[n.createElementVNode("div",{class:n.normalizeClass(["router-tab__slot-start",{"has-content":e.hasStartSlot}])},[n.renderSlot(e.$slots,"start")],2),n.createElementVNode("div",We,[n.createVNode(n.TransitionGroup,n.mergeProps({tag:"ul",class:"router-tab__nav"},e.tabTransitionProps),{default:n.withCtx(()=>[(n.openBlock(!0),n.createElementBlock(n.Fragment,null,n.renderList(e.tabs,(l,y)=>(n.openBlock(),n.createElementBlock("li",{key:l.id,class:n.normalizeClass(e.buildTabClass(l)),"data-title":e.getTabTitle(l),draggable:e.sortable,ref_for:!0,ref:g=>e.setTabRef(l.id,g),onClick:g=>e.activate(l),onAuxclick:n.withModifiers(g=>e.close(l),["middle","prevent"]),onContextmenu:n.withModifiers(g=>e.showContextMenu(l,g),["prevent"]),onDragstart:g=>e.onDragStart(l,y,g),onDragover:g=>e.onDragOver(y,g),onDragenter:g=>e.onDragEnter(y),onDragleave:a[0]||(a[0]=(...g)=>e.onDragLeave&&e.onDragLeave(...g)),onDrop:g=>e.onDrop(y,g),onDragend:a[1]||(a[1]=(...g)=>e.onDragEnd&&e.onDragEnd(...g))},[l.icon?(n.openBlock(),n.createElementBlock("i",{key:0,class:n.normalizeClass(["router-tab__item-icon",l.icon])},null,2)):n.createCommentVNode("",!0),n.createElementVNode("span",{class:"router-tab__item-title",title:e.getReactiveTabTitle(l)},n.toDisplayString(e.getReactiveTabTitle(l)),9,qe),e.isClosable(l)?(n.openBlock(),n.createElementBlock("a",{key:1,class:"router-tab__item-close",onClick:n.withModifiers(g=>e.close(l),["stop"])},null,8,Ge)):n.createCommentVNode("",!0)],42,Je))),128))]),_:1},16)],512),n.createElementVNode("div",{class:n.normalizeClass(["router-tab__slot-end",{"has-content":e.hasEndSlot}])},[n.renderSlot(e.$slots,"end")],2)]),n.createElementVNode("div",Xe,[e.persistenceHydrating?(n.openBlock(),n.createElementBlock("div",Qe)):(n.openBlock(),n.createBlock(w,{key:0},{default:n.withCtx(({Component:l,route:y})=>[e.hasCustomSlot?n.renderSlot(e.$slots,"default",n.normalizeProps(n.mergeProps({key:0},{Component:l,route:y,controller:e.controller,pageRef:g=>e.handleComponentRef(g,e.controller.getRouteKey(y))}))):(n.openBlock(),n.createElementBlock(n.Fragment,{key:1},[e.controller.options.keepAlive?(n.openBlock(),n.createBlock(n.KeepAlive,{key:0,include:e.includeKeys},[l?(n.openBlock(),n.createBlock(n.resolveDynamicComponent(e.getNamedComponent(l,e.getComponentCacheKey(y))),{key:e.getComponentCacheKey(y),ref:g=>e.handleComponentRef(g,e.controller.getRouteKey(y)),class:"router-tab-page"})):n.createCommentVNode("",!0)],1032,["include"])):(n.openBlock(),n.createBlock(n.Transition,n.mergeProps({key:1},e.pageTransitionProps,{appear:""}),{default:n.withCtx(()=>[l?(n.openBlock(),n.createBlock(n.resolveDynamicComponent(l),{key:e.controller.getRouteKey(y),ref:g=>e.handleComponentRef(g,e.controller.getRouteKey(y)),class:"router-tab-page"})):n.createCommentVNode("",!0)]),_:2},1040))],64))]),_:3}))]),n.withDirectives(n.createElementVNode("div",{ref:"menuRef",class:"router-tab__contextmenu",role:"menu",onKeydown:a[2]||(a[2]=(...l)=>e.onMenuKeydown&&e.onMenuKeydown(...l)),style:n.normalizeStyle({left:e.context.position.x+"px",top:e.context.position.y+"px"})},[(n.openBlock(!0),n.createElementBlock(n.Fragment,null,n.renderList(e.menuItems,(l,y)=>(n.openBlock(),n.createElementBlock("a",{key:l.id,role:"menuitem",class:n.normalizeClass(["router-tab__contextmenu-item",{"is-focused":y===e.highlightedIndex}]),"aria-disabled":l.disabled,disabled:l.disabled,tabindex:l.disabled?-1:y===e.highlightedIndex?0:-1,ref_for:!0,ref:g=>e.setMenuItemRef(g,y),onMouseenter:g=>!l.disabled&&e.highlightMenuIndex(y),onClick:g=>e.handleMenuAction(l)},n.toDisplayString(l.label),43,Ze))),128))],36),[[n.vShow,e.context.visible&&e.context.target]])])}const se=Fe(ze,[["render",et]]),tt={class:"router-tabs","aria-hidden":"true"},X=n.defineComponent({name:"RouterTabs",__name:"RouterTabs",props:{cookieKey:{},expiresInDays:{},path:{},domain:{},secure:{type:Boolean},sameSite:{},serialize:{type:Function},deserialize:{type:Function},fallbackRoute:{}},setup(e){return le(e),(r,s)=>(n.openBlock(),n.createElementBlock("span",tt))}}),we="tab-theme-style",Ce="tab-theme-primary-color",nt="system",Re="(prefers-color-scheme: dark)";let j=null;const P={primary:"#034960",background:"#ffffff",text:"#1e293b",border:"#e2e8f0",activeBackground:"#034960",activeText:"#ffffff",activeBorder:"#034960",headerBackground:"#ffffff",buttonBackground:"#f8fafc",buttonColor:"#034960",activeButtonBackground:"#034960",activeButtonColor:"#ffffff",iconColor:"#475569"},ot={primary:"#38bdf8",background:"#0f172a",text:"#f1f5f9",border:"#334155",activeBackground:"#1e293b",activeText:"#38bdf8",activeBorder:"#38bdf8",headerBackground:"#0c4a6e",buttonBackground:"#1e293b",buttonColor:"#f1f5f9",activeButtonBackground:"#38bdf8",activeButtonColor:"#0f172a",iconColor:"#cbd5e1"};function rt(e){if(typeof window>"u")return null;const a=window.localStorage.getItem(e);if(!a)return null;try{const r=JSON.parse(a);return r&&typeof r=="object"?r:null}catch{return null}}function ce(e){typeof document>"u"||(document.documentElement.style.setProperty("--router-tab-primary",e.primary??P.primary),document.documentElement.style.setProperty("--router-tab-header-bg",e.headerBackground??P.headerBackground),document.documentElement.style.setProperty("--router-tab-background",e.background??P.background),document.documentElement.style.setProperty("--router-tab-active-background",e.activeBackground??P.activeBackground),document.documentElement.style.setProperty("--router-tab-text",e.text??P.text),document.documentElement.style.setProperty("--router-tab-active-text",e.activeText??P.activeText),document.documentElement.style.setProperty("--router-tab-border",e.border??P.border),document.documentElement.style.setProperty("--router-tab-active-border",e.activeBorder??P.activeBorder),document.documentElement.style.setProperty("--router-tab-button-color",e.buttonColor??P.buttonColor),document.documentElement.style.setProperty("--router-tab-active-button-color",e.activeButtonColor??P.activeButtonColor),document.documentElement.style.setProperty("--router-tab-button-background",e.buttonBackground??P.buttonBackground),document.documentElement.style.setProperty("--router-tab-active-button-background",e.activeButtonBackground??P.activeButtonBackground),document.documentElement.style.setProperty("--router-tab-icon-color",e.iconColor??P.iconColor))}function Ee(e){if(typeof document>"u")return;const a=document.documentElement,r=window.matchMedia(Re),s=()=>{a.dataset.theme=r.matches?"dark":"light"};j&&(r.removeEventListener("change",j),j=null),e==="system"?(s(),j=()=>s(),r.addEventListener("change",j)):a.dataset.theme=e}function Be(e={}){if(typeof window>"u")return;const{styleKey:a=we,primaryKey:r=Ce,defaultStyle:s=nt,defaultPrimary:i}=e,p=window.localStorage.getItem(a)??s;Ee(p);const l=p==="dark"||p==="system"&&window.matchMedia(Re).matches?{...ot}:{...P};i&&(l.primary=i);const y=rt(r);ce(y?{...l,...y}:l)}function at(e,a){if(typeof window>"u")return;const r=a?.styleKey??we;window.localStorage.setItem(r,e),Ee(e)}function it(e,a){if(typeof window>"u")return;const r=a?.primaryKey??Ce;window.localStorage.setItem(r,JSON.stringify(e)),ce(e)}function Q(e,a){if(n.isRef(e)){const s=!n.isReadonly(e);return{value:e,update:s?i=>{e.value=i}:()=>{}}}if(typeof e=="function"){const s=e;return{value:n.computed(s),update:()=>{}}}const r=n.ref(e===void 0?a:e);return{value:r,update:s=>{r.value=s}}}function Z(e={}){const a=Q(e.title,"Untitled"),r=Q(e.icon,""),s=Q(e.closable,!0),i=Q(e.meta,{});return{routeTabTitle:a.value,routeTabIcon:r.value,routeTabClosable:s.value,routeTabMeta:i.value,updateTitle:a.update,updateIcon:r.update,updateClosable:s.update,updateMeta:i.update}}function lt(e,a="Page"){return Z({title:n.computed(()=>e.value?"Loading...":a),icon:n.computed(()=>e.value?"mdi-loading mdi-spin":"mdi-page"),closable:n.computed(()=>!e.value)})}function st(e,a="Page",r="mdi-page"){return Z({title:n.computed(()=>e.value>0?`${a} (${e.value})`:a),icon:n.computed(()=>e.value>0?"mdi-bell-badge":r)})}function ct(e,a="Page"){const r={normal:{suffix:"",icon:"mdi-page"},loading:{suffix:" - Loading",icon:"mdi-loading mdi-spin"},error:{suffix:" - Error",icon:"mdi-alert"},success:{suffix:" - Success",icon:"mdi-check-circle"}};return Z({title:n.computed(()=>a+r[e.value].suffix),icon:n.computed(()=>r[e.value].icon),closable:n.computed(()=>e.value!=="loading")})}let Ke=!1;const ut={install(e,a){if(Ke)return;Ke=!0;const{initTheme:r=!0,themeOptions:s,componentName:i=se.name||"RouterTab",tabsComponentName:p=X.name||"RouterTabs"}=a??{};r&&Be(s??{}),e.component(i,se),e.component(p,X),p.toLowerCase()!=="router-tabs"&&e.component("router-tabs",X),Object.defineProperty(e.config.globalProperties,"$tabs",{configurable:!0,enumerable:!1,get(){return e._context.provides[O]},set(w){w&&e.provide(O,w)}})}};E.RouterTab=se,E.RouterTabs=X,E.default=ut,E.initRouterTabsTheme=Be,E.routerTabsKey=O,E.setRouterTabsPrimary=it,E.setRouterTabsTheme=at,E.useLoadingTab=lt,E.useNotificationTab=st,E.useReactiveTab=Z,E.useRouterTabs=ie,E.useRouterTabsPersistence=le,E.useStatusTab=ct,Object.defineProperties(E,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
@@ -70,7 +70,7 @@
70
70
  <component
71
71
  v-if="Component"
72
72
  :is="getNamedComponent(Component, getComponentCacheKey(route))"
73
- :key="isRefreshing(route) ? getRefreshComponentKey(route) : getComponentCacheKey(route)"
73
+ :key="getComponentCacheKey(route)"
74
74
  :ref="(el: any) => handleComponentRef(el, controller.getRouteKey(route))"
75
75
  class="router-tab-page"
76
76
  />
@@ -785,7 +785,29 @@ export default defineComponent({
785
785
  return defineComponent({
786
786
  name,
787
787
  setup(_, { attrs, slots }) {
788
- return () => h(component, attrs, slots)
788
+ const innerRef = ref<any>()
789
+
790
+ // Forward tab props to the wrapper proxy so handleComponentRef can see them
791
+ const instance = getCurrentInstance()
792
+ if (instance?.proxy) {
793
+ const proxy = instance.proxy as any
794
+ const forwardProps: Record<string, () => any> = {
795
+ routeTabTitle: () => innerRef.value?.routeTabTitle,
796
+ routeTabIcon: () => innerRef.value?.routeTabIcon,
797
+ routeTabClosable: () => innerRef.value?.routeTabClosable,
798
+ routeTabMeta: () => innerRef.value?.routeTabMeta,
799
+ $: () => innerRef.value
800
+ }
801
+
802
+ Object.entries(forwardProps).forEach(([key, getter]) => {
803
+ Object.defineProperty(proxy, key, {
804
+ get: getter,
805
+ configurable: true
806
+ })
807
+ })
808
+ }
809
+
810
+ return () => h(component, { ...attrs, ref: innerRef }, slots)
789
811
  }
790
812
  })
791
813
  }
@@ -866,36 +888,14 @@ export default defineComponent({
866
888
  const tab = controller.tabs.find(item => item.id === routeKey)
867
889
 
868
890
  if (!tab) {
869
- console.warn('[RouterTab] Tab not found for route:', routeKey)
870
891
  return `${routeKey}::0`
871
892
  }
872
893
 
873
894
  const renderKey = tab.renderKey ?? 0
874
895
  const cacheKey = `${routeKey}::${renderKey}`
875
-
876
- // Debug logging for specific routes
877
- if (routeKey.includes('students') || routeKey.includes('classroom') || routeKey.includes('quiz')) {
878
- console.log(`[getComponentCacheKey] Route: ${route.fullPath}`, {
879
- routeKey,
880
- renderKey,
881
- cacheKey,
882
- tabAlive: tab.alive,
883
- includeKeys: includeKeys.value,
884
- isIncluded: includeKeys.value.includes(cacheKey)
885
- })
886
- }
887
-
888
896
  return cacheKey
889
897
  }
890
898
 
891
- /**
892
- * Generates a special key for components in refreshing state.
893
- * Appends '::refresh' to ensure it's treated as separate from cached instance.
894
- */
895
- function getRefreshComponentKey(route: RouteLocationNormalizedLoaded): string {
896
- return `${getComponentCacheKey(route)}::refresh`
897
- }
898
-
899
899
  function isClosable(tab: TabRecord) {
900
900
  if (tab.closable === false) return false
901
901
  if (controller.options.keepLastTab && controller.tabs.length <= 1) return false
@@ -969,10 +969,6 @@ export default defineComponent({
969
969
  ]
970
970
  }
971
971
 
972
- function isRefreshing(route: RouteLocationNormalizedLoaded) {
973
- return controller.refreshingKey.value === controller.getRouteKey(route)
974
- }
975
-
976
972
  function isTabCached(route: RouteLocationNormalizedLoaded) {
977
973
  const routeKey = controller.getRouteKey(route)
978
974
  const tab = controller.tabs.find(tab => tab.id === routeKey)
@@ -1099,7 +1095,6 @@ export default defineComponent({
1099
1095
 
1100
1096
  instanceKeys.forEach(key => {
1101
1097
  if (!currentTabIds.has(key)) {
1102
- console.log(`[RouterTab] Cleaning up stale component instance: ${key}`)
1103
1098
  cleanupComponentWatching(key)
1104
1099
  }
1105
1100
  })
@@ -1162,7 +1157,6 @@ export default defineComponent({
1162
1157
  hideContextMenu,
1163
1158
  getTabTitle,
1164
1159
  isClosable,
1165
- isRefreshing,
1166
1160
  isTabCached,
1167
1161
  isTabReady,
1168
1162
  hasCustomSlot,
@@ -1179,7 +1173,6 @@ export default defineComponent({
1179
1173
  handleComponentRef,
1180
1174
  getReactiveTabTitle,
1181
1175
  getComponentCacheKey,
1182
- getRefreshComponentKey,
1183
1176
  createNamedComponent,
1184
1177
  ensureNamedComponent,
1185
1178
  getNamedComponent,
@@ -98,7 +98,9 @@ export function useRouterTabsPersistence(options: RouterTabsPersistenceOptions =
98
98
  } = options
99
99
 
100
100
  const controller = useRouterTabs({ optional: true })
101
- const hydrating = ref(false)
101
+ // Start as `true` so pages won't mount until hydration decides what to do.
102
+ // This prevents double-mount / double-fetch on initial load when restoring tabs.
103
+ const hydrating = ref(true)
102
104
 
103
105
  const setup = (ctrl: NonNullable<typeof controller>, mode: 'hook' | 'immediate' = 'hook') => {
104
106
  const run = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue3-router-tab",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",