vue3-router-tab 1.2.7 → 1.2.9
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/README.md +589 -78
- package/dist/vue3-router-tab.css +1 -1
- package/dist/vue3-router-tab.js +464 -448
- package/dist/vue3-router-tab.umd.cjs +1 -1
- package/lib/components/RouterTab.vue +15 -2
- package/lib/core/createRouterTabs.ts +19 -4
- package/lib/core/types.ts +3 -0
- package/lib/persistence.ts +2 -1
- package/lib/scss/index.scss +248 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(w,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):(w=typeof globalThis<"u"?globalThis:w||self,n(w["vue3-router-tab"]={},w.Vue,w.VueRouter))})(this,(function(w,n,Ce){"use strict";function Re(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 M(e,a){const o=e.resolve(a);if(!o||!o.matched.length)throw new Error(`[RouterTabs] Unable to resolve route: ${String(a)}`);return o}const Ee={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 $(e){const a=e.meta?.key;if(typeof a=="function"){const o=a(e);if(typeof o=="string"&&o.length)return o}else if(typeof a=="string"&&a.length){const o=Ee[a.toLowerCase()];return o?o(e):a}return e.fullPath}function G(e,a){const o=e.meta?.keepAlive;return typeof o=="boolean"?o:a}function X(e,a){const o=e.meta?.reuse;return typeof o=="boolean"?o:a}function se(e){const a=e.meta??{},o={};return"title"in a&&(o.title=a.title),"tips"in a&&(o.tips=a.tips),"icon"in a&&(o.icon=a.icon),"closable"in a&&(o.closable=a.closable),"tabClass"in a&&(o.tabClass=a.tabClass),"target"in a&&(o.target=a.target),"href"in a&&(o.href=a.href),o}function _(e,a,o){const s=se(e);return{id:$(e),to:e.fullPath,fullPath:e.fullPath,matched:e,alive:G(e,o),reusable:X(e,!1),closable:s.closable??!0,...s,...a}}function Q(e,a,o,s){if(!e.find(p=>p.id===a.id)){if(o==="next"&&s){const p=e.findIndex(k=>k.id===s);if(p!==-1){e.splice(p+1,0,a);return}}e.push(a)}}function ce(e,a,o){if(!a||a<=0)return;const s=e.filter(r=>r.alive);for(;s.length>a;){const r=s.shift();if(!r||r.id===o)continue;const p=e.findIndex(k=>k.id===r.id);p>-1&&(e[p].alive=!1)}}function Pe(e){return{to:e.to,title:e.title,tips:e.tips,icon:e.icon,tabClass:e.tabClass,closable:e.closable}}function Be(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),a}function Ae(e,a={}){const o=Re(a),s=n.reactive([]),r=n.ref(null),p=n.shallowRef(),k=n.ref(null),c=n.computed(()=>s.filter(l=>l.alive).map(l=>l.id));let d=!1;function g(l){const b=typeof l.matched=="object"?l:M(e,l);return{key:$(b),fullPath:b.fullPath,alive:G(b,o.keepAlive),reusable:X(b,!1),matched:b}}function R(l){const b=$(l);let m=s.find(v=>v.id===b);return m?(m.fullPath=l.fullPath,m.to=l.fullPath,m.matched=l,m.alive=G(l,o.keepAlive),m.reusable=X(l,m.reusable),Object.assign(m,se(l)),m):(m=_(l,{},o.keepAlive),Q(s,m,o.appendPosition,r.value),ce(s,o.maxAlive,r.value),m)}async function I(l,b=!1,m=!0){const v=M(e,l),E=$(v),P=r.value===E;m==="sameTab"&&(m=P),m&&await K(E,!0),await e[b?"replace":"push"](v),P&&await T()}function x(l){const b=s.findIndex(A=>A.id===l);if(b===-1)return o.defaultRoute;const m=s[b+1],v=s[b-1],E=s.find(A=>A.id!==l),P=m||v||E;return P?P.to:o.defaultRoute}async function j(l=r.value,b={}){if(!l)return;if(!b.force&&o.keepLastTab&&s.length===1)throw new Error("[RouterTabs] Unable to close the final tab when keepLastTab is true.");const v=r.value===l&&b.redirect!==null,E=v?b.redirect??x(l):null;await O(l,{force:b.force}),b.redirect!==null&&v&&E&&await e.replace(E)}async function O(l,b={}){const m=s.findIndex(v=>v.id===l);m!==-1&&(s.splice(m,1),k.value===l&&(k.value=null),r.value===l&&(r.value=null,p.value=void 0))}async function K(l=r.value??void 0,b=!1){if(!l)return;const m=s.find(v=>v.id===l);m&&(o.keepAlive&&m.alive&&(m.alive=!1,await n.nextTick(),m.alive=!0,await n.nextTick()),k.value=l,await n.nextTick(),b||await n.nextTick(),k.value=null)}async function oe(l=!1){for(const b of s)await K(b.id,l)}async function ae(l=o.defaultRoute){s.splice(0,s.length),r.value=null,p.value=void 0;for(const b of o.initialTabs){const m=M(e,b.to),v=_(m,b,o.keepAlive);s.push(v)}await e.replace(l)}async function T(){const l=r.value;l&&await K(l,!0)}function W(l){return typeof l.matched=="object"?$(l):$(M(e,l))}function D(){const l=s.find(b=>b.id===r.value);return{tabs:s.map(Pe),active:l?l.to:null}}async function S(l){d=!0,s.splice(0,s.length),r.value=null,p.value=void 0;const b=l?.tabs??[];for(const v of b)try{const E=M(e,v.to),P=Be(v),A=_(E,P,o.keepAlive);Q(s,A,"last",null)}catch{}d=!1;const m=l?.active??b[b.length-1]?.to??o.defaultRoute;if(m)try{await e.replace(m)}catch{}}return n.watch(()=>e.currentRoute.value,l=>{if(d)return;const b=R(l);r.value=b.id,p.value=b,ce(s,o.maxAlive,r.value)},{immediate:!0}),o.initialTabs.length&&o.initialTabs.forEach(l=>{const b=M(e,l.to),m=_(b,l,o.keepAlive);Q(s,m,"last",null)}),{options:o,tabs:s,activeId:r,current:p,includeKeys:c,refreshingKey:k,openTab:I,closeTab:j,removeTab:O,refreshTab:K,refreshAll:oe,reset:ae,reload:T,getRouteKey:W,matchRoute:g,snapshot:D,hydrate:S}}function ue(e){return e?typeof e=="string"?{name:e}:e:{}}const V=Symbol("RouterTabsContext"),Y="router-tabs:snapshot";function Z(e={}){const{optional:a=!1}=e,o=n.inject(V,null);if(o)return o;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 Ie=864e5;function Se(e){if(typeof document>"u")return null;const a=`${encodeURIComponent(e)}=`,o=document.cookie?document.cookie.split("; "):[];for(const s of o)if(s.startsWith(a))return decodeURIComponent(s.slice(a.length));return null}function de(e,a,o){if(typeof document>"u")return;const{expiresInDays:s=7,path:r="/",domain:p,secure:k,sameSite:c="lax"}=o,d=[`${encodeURIComponent(e)}=${encodeURIComponent(a)}`];if(s!==1/0){const g=new Date(Date.now()+s*Ie).toUTCString();d.push(`Expires=${g}`)}r&&d.push(`Path=${r}`),p&&d.push(`Domain=${p}`),k&&d.push("Secure"),c&&d.push(`SameSite=${c.charAt(0).toUpperCase()}${c.slice(1)}`),document.cookie=d.join("; ")}function fe(e,a){if(typeof document>"u")return;const{path:o="/",domain:s}=a,r=[`${encodeURIComponent(e)}=`];r.push("Expires=Thu, 01 Jan 1970 00:00:01 GMT"),o&&r.push(`Path=${o}`),s&&r.push(`Domain=${s}`),document.cookie=r.join("; ")}const xe=e=>JSON.stringify(e??null),De=e=>{if(!e)return null;try{return JSON.parse(e)}catch{return null}};function ee(e={}){const{cookieKey:a=Y,serialize:o=xe,deserialize:s=De}=e,r=Z({optional:!0}),p=n.ref(!0),k=c=>{n.onMounted(async()=>{const d=s(Se(a));if(d&&d.tabs?.length)try{if(p.value=!0,await c.hydrate(d),d.active){await n.nextTick();const R=c.tabs.find(I=>I.to===d.active);R&&(c.activeId.value=R.id,c.current.value=R)}}finally{p.value=!1}else if(Object.prototype.hasOwnProperty.call(e,"fallbackRoute"))try{p.value=!0;const R=e.fallbackRoute??c.options.defaultRoute;await c.reset(R)}finally{p.value=!1}else p.value=!1;const g=c.snapshot();g.tabs.length?de(a,o(g),e):fe(a,e),p.value=!1}),n.watch(()=>({tabs:c.tabs.map(d=>({to:d.to,title:d.title,tips:d.tips,icon:d.icon,tabClass:d.tabClass,closable:d.closable})),active:c.activeId.value}),()=>{if(p.value)return;const d=c.snapshot();d.tabs.length?de(a,o(d),e):fe(a,e)},{deep:!0})};r?k(r):n.onMounted(()=>{const c=Z({optional:!0});c&&k(c)})}const Me=n.defineComponent({name:"RouterTab",components:{RouterView:Ce.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:Y},persistence:{type:Object,default:null},sortable:{type:Boolean,default:!0}},emits:["tab-sort","tab-sorted"],setup(e,{emit:a}){const o=n.getCurrentInstance();if(!o)throw new Error("[RouterTab] component must be used within a Vue application context.");const s=o.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 r=Ae(s,{initialTabs:e.tabs,keepAlive:e.keepAlive,maxAlive:e.maxAlive,keepLastTab:e.keepLastTab,appendPosition:e.append,defaultRoute:e.defaultPage});n.provide(V,r),o.appContext.config.globalProperties.$tabs=r;const p=n.computed(()=>!!o?.slots?.default),k=n.computed(()=>!!o?.slots?.start),c=n.computed(()=>!!o?.slots?.end),d=n.ref(0),g=n.computed(()=>{d.value;const t={};return r.tabs.forEach(i=>{const f=typeof i.title=="string"?i.title:String(i.title||ie(i));t[i.id]=f}),t});function R(){d.value++}const I=new Map,x=new Map;function j(t,i){if(!i||I.has(t))return;I.set(t,i);const f=r.tabs.find(y=>r.getRouteKey(y.to)===t);if(!f)return;const h=[];if(i.routeTabTitle!==void 0){const y=n.watch(()=>{const u=i.routeTabTitle;return u&&typeof u=="object"&&"value"in u?u.value:u},u=>{if(u!=null){const L=String(u);f.title=L,R()}},{immediate:!0});h.push(y)}if(i.routeTabIcon!==void 0){const y=n.watch(()=>{const u=i.routeTabIcon;return u&&typeof u=="object"&&"value"in u?u.value:u},u=>{u!=null&&(f.icon=String(u),R())},{immediate:!0});h.push(y)}if(i.routeTabClosable!==void 0){const y=n.watch(()=>{const u=i.routeTabClosable;return u&&typeof u=="object"&&"value"in u?u.value:u},u=>{u!=null&&(f.closable=!!u,R())},{immediate:!0});h.push(y)}if(i.routeTabMeta!==void 0){const y=n.watch(()=>{const u=i.routeTabMeta;return u&&typeof u=="object"&&"value"in u?u.value:u},u=>{u&&typeof u=="object"&&(Object.assign(f,u),R())},{immediate:!0,deep:!0});h.push(y)}x.set(t,h)}function O(t){const i=x.get(t);i&&(i.forEach(f=>f()),x.delete(t)),I.delete(t)}function K(t,i){t?t.routeTabTitle!==void 0||t.routeTabIcon!==void 0||t.routeTabClosable!==void 0?j(i,t):t.$&&(t.$.routeTabTitle!==void 0||t.$.routeTabIcon!==void 0||t.$.routeTabClosable!==void 0)&&j(i,t.$):t===null&&O(i)}if(e.cookieKey!==null||e.persistence){const t={...e.persistence??{}};e.cookieKey!==null?t.cookieKey=e.cookieKey||Y:t.cookieKey||(t.cookieKey=Y),ee(t)}const oe=n.computed(()=>ue(e.tabTransition)),ae=n.computed(()=>ue(e.pageTransition)),T=n.reactive({visible:!1,target:null,position:{x:0,y:0}}),W=n.ref(null),D=n.ref([]),S=n.ref(-1),l=n.reactive({dragging:!1,dragIndex:-1,dropIndex:-1,dragTab:null}),b=["refresh","refreshAll","close","closeLefts","closeRights","closeOthers"];function m(t){return r.tabs.findIndex(i=>i.id===t)}function v(t){const i=m(t.id);return i>0?r.tabs.slice(0,i):[]}function E(t){const i=m(t.id);return i>-1?r.tabs.slice(i+1):[]}function P(t){return r.tabs.filter(i=>i.id!==t.id)}async function A(t,i){const f=t.filter(h=>h.closable!==!1);if(f.length){for(const h of f)r.activeId.value===h.id?await r.closeTab(h.id,{redirect:i.to,force:!0}):await r.removeTab(h.id,{force:!0});r.activeId.value!==i.id&&await r.openTab(i.to,!0,!1)}}const et={refresh:{label:"Refresh",handler:async({target:t})=>{await r.refreshTab(t.id,!0)}},refreshAll:{label:"Refresh All",handler:async()=>{await r.refreshAll(!0)}},close:{label:"Close",handler:async({target:t})=>{await r.closeTab(t.id)},enable:({target:t})=>re(t)},closeLefts:{label:"Close to the Left",handler:async({target:t})=>{await A(v(t),t)},enable:({target:t})=>v(t).some(i=>i.closable!==!1)},closeRights:{label:"Close to the Right",handler:async({target:t})=>{await A(E(t),t)},enable:({target:t})=>E(t).some(i=>i.closable!==!1)},closeOthers:{label:"Close Others",handler:async({target:t})=>{await A(P(t),t)},enable:({target:t})=>P(t).some(i=>i.closable!==!1)}};function B(){T.visible=!1,T.target=null,S.value=-1,D.value=[]}function tt(t,i){e.contextmenu&&(T.visible=!0,T.target=t,T.position.x=i.clientX,T.position.y=i.clientY,document.addEventListener("click",B,{once:!0}),n.nextTick(()=>{ot()}))}function nt(t,i){const f=typeof t=="string"?{id:t}:t,h=et[f.id],y=f.label??h?.label??String(f.id),u=f.visible??h?.visible??!0;if(!(typeof u=="function"?u(i):u!==!1))return null;const le=f.enable??h?.enable??!0,yt=typeof le=="function"?le(i):le!==!1,we=f.handler??h?.handler;if(!we)return null;const Tt=async()=>{await Promise.resolve(we(i))};return{id:String(f.id),label:y,disabled:!yt,action:Tt}}const U=n.computed(()=>{if(!T.visible||!T.target||e.contextmenu===!1)return[];const t=Array.isArray(e.contextmenu)?e.contextmenu:b,i={target:T.target,controller:r};return t.map(f=>nt(f,i)).filter(f=>!!f)});function ot(){const t=W.value;if(!t)return;const i=8,{innerWidth:f,innerHeight:h}=window,y=t.getBoundingClientRect();let u=T.position.x,L=T.position.y;y.right>f-i&&(u=Math.max(i,f-y.width-i)),y.bottom>h-i&&(L=Math.max(i,h-y.height-i)),(u!==T.position.x||L!==T.position.y)&&(T.position.x=u,T.position.y=L)}function at(t,i){D.value[i]=t??null}function it(t){if(t<0)return;D.value[t]?.focus({preventScroll:!0})}function q(t,i,f=U.value){if(!f.length)return-1;const h=f.length;let y=t;for(let u=0;u<h;u++)if(y=(y+i+h)%h,!f[y].disabled)return y;return-1}function z(t){S.value=t,!(t<0)&&n.nextTick(()=>it(t))}function Te(t){const i=q(S.value,t);i!==-1&&z(i)}function rt(t){if(!T.visible)return;const i=t.key,f=U.value;if(!f.length)return;if(i==="Tab"){B();return}if(["ArrowDown","ArrowUp","ArrowRight","ArrowLeft","Home","End","Enter"," ","Spacebar","Escape"].includes(i))switch(t.preventDefault(),i){case"ArrowDown":case"ArrowRight":Te(1);break;case"ArrowUp":case"ArrowLeft":Te(-1);break;case"Home":z(q(-1,1));break;case"End":z(q(f.length,-1));break;case"Enter":case" ":case"Spacebar":{const y=S.value;if(y>-1){const u=f[y];u.disabled||ke(u)}break}case"Escape":B();break}}async function ke(t){t.disabled||(B(),await t.action())}function ie(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 lt(t){return g.value[t.id]||ie(t)}function re(t){return!(t.closable===!1||r.options.keepLastTab&&r.tabs.length<=1)}async function st(t){await r.closeTab(t.id)}function ct(t){if(t.href&&typeof window<"u"){t.target&&t.target!=="_self"?window.open(t.href,t.target):window.location.assign(t.href);return}r.activeId.value!==t.id&&r.openTab(t.to,!1)}function ut(t){return["router-tab__item",{"is-active":r.activeId.value===t.id,"is-closable":re(t),"is-dragging":l.dragging&&l.dragTab?.id===t.id,"is-drag-over":l.dropIndex===m(t.id)},t.tabClass]}function dt(t){return r.refreshingKey.value===r.getRouteKey(t)}function ft(t,i,f){e.sortable&&(l.dragging=!0,l.dragIndex=i,l.dragTab=t,f.dataTransfer&&(f.dataTransfer.effectAllowed="move",f.dataTransfer.setData("text/plain",t.id)),a("tab-sort",{tab:t,index:i}))}function bt(t,i){!e.sortable||!l.dragging||(i.preventDefault(),i.dataTransfer&&(i.dataTransfer.dropEffect="move"))}function mt(t){!e.sortable||!l.dragging||(l.dropIndex=t)}function pt(){!e.sortable||l.dragging}function gt(t,i){if(!(!e.sortable||!l.dragging)){if(i.preventDefault(),l.dragIndex!==-1&&l.dragIndex!==t){const f=r.tabs.splice(l.dragIndex,1)[0];r.tabs.splice(t,0,f),a("tab-sorted",{tab:f,fromIndex:l.dragIndex,toIndex:t})}ve()}}function ve(){l.dragging=!1,l.dragIndex=-1,l.dropIndex=-1,l.dragTab=null}n.onMounted(()=>{document.addEventListener("keydown",B)}),n.onBeforeUnmount(()=>{document.removeEventListener("keydown",B),o.appContext.config.globalProperties.$tabs=null,x.forEach(t=>{t.forEach(i=>i())}),x.clear(),I.clear()}),n.watch(()=>e.keepAlive,t=>{r.options.keepAlive=t}),n.watch(()=>r.activeId.value,()=>B()),n.watch(()=>e.contextmenu,t=>{t||B()}),n.watch(()=>U.value.length,t=>{T.visible&&t===0&&B()}),n.watch(U,t=>{if(D.value=new Array(t.length).fill(null),!T.visible)return;const i=q(-1,1,t);z(i)}),n.watch(()=>T.visible,t=>{t||(S.value=-1,D.value=[])});const ht=r.includeKeys;return{controller:r,tabs:r.tabs,includeKeys:ht,tabTransitionProps:oe,pageTransitionProps:ae,buildTabClass:ut,activate:ct,close:st,context:T,menuItems:U,handleMenuAction:ke,showContextMenu:tt,hideContextMenu:B,getTabTitle:ie,isClosable:re,isRefreshing:dt,hasCustomSlot:p,hasStartSlot:k,hasEndSlot:c,onDragStart:ft,onDragOver:bt,onDragEnter:mt,onDragLeave:pt,onDrop:gt,onDragEnd:ve,setupComponentWatching:j,cleanupComponentWatching:O,handleComponentRef:K,getReactiveTabTitle:lt,triggerTabUpdate:R,menuRef:W,highlightedIndex:S,setMenuItemRef:at,onMenuKeydown:rt,highlightMenuIndex:z}}}),$e=(e,a)=>{const o=e.__vccOpts||e;for(const[s,r]of a)o[s]=r;return o},Ke={class:"router-tab"},Le={class:"router-tab__header"},Ve={class:"router-tab__scroll"},Ne=["data-title","draggable","onClick","onAuxclick","onContextmenu","onDragstart","onDragover","onDragenter","onDrop"],je=["title"],Oe=["onClick"],Ue={class:"router-tab__container"},ze=["aria-disabled","disabled","tabindex","onMouseenter","onClick"];function _e(e,a,o,s,r,p){const k=n.resolveComponent("RouterView");return n.openBlock(),n.createElementBlock("div",Ke,[n.createElementVNode("header",Le,[n.createElementVNode("div",{class:n.normalizeClass(["router-tab__slot-start",{"has-content":e.hasStartSlot}])},[n.renderSlot(e.$slots,"start")],2),n.createElementVNode("div",Ve,[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,(c,d)=>(n.openBlock(),n.createElementBlock("li",{key:c.id,class:n.normalizeClass(e.buildTabClass(c)),"data-title":e.getTabTitle(c),draggable:e.sortable,onClick:g=>e.activate(c),onAuxclick:n.withModifiers(g=>e.close(c),["middle","prevent"]),onContextmenu:n.withModifiers(g=>e.showContextMenu(c,g),["prevent"]),onDragstart:g=>e.onDragStart(c,d,g),onDragover:g=>e.onDragOver(d,g),onDragenter:g=>e.onDragEnter(d),onDragleave:a[0]||(a[0]=(...g)=>e.onDragLeave&&e.onDragLeave(...g)),onDrop:g=>e.onDrop(d,g),onDragend:a[1]||(a[1]=(...g)=>e.onDragEnd&&e.onDragEnd(...g))},[c.icon?(n.openBlock(),n.createElementBlock("i",{key:0,class:n.normalizeClass(["router-tab__item-icon",c.icon])},null,2)):n.createCommentVNode("",!0),n.createElementVNode("span",{class:"router-tab__item-title",title:e.getReactiveTabTitle(c)},n.toDisplayString(e.getReactiveTabTitle(c)),9,je),e.isClosable(c)?(n.openBlock(),n.createElementBlock("a",{key:1,class:"router-tab__item-close",onClick:n.withModifiers(g=>e.close(c),["stop"])},null,8,Oe)):n.createCommentVNode("",!0)],42,Ne))),128))]),_:1},16)]),n.createElementVNode("div",{class:n.normalizeClass(["router-tab__slot-end",{"has-content":e.hasEndSlot}])},[n.renderSlot(e.$slots,"end")],2)]),n.createElementVNode("div",Ue,[n.createVNode(k,null,{default:n.withCtx(c=>[e.hasCustomSlot?n.renderSlot(e.$slots,"default",n.normalizeProps(n.mergeProps({key:0},{...c,controller:e.controller,pageRef:d=>e.handleComponentRef(d,e.controller.getRouteKey(c.route))}))):(n.openBlock(),n.createElementBlock(n.Fragment,{key:1},[n.createVNode(n.Transition,n.mergeProps(e.pageTransitionProps,{appear:""}),{default:n.withCtx(()=>[e.controller.options.keepAlive?(n.openBlock(),n.createBlock(n.KeepAlive,{key:0,include:e.includeKeys,max:e.controller.options.maxAlive||void 0},[e.isRefreshing(c.route)?n.createCommentVNode("",!0):(n.openBlock(),n.createBlock(n.resolveDynamicComponent(c.Component),{key:e.controller.getRouteKey(c.route),ref:d=>e.handleComponentRef(d,e.controller.getRouteKey(c.route)),class:"router-tab-page"}))],1032,["include","max"])):n.createCommentVNode("",!0)]),_:2},1040),n.createVNode(n.Transition,n.mergeProps(e.pageTransitionProps,{appear:""}),{default:n.withCtx(()=>[!e.controller.options.keepAlive||e.isRefreshing(c.route)?(n.openBlock(),n.createBlock(n.resolveDynamicComponent(c.Component),{key:e.controller.getRouteKey(c.route)+(e.isRefreshing(c.route)?"-refresh":""),ref:d=>e.handleComponentRef(d,e.controller.getRouteKey(c.route)),class:"router-tab-page"})):n.createCommentVNode("",!0)]),_:2},1040)],64))]),_:3})]),e.context.visible&&e.context.target?(n.openBlock(),n.createElementBlock("div",{key:0,ref:"menuRef",class:"router-tab__contextmenu",role:"menu",onKeydown:a[2]||(a[2]=(...c)=>e.onMenuKeydown&&e.onMenuKeydown(...c)),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,(c,d)=>(n.openBlock(),n.createElementBlock("a",{key:c.id,role:"menuitem",class:n.normalizeClass(["router-tab__contextmenu-item",{"is-focused":d===e.highlightedIndex}]),"aria-disabled":c.disabled,disabled:c.disabled,tabindex:c.disabled?-1:d===e.highlightedIndex?0:-1,ref_for:!0,ref:g=>e.setMenuItemRef(g,d),onMouseenter:g=>!c.disabled&&e.highlightMenuIndex(d),onClick:g=>e.handleMenuAction(c)},n.toDisplayString(c.label),43,ze))),128))],36)):n.createCommentVNode("",!0)])}const te=$e(Me,[["render",_e]]),Ye={class:"router-tabs","aria-hidden":"true"},F=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 ee(e),(o,s)=>(n.openBlock(),n.createElementBlock("span",Ye))}}),be="tab-theme-style",me="tab-theme-primary-color",Fe="system",pe="(prefers-color-scheme: dark)";let N=null;const C={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"},He={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 Je(e){if(typeof window>"u")return null;const a=window.localStorage.getItem(e);if(!a)return null;try{const o=JSON.parse(a);return o&&typeof o=="object"?o:null}catch{return null}}function ne(e){typeof document>"u"||(document.documentElement.style.setProperty("--router-tab-primary",e.primary??C.primary),document.documentElement.style.setProperty("--router-tab-header-bg",e.headerBackground??C.headerBackground),document.documentElement.style.setProperty("--router-tab-background",e.background??C.background),document.documentElement.style.setProperty("--router-tab-active-background",e.activeBackground??C.activeBackground),document.documentElement.style.setProperty("--router-tab-text",e.text??C.text),document.documentElement.style.setProperty("--router-tab-active-text",e.activeText??C.activeText),document.documentElement.style.setProperty("--router-tab-border",e.border??C.border),document.documentElement.style.setProperty("--router-tab-active-border",e.activeBorder??C.activeBorder),document.documentElement.style.setProperty("--router-tab-button-color",e.buttonColor??C.buttonColor),document.documentElement.style.setProperty("--router-tab-active-button-color",e.activeButtonColor??C.activeButtonColor),document.documentElement.style.setProperty("--router-tab-button-background",e.buttonBackground??C.buttonBackground),document.documentElement.style.setProperty("--router-tab-active-button-background",e.activeButtonBackground??C.activeButtonBackground),document.documentElement.style.setProperty("--router-tab-icon-color",e.iconColor??C.iconColor))}function ge(e){if(typeof document>"u")return;const a=document.documentElement,o=window.matchMedia(pe),s=()=>{a.dataset.theme=o.matches?"dark":"light"};N&&(o.removeEventListener("change",N),N=null),e==="system"?(s(),N=()=>s(),o.addEventListener("change",N)):a.dataset.theme=e}function he(e={}){if(typeof window>"u")return;const{styleKey:a=be,primaryKey:o=me,defaultStyle:s=Fe,defaultPrimary:r}=e,p=window.localStorage.getItem(a)??s;ge(p);const c=p==="dark"||p==="system"&&window.matchMedia(pe).matches?{...He}:{...C};r&&(c.primary=r);const d=Je(o);ne(d?{...c,...d}:c)}function We(e,a){if(typeof window>"u")return;const o=a?.styleKey??be;window.localStorage.setItem(o,e),ge(e)}function qe(e,a){if(typeof window>"u")return;const o=a?.primaryKey??me;window.localStorage.setItem(o,JSON.stringify(e)),ne(e)}function H(e,a){if(n.isRef(e)){const s=!n.isReadonly(e);return{value:e,update:s?r=>{e.value=r}:()=>{}}}if(typeof e=="function"){const s=e;return{value:n.computed(s),update:()=>{}}}const o=n.ref(e===void 0?a:e);return{value:o,update:s=>{o.value=s}}}function J(e={}){const a=H(e.title,"Untitled"),o=H(e.icon,""),s=H(e.closable,!0),r=H(e.meta,{});return{routeTabTitle:a.value,routeTabIcon:o.value,routeTabClosable:s.value,routeTabMeta:r.value,updateTitle:a.update,updateIcon:o.update,updateClosable:s.update,updateMeta:r.update}}function Ge(e,a="Page"){return J({title:n.computed(()=>e.value?"Loading...":a),icon:n.computed(()=>e.value?"mdi-loading mdi-spin":"mdi-page"),closable:n.computed(()=>!e.value)})}function Xe(e,a="Page",o="mdi-page"){return J({title:n.computed(()=>e.value>0?`${a} (${e.value})`:a),icon:n.computed(()=>e.value>0?"mdi-bell-badge":o)})}function Qe(e,a="Page"){const o={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 J({title:n.computed(()=>a+o[e.value].suffix),icon:n.computed(()=>o[e.value].icon),closable:n.computed(()=>e.value!=="loading")})}let ye=!1;const Ze={install(e,a){if(ye)return;ye=!0;const{initTheme:o=!0,themeOptions:s,componentName:r=te.name||"RouterTab",tabsComponentName:p=F.name||"RouterTabs"}=a??{};o&&he(s??{}),e.component(r,te),e.component(p,F),p.toLowerCase()!=="router-tabs"&&e.component("router-tabs",F),Object.defineProperty(e.config.globalProperties,"$tabs",{configurable:!0,enumerable:!1,get(){return e._context.provides[V]},set(k){k&&e.provide(V,k)}})}};w.RouterTab=te,w.RouterTabs=F,w.default=Ze,w.initRouterTabsTheme=he,w.routerTabsKey=V,w.setRouterTabsPrimary=qe,w.setRouterTabsTheme=We,w.useLoadingTab=Ge,w.useNotificationTab=Xe,w.useReactiveTab=J,w.useRouterTabs=Z,w.useRouterTabsPersistence=ee,w.useStatusTab=Qe,Object.defineProperties(w,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
|
1
|
+
(function(w,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):(w=typeof globalThis<"u"?globalThis:w||self,n(w["vue3-router-tab"]={},w.Vue,w.VueRouter))})(this,(function(w,n,Re){"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 D(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 Pe={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 $(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=Pe[o.toLowerCase()];return a?a(e):o}return e.fullPath}function G(e,o){const a=e.meta?.keepAlive;return typeof a=="boolean"?a:o}function X(e,o){const a=e.meta?.reuse;return typeof a=="boolean"?a:o}function se(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 _(e,o,a){const s=se(e);return{id:$(e),to:e.fullPath,fullPath:e.fullPath,matched:e,alive:G(e,a),reusable:X(e,!1),closable:s.closable??!0,renderKey:typeof o.renderKey=="number"?o.renderKey:0,...s,...o}}function Q(e,o,a,s){if(!e.find(p=>p.id===o.id)){if(a==="next"&&s){const p=e.findIndex(v=>v.id===s);if(p!==-1){e.splice(p+1,0,o);return}}e.push(o)}}function ce(e,o,a){if(!o||o<=0)return;const s=e.filter(i=>i.alive);for(;s.length>o;){const i=s.shift();if(!i||i.id===a)continue;const p=e.findIndex(v=>v.id===i.id);p>-1&&(e[p].alive=!1)}}function Be(e){return{to:e.to,title:e.title,tips:e.tips,icon:e.icon,tabClass:e.tabClass,closable:e.closable,renderKey:e.renderKey}}function Ae(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),"renderKey"in e&&typeof e.renderKey=="number"&&(o.renderKey=e.renderKey),o}function Ke(e,o={}){const a=Ee(o),s=n.reactive([]),i=n.ref(null),p=n.shallowRef(),v=n.ref(null),c=n.computed(()=>s.filter(l=>l.alive).map(l=>`${l.id}::${l.renderKey}`));let d=!1;function g(l){const m=typeof l.matched=="object"?l:D(e,l);return{key:$(m),fullPath:m.fullPath,alive:G(m,a.keepAlive),reusable:X(m,!1),matched:m}}function E(l){const m=$(l);let b=s.find(k=>k.id===m);return b?(b.fullPath=l.fullPath,b.to=l.fullPath,b.matched=l,b.alive=G(l,a.keepAlive),b.reusable=X(l,b.reusable),Object.assign(b,se(l)),b):(b=_(l,{},a.keepAlive),Q(s,b,a.appendPosition,i.value),ce(s,a.maxAlive,i.value),b)}async function K(l,m=!1,b=!0){const k=D(e,l),C=$(k),P=i.value===C;b==="sameTab"&&(b=P),b&&await M(C,!0),await e[m?"replace":"push"](k),P&&await T()}function S(l){const m=s.findIndex(A=>A.id===l);if(m===-1)return a.defaultRoute;const b=s[m+1],k=s[m-1],C=s.find(A=>A.id!==l),P=b||k||C;return P?P.to:a.defaultRoute}async function j(l=i.value,m={}){if(!l)return;if(!m.force&&a.keepLastTab&&s.length===1)throw new Error("[RouterTabs] Unable to close the final tab when keepLastTab is true.");const k=i.value===l&&m.redirect!==null,C=k?m.redirect??S(l):null;await O(l,{force:m.force}),m.redirect!==null&&k&&C&&await e.replace(C)}async function O(l,m={}){const b=s.findIndex(k=>k.id===l);b!==-1&&(s.splice(b,1),v.value===l&&(v.value=null),i.value===l&&(i.value=null,p.value=void 0))}async function M(l=i.value??void 0,m=!1){if(!l)return;const b=s.find(C=>C.id===l);if(!b)return;const k=a.keepAlive&&b.alive;k&&(b.alive=!1,await n.nextTick()),b.renderKey=(b.renderKey??0)+1,k&&(b.alive=!0,await n.nextTick()),v.value=l,await n.nextTick(),v.value=null}async function oe(l=!1){for(const m of s)await M(m.id,l)}async function ae(l=a.defaultRoute){s.splice(0,s.length),i.value=null,p.value=void 0;for(const m of a.initialTabs){const b=D(e,m.to),k=_(b,m,a.keepAlive);s.push(k)}await e.replace(l)}async function T(){const l=i.value;l&&await M(l,!0)}function W(l){return typeof l.matched=="object"?$(l):$(D(e,l))}function x(){const l=s.find(m=>m.id===i.value);return{tabs:s.map(Be),active:l?l.to:null}}async function I(l){d=!0,s.splice(0,s.length),i.value=null,p.value=void 0;const m=l?.tabs??[];for(const k of m)try{const C=D(e,k.to),P=Ae(k),A=_(C,P,a.keepAlive);Q(s,A,"last",null)}catch{}d=!1;const b=l?.active??m[m.length-1]?.to??a.defaultRoute;if(b)try{await e.replace(b)}catch{}}return n.watch(()=>e.currentRoute.value,l=>{if(d)return;const m=E(l);i.value=m.id,p.value=m,ce(s,a.maxAlive,i.value)},{immediate:!0}),a.initialTabs.length&&a.initialTabs.forEach(l=>{const m=D(e,l.to),b=_(m,l,a.keepAlive);Q(s,b,"last",null)}),{options:a,tabs:s,activeId:i,current:p,includeKeys:c,refreshingKey:v,openTab:K,closeTab:j,removeTab:O,refreshTab:M,refreshAll:oe,reset:ae,reload:T,getRouteKey:W,matchRoute:g,snapshot:x,hydrate:I}}function ue(e){return e?typeof e=="string"?{name:e}:e:{}}const V=Symbol("RouterTabsContext"),Y="router-tabs:snapshot";function Z(e={}){const{optional:o=!1}=e,a=n.inject(V,null);if(a)return a;const s=n.inject("$tabs",null);if(s)return s;const p=n.getCurrentInstance()?.appContext.config.globalProperties.$tabs;if(p)return p;if(!o)throw new Error("[RouterTabs] useRouterTabs must be used within <router-tab>.");return null}const Ie=864e5;function Se(e){if(typeof document>"u")return null;const o=`${encodeURIComponent(e)}=`,a=document.cookie?document.cookie.split("; "):[];for(const s of a)if(s.startsWith(o))return decodeURIComponent(s.slice(o.length));return null}function de(e,o,a){if(typeof document>"u")return;const{expiresInDays:s=7,path:i="/",domain:p,secure:v,sameSite:c="lax"}=a,d=[`${encodeURIComponent(e)}=${encodeURIComponent(o)}`];if(s!==1/0){const g=new Date(Date.now()+s*Ie).toUTCString();d.push(`Expires=${g}`)}i&&d.push(`Path=${i}`),p&&d.push(`Domain=${p}`),v&&d.push("Secure"),c&&d.push(`SameSite=${c.charAt(0).toUpperCase()}${c.slice(1)}`),document.cookie=d.join("; ")}function fe(e,o){if(typeof document>"u")return;const{path:a="/",domain:s}=o,i=[`${encodeURIComponent(e)}=`];i.push("Expires=Thu, 01 Jan 1970 00:00:01 GMT"),a&&i.push(`Path=${a}`),s&&i.push(`Domain=${s}`),document.cookie=i.join("; ")}const xe=e=>JSON.stringify(e??null),De=e=>{if(!e)return null;try{return JSON.parse(e)}catch{return null}};function ee(e={}){const{cookieKey:o=Y,serialize:a=xe,deserialize:s=De}=e,i=Z({optional:!0}),p=n.ref(!0),v=c=>{n.onMounted(async()=>{const d=s(Se(o));if(d&&d.tabs?.length)try{if(p.value=!0,await c.hydrate(d),d.active){await n.nextTick();const E=c.tabs.find(K=>K.to===d.active);E&&(c.activeId.value=E.id,c.current.value=E)}}finally{p.value=!1}else if(Object.prototype.hasOwnProperty.call(e,"fallbackRoute"))try{p.value=!0;const E=e.fallbackRoute??c.options.defaultRoute;await c.reset(E)}finally{p.value=!1}else p.value=!1;const g=c.snapshot();g.tabs.length?de(o,a(g),e):fe(o,e),p.value=!1}),n.watch(()=>({tabs:c.tabs.map(d=>({to:d.to,title:d.title,tips:d.tips,icon:d.icon,tabClass:d.tabClass,closable:d.closable,renderKey:d.renderKey})),active:c.activeId.value}),()=>{if(p.value)return;const d=c.snapshot();d.tabs.length?de(o,a(d),e):fe(o,e)},{deep:!0})};i?v(i):n.onMounted(()=>{const c=Z({optional:!0});c&&v(c)})}const $e=n.defineComponent({name:"RouterTab",components:{RouterView:Re.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:Y},persistence:{type:Object,default:null},sortable:{type:Boolean,default:!0}},emits:["tab-sort","tab-sorted"],setup(e,{emit:o}){const a=n.getCurrentInstance();if(!a)throw new Error("[RouterTab] component must be used within a Vue application context.");const s=a.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=Ke(s,{initialTabs:e.tabs,keepAlive:e.keepAlive,maxAlive:e.maxAlive,keepLastTab:e.keepLastTab,appendPosition:e.append,defaultRoute:e.defaultPage});n.provide(V,i),a.appContext.config.globalProperties.$tabs=i;const p=n.computed(()=>!!a?.slots?.default),v=n.computed(()=>!!a?.slots?.start),c=n.computed(()=>!!a?.slots?.end),d=n.ref(0),g=n.computed(()=>{d.value;const t={};return i.tabs.forEach(r=>{const f=typeof r.title=="string"?r.title:String(r.title||re(r));t[r.id]=f}),t});function E(){d.value++}const K=new Map,S=new Map;function j(t,r){if(!r||K.has(t))return;K.set(t,r);const f=i.tabs.find(y=>i.getRouteKey(y.to)===t);if(!f)return;const h=[];if(r.routeTabTitle!==void 0){const y=n.watch(()=>{const u=r.routeTabTitle;return u&&typeof u=="object"&&"value"in u?u.value:u},u=>{if(u!=null){const L=String(u);f.title=L,E()}},{immediate:!0});h.push(y)}if(r.routeTabIcon!==void 0){const y=n.watch(()=>{const u=r.routeTabIcon;return u&&typeof u=="object"&&"value"in u?u.value:u},u=>{u!=null&&(f.icon=String(u),E())},{immediate:!0});h.push(y)}if(r.routeTabClosable!==void 0){const y=n.watch(()=>{const u=r.routeTabClosable;return u&&typeof u=="object"&&"value"in u?u.value:u},u=>{u!=null&&(f.closable=!!u,E())},{immediate:!0});h.push(y)}if(r.routeTabMeta!==void 0){const y=n.watch(()=>{const u=r.routeTabMeta;return u&&typeof u=="object"&&"value"in u?u.value:u},u=>{u&&typeof u=="object"&&(Object.assign(f,u),E())},{immediate:!0,deep:!0});h.push(y)}S.set(t,h)}function O(t){const r=S.get(t);r&&(r.forEach(f=>f()),S.delete(t)),K.delete(t)}function M(t,r){t?t.routeTabTitle!==void 0||t.routeTabIcon!==void 0||t.routeTabClosable!==void 0?j(r,t):t.$&&(t.$.routeTabTitle!==void 0||t.$.routeTabIcon!==void 0||t.$.routeTabClosable!==void 0)&&j(r,t.$):t===null&&O(r)}if(e.cookieKey!==null||e.persistence){const t={...e.persistence??{}};e.cookieKey!==null?t.cookieKey=e.cookieKey||Y:t.cookieKey||(t.cookieKey=Y),ee(t)}const oe=n.computed(()=>ue(e.tabTransition)),ae=n.computed(()=>ue(e.pageTransition)),T=n.reactive({visible:!1,target:null,position:{x:0,y:0}}),W=n.ref(null),x=n.ref([]),I=n.ref(-1),l=n.reactive({dragging:!1,dragIndex:-1,dropIndex:-1,dragTab:null}),m=["refresh","refreshAll","close","closeLefts","closeRights","closeOthers"];function b(t){return i.tabs.findIndex(r=>r.id===t)}function k(t){const r=b(t.id);return r>0?i.tabs.slice(0,r):[]}function C(t){const r=b(t.id);return r>-1?i.tabs.slice(r+1):[]}function P(t){return i.tabs.filter(r=>r.id!==t.id)}async function A(t,r){const f=t.filter(h=>h.closable!==!1);if(f.length){for(const h of f)i.activeId.value===h.id?await i.closeTab(h.id,{redirect:r.to,force:!0}):await i.removeTab(h.id,{force:!0});i.activeId.value!==r.id&&await i.openTab(r.to,!0,!1)}}const tt={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})=>ie(t)},closeLefts:{label:"Close to the Left",handler:async({target:t})=>{await A(k(t),t)},enable:({target:t})=>k(t).some(r=>r.closable!==!1)},closeRights:{label:"Close to the Right",handler:async({target:t})=>{await A(C(t),t)},enable:({target:t})=>C(t).some(r=>r.closable!==!1)},closeOthers:{label:"Close Others",handler:async({target:t})=>{await A(P(t),t)},enable:({target:t})=>P(t).some(r=>r.closable!==!1)}};function B(){T.visible=!1,T.target=null,I.value=-1,x.value=[]}function nt(t,r){e.contextmenu&&(T.visible=!0,T.target=t,T.position.x=r.clientX,T.position.y=r.clientY,document.addEventListener("click",B,{once:!0}),n.nextTick(()=>{at()}))}function ot(t,r){const f=typeof t=="string"?{id:t}:t,h=tt[f.id],y=f.label??h?.label??String(f.id),u=f.visible??h?.visible??!0;if(!(typeof u=="function"?u(r):u!==!1))return null;const le=f.enable??h?.enable??!0,kt=typeof le=="function"?le(r):le!==!1,Ce=f.handler??h?.handler;if(!Ce)return null;const vt=async()=>{await Promise.resolve(Ce(r))};return{id:String(f.id),label:y,disabled:!kt,action:vt}}const U=n.computed(()=>{if(!T.visible||!T.target||e.contextmenu===!1)return[];const t=Array.isArray(e.contextmenu)?e.contextmenu:m,r={target:T.target,controller:i};return t.map(f=>ot(f,r)).filter(f=>!!f)});function at(){const t=W.value;if(!t)return;const r=8,{innerWidth:f,innerHeight:h}=window,y=t.getBoundingClientRect();let u=T.position.x,L=T.position.y;y.right>f-r&&(u=Math.max(r,f-y.width-r)),y.bottom>h-r&&(L=Math.max(r,h-y.height-r)),(u!==T.position.x||L!==T.position.y)&&(T.position.x=u,T.position.y=L)}function rt(t,r){x.value[r]=t??null}function it(t){if(t<0)return;x.value[t]?.focus({preventScroll:!0})}function q(t,r,f=U.value){if(!f.length)return-1;const h=f.length;let y=t;for(let u=0;u<h;u++)if(y=(y+r+h)%h,!f[y].disabled)return y;return-1}function z(t){I.value=t,!(t<0)&&n.nextTick(()=>it(t))}function Te(t){const r=q(I.value,t);r!==-1&&z(r)}function lt(t){if(!T.visible)return;const r=t.key,f=U.value;if(!f.length)return;if(r==="Tab"){B();return}if(["ArrowDown","ArrowUp","ArrowRight","ArrowLeft","Home","End","Enter"," ","Spacebar","Escape"].includes(r))switch(t.preventDefault(),r){case"ArrowDown":case"ArrowRight":Te(1);break;case"ArrowUp":case"ArrowLeft":Te(-1);break;case"Home":z(q(-1,1));break;case"End":z(q(f.length,-1));break;case"Enter":case" ":case"Spacebar":{const y=I.value;if(y>-1){const u=f[y];u.disabled||ke(u)}break}case"Escape":B();break}}async function ke(t){t.disabled||(B(),await t.action())}function re(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 st(t){return g.value[t.id]||re(t)}function ve(t){const r=i.getRouteKey(t),h=i.tabs.find(y=>y.id===r)?.renderKey??0;return`${r}::${h}`}function ct(t){return`${ve(t)}::refresh`}function ie(t){return!(t.closable===!1||i.options.keepLastTab&&i.tabs.length<=1)}async function ut(t){await i.closeTab(t.id)}function dt(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)}function ft(t){return["router-tab__item",{"is-active":i.activeId.value===t.id,"is-closable":ie(t),"is-dragging":l.dragging&&l.dragTab?.id===t.id,"is-drag-over":l.dropIndex===b(t.id)},t.tabClass]}function bt(t){return i.refreshingKey.value===i.getRouteKey(t)}function mt(t,r,f){e.sortable&&(l.dragging=!0,l.dragIndex=r,l.dragTab=t,f.dataTransfer&&(f.dataTransfer.effectAllowed="move",f.dataTransfer.setData("text/plain",t.id)),o("tab-sort",{tab:t,index:r}))}function pt(t,r){!e.sortable||!l.dragging||(r.preventDefault(),r.dataTransfer&&(r.dataTransfer.dropEffect="move"))}function gt(t){!e.sortable||!l.dragging||(l.dropIndex=t)}function ht(){!e.sortable||l.dragging}function yt(t,r){if(!(!e.sortable||!l.dragging)){if(r.preventDefault(),l.dragIndex!==-1&&l.dragIndex!==t){const f=i.tabs.splice(l.dragIndex,1)[0];i.tabs.splice(t,0,f),o("tab-sorted",{tab:f,fromIndex:l.dragIndex,toIndex:t})}we()}}function we(){l.dragging=!1,l.dragIndex=-1,l.dropIndex=-1,l.dragTab=null}n.onMounted(()=>{document.addEventListener("keydown",B)}),n.onBeforeUnmount(()=>{document.removeEventListener("keydown",B),a.appContext.config.globalProperties.$tabs=null,S.forEach(t=>{t.forEach(r=>r())}),S.clear(),K.clear()}),n.watch(()=>e.keepAlive,t=>{i.options.keepAlive=t}),n.watch(()=>i.activeId.value,()=>B()),n.watch(()=>e.contextmenu,t=>{t||B()}),n.watch(()=>U.value.length,t=>{T.visible&&t===0&&B()}),n.watch(U,t=>{if(x.value=new Array(t.length).fill(null),!T.visible)return;const r=q(-1,1,t);z(r)}),n.watch(()=>T.visible,t=>{t||(I.value=-1,x.value=[])});const Tt=i.includeKeys;return{controller:i,tabs:i.tabs,includeKeys:Tt,tabTransitionProps:oe,pageTransitionProps:ae,buildTabClass:ft,activate:dt,close:ut,context:T,menuItems:U,handleMenuAction:ke,showContextMenu:nt,hideContextMenu:B,getTabTitle:re,isClosable:ie,isRefreshing:bt,hasCustomSlot:p,hasStartSlot:v,hasEndSlot:c,onDragStart:mt,onDragOver:pt,onDragEnter:gt,onDragLeave:ht,onDrop:yt,onDragEnd:we,setupComponentWatching:j,cleanupComponentWatching:O,handleComponentRef:M,getReactiveTabTitle:st,getComponentCacheKey:ve,getRefreshComponentKey:ct,triggerTabUpdate:E,menuRef:W,highlightedIndex:I,setMenuItemRef:rt,onMenuKeydown:lt,highlightMenuIndex:z}}}),Me=(e,o)=>{const a=e.__vccOpts||e;for(const[s,i]of o)a[s]=i;return a},Le={class:"router-tab"},Ve={class:"router-tab__header"},Ne={class:"router-tab__scroll"},je=["data-title","draggable","onClick","onAuxclick","onContextmenu","onDragstart","onDragover","onDragenter","onDrop"],Oe=["title"],Ue=["onClick"],ze={class:"router-tab__container"},_e=["aria-disabled","disabled","tabindex","onMouseenter","onClick"];function Ye(e,o,a,s,i,p){const v=n.resolveComponent("RouterView");return n.openBlock(),n.createElementBlock("div",Le,[n.createElementVNode("header",Ve,[n.createElementVNode("div",{class:n.normalizeClass(["router-tab__slot-start",{"has-content":e.hasStartSlot}])},[n.renderSlot(e.$slots,"start")],2),n.createElementVNode("div",Ne,[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,(c,d)=>(n.openBlock(),n.createElementBlock("li",{key:c.id,class:n.normalizeClass(e.buildTabClass(c)),"data-title":e.getTabTitle(c),draggable:e.sortable,onClick:g=>e.activate(c),onAuxclick:n.withModifiers(g=>e.close(c),["middle","prevent"]),onContextmenu:n.withModifiers(g=>e.showContextMenu(c,g),["prevent"]),onDragstart:g=>e.onDragStart(c,d,g),onDragover:g=>e.onDragOver(d,g),onDragenter:g=>e.onDragEnter(d),onDragleave:o[0]||(o[0]=(...g)=>e.onDragLeave&&e.onDragLeave(...g)),onDrop:g=>e.onDrop(d,g),onDragend:o[1]||(o[1]=(...g)=>e.onDragEnd&&e.onDragEnd(...g))},[c.icon?(n.openBlock(),n.createElementBlock("i",{key:0,class:n.normalizeClass(["router-tab__item-icon",c.icon])},null,2)):n.createCommentVNode("",!0),n.createElementVNode("span",{class:"router-tab__item-title",title:e.getReactiveTabTitle(c)},n.toDisplayString(e.getReactiveTabTitle(c)),9,Oe),e.isClosable(c)?(n.openBlock(),n.createElementBlock("a",{key:1,class:"router-tab__item-close",onClick:n.withModifiers(g=>e.close(c),["stop"])},null,8,Ue)):n.createCommentVNode("",!0)],42,je))),128))]),_:1},16)]),n.createElementVNode("div",{class:n.normalizeClass(["router-tab__slot-end",{"has-content":e.hasEndSlot}])},[n.renderSlot(e.$slots,"end")],2)]),n.createElementVNode("div",ze,[n.createVNode(v,null,{default:n.withCtx(c=>[e.hasCustomSlot?n.renderSlot(e.$slots,"default",n.normalizeProps(n.mergeProps({key:0},{...c,controller:e.controller,pageRef:d=>e.handleComponentRef(d,e.controller.getRouteKey(c.route))}))):(n.openBlock(),n.createElementBlock(n.Fragment,{key:1},[n.createVNode(n.Transition,n.mergeProps(e.pageTransitionProps,{appear:""}),{default:n.withCtx(()=>[e.controller.options.keepAlive?(n.openBlock(),n.createBlock(n.KeepAlive,{key:0,include:e.includeKeys,max:e.controller.options.maxAlive||void 0},[e.isRefreshing(c.route)?n.createCommentVNode("",!0):(n.openBlock(),n.createBlock(n.resolveDynamicComponent(c.Component),{key:e.getComponentCacheKey(c.route),ref:d=>e.handleComponentRef(d,e.controller.getRouteKey(c.route)),class:"router-tab-page"}))],1032,["include","max"])):n.createCommentVNode("",!0)]),_:2},1040),n.createVNode(n.Transition,n.mergeProps(e.pageTransitionProps,{appear:""}),{default:n.withCtx(()=>[!e.controller.options.keepAlive||e.isRefreshing(c.route)?(n.openBlock(),n.createBlock(n.resolveDynamicComponent(c.Component),{key:e.getRefreshComponentKey(c.route),ref:d=>e.handleComponentRef(d,e.controller.getRouteKey(c.route)),class:"router-tab-page"})):n.createCommentVNode("",!0)]),_:2},1040)],64))]),_:3})]),e.context.visible&&e.context.target?(n.openBlock(),n.createElementBlock("div",{key:0,ref:"menuRef",class:"router-tab__contextmenu",role:"menu",onKeydown:o[2]||(o[2]=(...c)=>e.onMenuKeydown&&e.onMenuKeydown(...c)),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,(c,d)=>(n.openBlock(),n.createElementBlock("a",{key:c.id,role:"menuitem",class:n.normalizeClass(["router-tab__contextmenu-item",{"is-focused":d===e.highlightedIndex}]),"aria-disabled":c.disabled,disabled:c.disabled,tabindex:c.disabled?-1:d===e.highlightedIndex?0:-1,ref_for:!0,ref:g=>e.setMenuItemRef(g,d),onMouseenter:g=>!c.disabled&&e.highlightMenuIndex(d),onClick:g=>e.handleMenuAction(c)},n.toDisplayString(c.label),43,_e))),128))],36)):n.createCommentVNode("",!0)])}const te=Me($e,[["render",Ye]]),Fe={class:"router-tabs","aria-hidden":"true"},F=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 ee(e),(a,s)=>(n.openBlock(),n.createElementBlock("span",Fe))}}),be="tab-theme-style",me="tab-theme-primary-color",He="system",pe="(prefers-color-scheme: dark)";let N=null;const R={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"},Je={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 We(e){if(typeof window>"u")return null;const o=window.localStorage.getItem(e);if(!o)return null;try{const a=JSON.parse(o);return a&&typeof a=="object"?a:null}catch{return null}}function ne(e){typeof document>"u"||(document.documentElement.style.setProperty("--router-tab-primary",e.primary??R.primary),document.documentElement.style.setProperty("--router-tab-header-bg",e.headerBackground??R.headerBackground),document.documentElement.style.setProperty("--router-tab-background",e.background??R.background),document.documentElement.style.setProperty("--router-tab-active-background",e.activeBackground??R.activeBackground),document.documentElement.style.setProperty("--router-tab-text",e.text??R.text),document.documentElement.style.setProperty("--router-tab-active-text",e.activeText??R.activeText),document.documentElement.style.setProperty("--router-tab-border",e.border??R.border),document.documentElement.style.setProperty("--router-tab-active-border",e.activeBorder??R.activeBorder),document.documentElement.style.setProperty("--router-tab-button-color",e.buttonColor??R.buttonColor),document.documentElement.style.setProperty("--router-tab-active-button-color",e.activeButtonColor??R.activeButtonColor),document.documentElement.style.setProperty("--router-tab-button-background",e.buttonBackground??R.buttonBackground),document.documentElement.style.setProperty("--router-tab-active-button-background",e.activeButtonBackground??R.activeButtonBackground),document.documentElement.style.setProperty("--router-tab-icon-color",e.iconColor??R.iconColor))}function ge(e){if(typeof document>"u")return;const o=document.documentElement,a=window.matchMedia(pe),s=()=>{o.dataset.theme=a.matches?"dark":"light"};N&&(a.removeEventListener("change",N),N=null),e==="system"?(s(),N=()=>s(),a.addEventListener("change",N)):o.dataset.theme=e}function he(e={}){if(typeof window>"u")return;const{styleKey:o=be,primaryKey:a=me,defaultStyle:s=He,defaultPrimary:i}=e,p=window.localStorage.getItem(o)??s;ge(p);const c=p==="dark"||p==="system"&&window.matchMedia(pe).matches?{...Je}:{...R};i&&(c.primary=i);const d=We(a);ne(d?{...c,...d}:c)}function qe(e,o){if(typeof window>"u")return;const a=o?.styleKey??be;window.localStorage.setItem(a,e),ge(e)}function Ge(e,o){if(typeof window>"u")return;const a=o?.primaryKey??me;window.localStorage.setItem(a,JSON.stringify(e)),ne(e)}function H(e,o){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 a=n.ref(e===void 0?o:e);return{value:a,update:s=>{a.value=s}}}function J(e={}){const o=H(e.title,"Untitled"),a=H(e.icon,""),s=H(e.closable,!0),i=H(e.meta,{});return{routeTabTitle:o.value,routeTabIcon:a.value,routeTabClosable:s.value,routeTabMeta:i.value,updateTitle:o.update,updateIcon:a.update,updateClosable:s.update,updateMeta:i.update}}function Xe(e,o="Page"){return J({title:n.computed(()=>e.value?"Loading...":o),icon:n.computed(()=>e.value?"mdi-loading mdi-spin":"mdi-page"),closable:n.computed(()=>!e.value)})}function Qe(e,o="Page",a="mdi-page"){return J({title:n.computed(()=>e.value>0?`${o} (${e.value})`:o),icon:n.computed(()=>e.value>0?"mdi-bell-badge":a)})}function Ze(e,o="Page"){const a={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 J({title:n.computed(()=>o+a[e.value].suffix),icon:n.computed(()=>a[e.value].icon),closable:n.computed(()=>e.value!=="loading")})}let ye=!1;const et={install(e,o){if(ye)return;ye=!0;const{initTheme:a=!0,themeOptions:s,componentName:i=te.name||"RouterTab",tabsComponentName:p=F.name||"RouterTabs"}=o??{};a&&he(s??{}),e.component(i,te),e.component(p,F),p.toLowerCase()!=="router-tabs"&&e.component("router-tabs",F),Object.defineProperty(e.config.globalProperties,"$tabs",{configurable:!0,enumerable:!1,get(){return e._context.provides[V]},set(v){v&&e.provide(V,v)}})}};w.RouterTab=te,w.RouterTabs=F,w.default=et,w.initRouterTabsTheme=he,w.routerTabsKey=V,w.setRouterTabsPrimary=Ge,w.setRouterTabsTheme=qe,w.useLoadingTab=Xe,w.useNotificationTab=Qe,w.useReactiveTab=J,w.useRouterTabs=Z,w.useRouterTabsPersistence=ee,w.useStatusTab=Ze,Object.defineProperties(w,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
<component
|
|
77
77
|
v-if="!isRefreshing(routerSlot.route)"
|
|
78
78
|
:is="routerSlot.Component"
|
|
79
|
-
:key="
|
|
79
|
+
:key="getComponentCacheKey(routerSlot.route)"
|
|
80
80
|
:ref="(el: any) => handleComponentRef(el, controller.getRouteKey(routerSlot.route))"
|
|
81
81
|
class="router-tab-page"
|
|
82
82
|
/>
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
<component
|
|
91
91
|
v-if="!controller.options.keepAlive || isRefreshing(routerSlot.route)"
|
|
92
92
|
:is="routerSlot.Component"
|
|
93
|
-
:key="
|
|
93
|
+
:key="getRefreshComponentKey(routerSlot.route)"
|
|
94
94
|
:ref="(el: any) => handleComponentRef(el, controller.getRouteKey(routerSlot.route))"
|
|
95
95
|
class="router-tab-page"
|
|
96
96
|
/>
|
|
@@ -716,6 +716,17 @@ export default defineComponent({
|
|
|
716
716
|
return reactiveTitles[tab.id] || getTabTitle(tab)
|
|
717
717
|
}
|
|
718
718
|
|
|
719
|
+
function getComponentCacheKey(route: RouteLocationNormalizedLoaded): string {
|
|
720
|
+
const routeKey = controller.getRouteKey(route)
|
|
721
|
+
const tab = controller.tabs.find(item => item.id === routeKey)
|
|
722
|
+
const renderKey = tab?.renderKey ?? 0
|
|
723
|
+
return `${routeKey}::${renderKey}`
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
function getRefreshComponentKey(route: RouteLocationNormalizedLoaded): string {
|
|
727
|
+
return `${getComponentCacheKey(route)}::refresh`
|
|
728
|
+
}
|
|
729
|
+
|
|
719
730
|
function isClosable(tab: TabRecord) {
|
|
720
731
|
if (tab.closable === false) return false
|
|
721
732
|
if (controller.options.keepLastTab && controller.tabs.length <= 1) return false
|
|
@@ -910,6 +921,8 @@ export default defineComponent({
|
|
|
910
921
|
cleanupComponentWatching,
|
|
911
922
|
handleComponentRef,
|
|
912
923
|
getReactiveTabTitle,
|
|
924
|
+
getComponentCacheKey,
|
|
925
|
+
getRefreshComponentKey,
|
|
913
926
|
triggerTabUpdate,
|
|
914
927
|
menuRef,
|
|
915
928
|
highlightedIndex,
|
|
@@ -96,6 +96,7 @@ function createTabFromRoute(
|
|
|
96
96
|
alive: resolveAlive(route, keepAliveDefault),
|
|
97
97
|
reusable: resolveReusable(route, false),
|
|
98
98
|
closable: meta.closable ?? true,
|
|
99
|
+
renderKey: typeof base.renderKey === 'number' ? base.renderKey : 0,
|
|
99
100
|
...meta,
|
|
100
101
|
...base
|
|
101
102
|
}
|
|
@@ -134,7 +135,8 @@ function toSnapshotTab(tab: TabRecord): RouterTabsSnapshotTab {
|
|
|
134
135
|
tips: tab.tips,
|
|
135
136
|
icon: tab.icon,
|
|
136
137
|
tabClass: tab.tabClass,
|
|
137
|
-
closable: tab.closable
|
|
138
|
+
closable: tab.closable,
|
|
139
|
+
renderKey: tab.renderKey
|
|
138
140
|
}
|
|
139
141
|
}
|
|
140
142
|
|
|
@@ -145,6 +147,9 @@ function fromSnapshotTab(snapshot: RouterTabsSnapshotTab): Partial<TabRecord> {
|
|
|
145
147
|
if ('icon' in snapshot) base.icon = snapshot.icon
|
|
146
148
|
if ('tabClass' in snapshot) base.tabClass = snapshot.tabClass
|
|
147
149
|
if ('closable' in snapshot) base.closable = snapshot.closable
|
|
150
|
+
if ('renderKey' in snapshot && typeof snapshot.renderKey === 'number') {
|
|
151
|
+
base.renderKey = snapshot.renderKey
|
|
152
|
+
}
|
|
148
153
|
return base
|
|
149
154
|
}
|
|
150
155
|
|
|
@@ -158,7 +163,11 @@ export function createRouterTabs(
|
|
|
158
163
|
const activeId = ref<string | null>(null)
|
|
159
164
|
const current = shallowRef<TabRecord>()
|
|
160
165
|
const refreshingKey = ref<string | null>(null)
|
|
161
|
-
const includeKeys = computed(() =>
|
|
166
|
+
const includeKeys = computed(() =>
|
|
167
|
+
tabs
|
|
168
|
+
.filter(tab => tab.alive)
|
|
169
|
+
.map(tab => `${tab.id}::${tab.renderKey}`)
|
|
170
|
+
)
|
|
162
171
|
|
|
163
172
|
let isHydrating = false
|
|
164
173
|
|
|
@@ -270,16 +279,22 @@ export function createRouterTabs(
|
|
|
270
279
|
const tab = tabs.find(item => item.id === id)
|
|
271
280
|
if (!tab) return
|
|
272
281
|
|
|
273
|
-
|
|
282
|
+
const wasAlive = options.keepAlive && tab.alive
|
|
283
|
+
|
|
284
|
+
if (wasAlive) {
|
|
274
285
|
tab.alive = false
|
|
275
286
|
await nextTick()
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
tab.renderKey = (tab.renderKey ?? 0) + 1
|
|
290
|
+
|
|
291
|
+
if (wasAlive) {
|
|
276
292
|
tab.alive = true
|
|
277
293
|
await nextTick()
|
|
278
294
|
}
|
|
279
295
|
|
|
280
296
|
refreshingKey.value = id
|
|
281
297
|
await nextTick()
|
|
282
|
-
if (!force) await nextTick()
|
|
283
298
|
refreshingKey.value = null
|
|
284
299
|
}
|
|
285
300
|
|
package/lib/core/types.ts
CHANGED
|
@@ -23,6 +23,7 @@ export interface TabMeta {
|
|
|
23
23
|
export interface TabInput extends Partial<TabMeta> {
|
|
24
24
|
to: RouteLocationRaw
|
|
25
25
|
id?: string
|
|
26
|
+
renderKey?: number
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export interface TabRecord extends TabMeta {
|
|
@@ -32,6 +33,7 @@ export interface TabRecord extends TabMeta {
|
|
|
32
33
|
matched: RouteLocationNormalizedLoaded
|
|
33
34
|
alive: boolean
|
|
34
35
|
reusable: boolean
|
|
36
|
+
renderKey: number
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
export type RouterTabsMenuPreset =
|
|
@@ -64,6 +66,7 @@ export interface RouterTabsSnapshotTab {
|
|
|
64
66
|
icon?: TabRecord['icon']
|
|
65
67
|
tabClass?: TabRecord['tabClass']
|
|
66
68
|
closable?: boolean
|
|
69
|
+
renderKey?: number
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
export interface RouterTabsSnapshot {
|
package/lib/persistence.ts
CHANGED
|
@@ -149,7 +149,8 @@ export function useRouterTabsPersistence(options: RouterTabsPersistenceOptions =
|
|
|
149
149
|
tips: tab.tips,
|
|
150
150
|
icon: tab.icon,
|
|
151
151
|
tabClass: tab.tabClass,
|
|
152
|
-
closable: tab.closable
|
|
152
|
+
closable: tab.closable,
|
|
153
|
+
renderKey: tab.renderKey
|
|
153
154
|
})),
|
|
154
155
|
active: ctrl.activeId.value
|
|
155
156
|
}),
|
package/lib/scss/index.scss
CHANGED
|
@@ -310,3 +310,251 @@
|
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
|
+
|
|
314
|
+
// =============================================================================
|
|
315
|
+
// Transition Presets
|
|
316
|
+
// =============================================================================
|
|
317
|
+
|
|
318
|
+
// Tab list animation (used for transition-group on nav items)
|
|
319
|
+
.router-tab-zoom-enter-active,
|
|
320
|
+
.router-tab-zoom-leave-active {
|
|
321
|
+
transition:
|
|
322
|
+
transform $router-tab-transition-fast,
|
|
323
|
+
opacity $router-tab-transition-fast;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.router-tab-zoom-enter-from,
|
|
327
|
+
.router-tab-zoom-leave-to {
|
|
328
|
+
transform: scale(0.9);
|
|
329
|
+
opacity: 0;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.router-tab-zoom-enter-to,
|
|
333
|
+
.router-tab-zoom-leave-from {
|
|
334
|
+
transform: scale(1);
|
|
335
|
+
opacity: 1;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.router-tab-zoom-move {
|
|
339
|
+
transition: transform $router-tab-transition-fast;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Page swap animation (default for routed content)
|
|
343
|
+
.router-tab-swap-enter-active,
|
|
344
|
+
.router-tab-swap-leave-active {
|
|
345
|
+
position: relative;
|
|
346
|
+
transition:
|
|
347
|
+
opacity 0.3s ease,
|
|
348
|
+
transform 0.3s ease;
|
|
349
|
+
will-change: opacity, transform;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.router-tab-swap-enter-from {
|
|
353
|
+
opacity: 0;
|
|
354
|
+
transform: translateY(20px);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.router-tab-swap-enter-to {
|
|
358
|
+
opacity: 1;
|
|
359
|
+
transform: translateY(0);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.router-tab-swap-leave-from {
|
|
363
|
+
opacity: 1;
|
|
364
|
+
transform: translateY(0);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.router-tab-swap-leave-to {
|
|
368
|
+
opacity: 0;
|
|
369
|
+
transform: translateY(-15px);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// =============================================================================
|
|
373
|
+
// Additional Page Transition Effects
|
|
374
|
+
// =============================================================================
|
|
375
|
+
|
|
376
|
+
// Slide transition - slides horizontally
|
|
377
|
+
.router-tab-slide-enter-active,
|
|
378
|
+
.router-tab-slide-leave-active {
|
|
379
|
+
position: relative;
|
|
380
|
+
transition:
|
|
381
|
+
opacity 0.3s ease,
|
|
382
|
+
transform 0.3s ease;
|
|
383
|
+
will-change: opacity, transform;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.router-tab-slide-enter-from {
|
|
387
|
+
opacity: 0;
|
|
388
|
+
transform: translateX(80px);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.router-tab-slide-enter-to {
|
|
392
|
+
opacity: 1;
|
|
393
|
+
transform: translateX(0);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.router-tab-slide-leave-from {
|
|
397
|
+
opacity: 1;
|
|
398
|
+
transform: translateX(0);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.router-tab-slide-leave-to {
|
|
402
|
+
opacity: 0;
|
|
403
|
+
transform: translateX(-80px);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Fade transition - smooth fade in and out
|
|
407
|
+
.router-tab-fade-enter-active {
|
|
408
|
+
transition: opacity 0.4s ease-in;
|
|
409
|
+
will-change: opacity;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.router-tab-fade-leave-active {
|
|
413
|
+
transition: opacity 0.3s ease-out;
|
|
414
|
+
will-change: opacity;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.router-tab-fade-enter-from {
|
|
418
|
+
opacity: 0;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.router-tab-fade-enter-to {
|
|
422
|
+
opacity: 1;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.router-tab-fade-leave-from {
|
|
426
|
+
opacity: 1;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.router-tab-fade-leave-to {
|
|
430
|
+
opacity: 0;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Scale transition - zoom in/out effect
|
|
434
|
+
.router-tab-scale-enter-active,
|
|
435
|
+
.router-tab-scale-leave-active {
|
|
436
|
+
position: relative;
|
|
437
|
+
transition:
|
|
438
|
+
opacity 0.35s ease,
|
|
439
|
+
transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
440
|
+
will-change: opacity, transform;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.router-tab-scale-enter-from {
|
|
444
|
+
opacity: 0;
|
|
445
|
+
transform: scale(0.7);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.router-tab-scale-enter-to {
|
|
449
|
+
opacity: 1;
|
|
450
|
+
transform: scale(1);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.router-tab-scale-leave-from {
|
|
454
|
+
opacity: 1;
|
|
455
|
+
transform: scale(1);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.router-tab-scale-leave-to {
|
|
459
|
+
opacity: 0;
|
|
460
|
+
transform: scale(1.2);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Flip transition - 3D flip effect
|
|
464
|
+
.router-tab-flip-enter-active,
|
|
465
|
+
.router-tab-flip-leave-active {
|
|
466
|
+
position: relative;
|
|
467
|
+
transition:
|
|
468
|
+
opacity 0.35s ease,
|
|
469
|
+
transform 0.35s ease;
|
|
470
|
+
transform-style: preserve-3d;
|
|
471
|
+
will-change: opacity, transform;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.router-tab-flip-enter-from {
|
|
475
|
+
opacity: 0;
|
|
476
|
+
transform: rotateX(-90deg);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.router-tab-flip-enter-to {
|
|
480
|
+
opacity: 1;
|
|
481
|
+
transform: rotateX(0);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.router-tab-flip-leave-from {
|
|
485
|
+
opacity: 1;
|
|
486
|
+
transform: rotateX(0);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.router-tab-flip-leave-to {
|
|
490
|
+
opacity: 0;
|
|
491
|
+
transform: rotateX(90deg);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Rotate transition - rotate and fade
|
|
495
|
+
.router-tab-rotate-enter-active,
|
|
496
|
+
.router-tab-rotate-leave-active {
|
|
497
|
+
position: relative;
|
|
498
|
+
transition:
|
|
499
|
+
opacity 0.20s ease,
|
|
500
|
+
transform 0.20s ease;
|
|
501
|
+
will-change: opacity, transform;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.router-tab-rotate-enter-from {
|
|
505
|
+
opacity: 0;
|
|
506
|
+
transform: rotate(-8deg) scale(0.85);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.router-tab-rotate-enter-to {
|
|
510
|
+
opacity: 1;
|
|
511
|
+
transform: rotate(0) scale(1);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.router-tab-rotate-leave-from {
|
|
515
|
+
opacity: 1;
|
|
516
|
+
transform: rotate(0) scale(1);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.router-tab-rotate-leave-to {
|
|
520
|
+
opacity: 0;
|
|
521
|
+
transform: rotate(8deg) scale(0.85);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Bounce transition - elastic bounce effect
|
|
525
|
+
.router-tab-bounce-enter-active {
|
|
526
|
+
animation: router-tab-bounce-in 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.router-tab-bounce-leave-active {
|
|
530
|
+
animation: router-tab-bounce-out 0.3s ease-in;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
@keyframes router-tab-bounce-in {
|
|
534
|
+
0% {
|
|
535
|
+
opacity: 0;
|
|
536
|
+
transform: scale(0.3) translateY(-80px);
|
|
537
|
+
}
|
|
538
|
+
50% {
|
|
539
|
+
opacity: 1;
|
|
540
|
+
transform: scale(1.1);
|
|
541
|
+
}
|
|
542
|
+
70% {
|
|
543
|
+
transform: scale(0.9);
|
|
544
|
+
}
|
|
545
|
+
100% {
|
|
546
|
+
opacity: 1;
|
|
547
|
+
transform: scale(1) translateY(0);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
@keyframes router-tab-bounce-out {
|
|
552
|
+
0% {
|
|
553
|
+
opacity: 1;
|
|
554
|
+
transform: scale(1);
|
|
555
|
+
}
|
|
556
|
+
100% {
|
|
557
|
+
opacity: 0;
|
|
558
|
+
transform: scale(0.7) translateY(30px);
|
|
559
|
+
}
|
|
560
|
+
}
|