vue3-router-tab 1.1.3 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vue3-router-tab.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
.router-tab{display:flex;flex-direction:column;min-height:300px;background-color:var(--router-tab-background, var(--theme-background, #ffffff));color:var(--router-tab-foreground, var(--theme-foreground, #1e293b))}.router-tab__header{position:relative;z-index:9;display:flex;flex:none;box-sizing:border-box;height:40px;border-bottom:1px solid var(--router-tab-border, var(--theme-border, rgba(15, 23, 42, .08)));background-color:var(--router-tab-header-bg, var(--router-tab-background, var(--theme-background, #ffffff)));transition:all .2s ease-in-out}.router-tab__scroll{position:relative;flex:1 1 0px;height:40px;overflow:hidden}.router-tab__scroll-container{width:100%;height:100%;overflow:hidden}.router-tab__scroll-container.is-mobile{overflow-x:auto;overflow-y:hidden}.router-tab__scrollbar{position:absolute;right:0;bottom:0;left:0;height:3px;background-color:#0000001a;border-radius:3px;opacity:0;transition:opacity .3s ease-in-out}.router-tab__scroll:hover .router-tab__scrollbar,.router-tab__scrollbar.is-dragging{opacity:1}.router-tab__scrollbar-thumb{position:absolute;top:0;left:0;height:100%;background-color:#0000001a;border-radius:3px;transition:background-color .3s ease-in-out}.router-tab__scrollbar-thumb:hover,.router-tab__scrollbar.is-dragging .router-tab__scrollbar-thumb{background-color:#0003}.router-tab__nav{position:relative;display:inline-flex;flex-wrap:nowrap;height:100%;margin:0;padding:0;list-style:none}.router-tab__item{position:relative;display:flex;flex:none;align-items:center;padding:0 20px;color:inherit;font-size:14px;border:1px solid var(--router-tab-border, var(--theme-border, rgba(15, 23, 42, .08)));border-left:none;transform-origin:left bottom;cursor:pointer;transition:all .3s ease-in-out;-webkit-user-select:none;user-select:none;background-color:transparent}.router-tab__item:first-child{border-left:1px solid var(--router-tab-border, var(--theme-border, rgba(15, 23, 42, .08)))}.router-tab__item.is-contextmenu{color:var(--router-tab-primary, var(--theme-primary, #635bff))}.router-tab__item.is-drag-over{background:#0000000d;transition:background .15s ease}.router-tab__item-title{min-width:30px;max-width:120px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.router-tab__item-icon{margin-right:5px;font-size:16px}.router-tab__item:hover,.router-tab__item.is-active{color:var(--router-tab-primary, var(--theme-primary, #635bff))}.router-tab__item:hover.is-closable,.router-tab__item.is-active.is-closable{padding:0 11.5px}.router-tab__item:hover .router-tab__item-close,.router-tab__item.is-active .router-tab__item-close{width:13px;margin-left:4px}.router-tab__item:hover .router-tab__item-close:before,.router-tab__item:hover .router-tab__item-close:after,.router-tab__item.is-active .router-tab__item-close:before,.router-tab__item.is-active .router-tab__item-close:after{background-color:#fff}.router-tab__item.is-active{border-bottom-color:var(--router-tab-background, var(--theme-background, #ffffff))}.router-tab__item-close{position:relative;display:block;width:0;height:13px;margin-left:0;overflow:hidden;border-radius:50%;cursor:pointer;transition:all .3s ease-in-out;background:transparent;border:none}.router-tab__item-close:before,.router-tab__item-close:after{position:absolute;top:6px;left:50%;display:block;width:8px;height:1px;margin-left:-4px;background-color:currentColor;transition:background-color .2s ease-in-out;content:""}.router-tab__item-close:before{transform:rotate(-45deg)}.router-tab__item-close:after{transform:rotate(45deg)}.router-tab__item-close:hover{background-color:color-mix(in srgb,var(--router-tab-primary, var(--theme-primary, #635bff)) 40%,#ffffff 60%)}.router-tab__item-close:hover:before,.router-tab__item-close:hover:after{background-color:#fff}.router-tab__contextmenu{position:fixed;z-index:1000;min-width:140px;padding:8px 0;font-size:14px;background:var(--router-tab-background, var(--theme-background, #ffffff));border:1px solid var(--router-tab-border, var(--theme-border, rgba(15, 23, 42, .08)));box-shadow:0 10px 30px #0f172a26;border-radius:8px}.router-tab__contextmenu a,.router-tab__contextmenu button{display:block;width:100%;padding:0 16px;line-height:30px;text-align:left;background:transparent;border:none;color:inherit;cursor:pointer;font:inherit;transition:background-color .2s ease-in-out}.router-tab__contextmenu a[aria-disabled=true],.router-tab__contextmenu button[aria-disabled=true]{color:#94a3b899;pointer-events:none}.router-tab__contextmenu a:hover,.router-tab__contextmenu a:focus-visible,.router-tab__contextmenu button:hover,.router-tab__contextmenu button:focus-visible{background:color-mix(in srgb,var(--router-tab-primary, var(--theme-primary, #635bff)) 20%,#ffffff 80%);color:var(--router-tab-primary, var(--theme-primary, #635bff))}.router-tab__container{position:relative;flex:1 1 auto;background-color:var(--router-tab-background, var(--theme-background, #ffffff))}.router-tab__item.is-active+.router-tab__item{border-left-color:var(--router-tab-border, var(--theme-border, rgba(15, 23, 42, .08)))}
|
package/dist/vue3-router-tab.js
CHANGED
|
@@ -680,7 +680,7 @@ const he = /* @__PURE__ */ We(Qe, [["render", rt]]), ct = {
|
|
|
680
680
|
setup(e) {
|
|
681
681
|
return Re(e), (o, t) => (h(), g("span", ct));
|
|
682
682
|
}
|
|
683
|
-
}), Ce = "theme-style", Ae = "theme-primary-color", ut = "system", ft = "#635bff", dt = "(prefers-color-scheme: dark)";
|
|
683
|
+
}), Ce = "tab-theme-style", Ae = "tab-theme-primary-color", ut = "system", ft = "#635bff", dt = "(prefers-color-scheme: dark)";
|
|
684
684
|
let S = null;
|
|
685
685
|
function _e(e) {
|
|
686
686
|
typeof document > "u" || (document.documentElement.style.setProperty("--theme-primary", e), document.documentElement.style.setProperty("--router-tab-primary", e));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(b,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue"),require("vue-router")):typeof define=="function"&&define.amd?define(["exports","vue","vue-router"],t):(b=typeof globalThis<"u"?globalThis:b||self,t(b["vue3-router-tab"]={},b.Vue,b.VueRouter))})(this,(function(b,t,le){"use strict";function se(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 R(e,o){const i=e.resolve(o);if(!i||!i.matched.length)throw new Error(`[RouterTabs] Unable to resolve route: ${String(o)}`);return i}const re={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 C(e){const o=e.meta?.key;if(typeof o=="function"){const i=o(e);if(typeof i=="string"&&i.length)return i}else if(typeof o=="string"&&o.length){const i=re[o.toLowerCase()];return i?i(e):o}return e.fullPath}function M(e,o){const i=e.meta?.keepAlive;return typeof i=="boolean"?i:o}function L(e,o){const i=e.meta?.reuse;return typeof i=="boolean"?i:o}function H(e){const o=e.meta??{},i={};return"title"in o&&(i.title=o.title),"tips"in o&&(i.tips=o.tips),"icon"in o&&(i.icon=o.icon),"closable"in o&&(i.closable=o.closable),"tabClass"in o&&(i.tabClass=o.tabClass),"target"in o&&(i.target=o.target),"href"in o&&(i.href=o.href),i}function K(e,o,i){const n=H(e);return{id:C(e),to:e.fullPath,fullPath:e.fullPath,matched:e,alive:M(e,i),reusable:L(e,!1),closable:n.closable??!0,...n,...o}}function N(e,o,i,n){if(!e.find(d=>d.id===o.id)){if(i==="next"&&n){const d=e.findIndex(m=>m.id===n);if(d>-1){e.splice(d+1,0,o);return}}e.push(o)}}function Q(e,o,i){if(!o||o<=0)return;const n=e.filter(r=>r.alive);for(;n.length>o;){const r=n.shift();if(!r||r.id===i)continue;const d=e.findIndex(m=>m.id===r.id);d>-1&&(e[d].alive=!1)}}function ce(e){return{to:e.to,title:e.title,tips:e.tips,icon:e.icon,tabClass:e.tabClass,closable:e.closable}}function ue(e){const o={};return"title"in e&&(o.title=e.title),"tips"in e&&(o.tips=e.tips),"icon"in e&&(o.icon=e.icon),"tabClass"in e&&(o.tabClass=e.tabClass),"closable"in e&&(o.closable=e.closable),o}function fe(e,o={}){const i=se(o),n=t.reactive([]),r=t.ref(null),d=t.shallowRef(),m=t.ref(null),s=t.computed(()=>n.filter(l=>l.alive).map(l=>l.id));let f=!1;function T(l){const c=typeof l.matched=="object"?l:R(e,l);return{key:C(c),fullPath:c.fullPath,alive:M(c,i.keepAlive),reusable:L(c,!1),matched:c}}function P(l){const c=C(l);let u=n.find(h=>h.id===c);return u?(u.fullPath=l.fullPath,u.to=l.fullPath,u.matched=l,u.alive=M(l,i.keepAlive),u.reusable=L(l,u.reusable),Object.assign(u,H(l)),u):(u=K(l,{},i.keepAlive),N(n,u,i.appendPosition,r.value),Q(n,i.maxAlive,r.value),u)}async function B(l,c=!1,u=!0){const h=R(e,l),w=C(h),a=r.value===w;u==="sameTab"&&(u=a),u&&await g(w,!0),await e[c?"replace":"push"](h),a&&await E()}function $(l){const c=n.findIndex(h=>h.id===l),u=n[c]||n[c-1]||n[0];return u?u.to:i.defaultRoute}async function v(l=r.value,c={}){if(l){if(!c.force&&i.keepLastTab&&n.length===1)throw new Error("[RouterTabs] Unable to close the final tab when keepLastTab is true.");if(await V(l,{force:c.force}),c.redirect!==null)if(r.value===l){const u=c.redirect??$(l);u&&await e.replace(u)}else c.redirect&&await e.replace(c.redirect)}}async function V(l,c={}){const u=n.findIndex(h=>h.id===l);u!==-1&&(n.splice(u,1),m.value===l&&(m.value=null),r.value===l&&(r.value=null,d.value=void 0))}async function g(l=r.value??void 0,c=!1){l&&(m.value=l,await t.nextTick(),c||await t.nextTick(),m.value=null)}async function O(l=!1){for(const c of n)await g(c.id,l)}async function F(l=i.defaultRoute){n.splice(0,n.length),r.value=null,d.value=void 0;for(const c of i.initialTabs){const u=R(e,c.to),h=K(u,c,i.keepAlive);n.push(h)}await e.replace(l)}async function E(){const l=r.value;l&&await g(l,!0)}function Y(l){return typeof l.matched=="object"?C(l):C(R(e,l))}function q(){const l=n.find(c=>c.id===r.value);return{tabs:n.map(ce),active:l?l.to:null}}async function S(l){f=!0,n.splice(0,n.length),r.value=null,d.value=void 0;const c=l?.tabs??[];for(const h of c)try{const w=R(e,h.to),a=ue(h),p=K(w,a,i.keepAlive);N(n,p,"last",null)}catch{}f=!1;const u=l?.active??c[c.length-1]?.to??i.defaultRoute;if(u)try{await e.replace(u)}catch{}}return t.watch(()=>e.currentRoute.value,l=>{if(f)return;const c=P(l);r.value=c.id,d.value=c,Q(n,i.maxAlive,r.value)},{immediate:!0}),i.initialTabs.length&&i.initialTabs.forEach(l=>{const c=R(e,l.to),u=K(c,l,i.keepAlive);N(n,u,"last",null)}),{options:i,tabs:n,activeId:r,current:d,includeKeys:s,refreshingKey:m,openTab:B,closeTab:v,removeTab:V,refreshTab:g,refreshAll:O,reset:F,reload:E,getRouteKey:Y,matchRoute:T,snapshot:q,hydrate:S}}function W(e){return e?typeof e=="string"?{name:e}:e:{}}const A=Symbol("RouterTabsContext"),x="router-tabs:snapshot";function j(e={}){const{optional:o=!1}=e,i=t.inject(A,null);if(i)return i;const n=t.inject("$tabs",null);if(n)return n;const d=t.getCurrentInstance()?.appContext.config.globalProperties.$tabs;if(d)return d;if(!o)throw new Error("[RouterTabs] useRouterTabs must be used within <router-tab>.");return null}const de=864e5;function pe(e){if(typeof document>"u")return null;const o=`${encodeURIComponent(e)}=`,i=document.cookie?document.cookie.split("; "):[];for(const n of i)if(n.startsWith(o))return decodeURIComponent(n.slice(o.length));return null}function X(e,o,i){if(typeof document>"u")return;const{expiresInDays:n=7,path:r="/",domain:d,secure:m,sameSite:s="lax"}=i,f=[`${encodeURIComponent(e)}=${encodeURIComponent(o)}`];if(n!==1/0){const T=new Date(Date.now()+n*de).toUTCString();f.push(`Expires=${T}`)}r&&f.push(`Path=${r}`),d&&f.push(`Domain=${d}`),m&&f.push("Secure"),s&&f.push(`SameSite=${s.charAt(0).toUpperCase()}${s.slice(1)}`),document.cookie=f.join("; ")}function Z(e,o){if(typeof document>"u")return;const{path:i="/",domain:n}=o,r=[`${encodeURIComponent(e)}=`];r.push("Expires=Thu, 01 Jan 1970 00:00:01 GMT"),i&&r.push(`Path=${i}`),n&&r.push(`Domain=${n}`),document.cookie=r.join("; ")}const me=e=>JSON.stringify(e??null),be=e=>{if(!e)return null;try{return JSON.parse(e)}catch{return null}};function D(e={}){const{cookieKey:o=x,serialize:i=me,deserialize:n=be}=e,r=j({optional:!0}),d=t.ref(!0),m=s=>{t.onMounted(async()=>{const f=n(pe(o));if(f&&f.tabs?.length)try{d.value=!0,await s.hydrate(f)}finally{d.value=!1}else try{d.value=!0;const P=e.fallbackRoute??s.options.defaultRoute;await s.reset(P)}finally{d.value=!1}const T=s.snapshot();T.tabs.length?X(o,i(T),e):Z(o,e),d.value=!1}),t.watch(()=>({tabs:s.tabs.map(f=>({to:f.to,title:f.title,tips:f.tips,icon:f.icon,tabClass:f.tabClass,closable:f.closable})),active:s.activeId.value}),()=>{if(d.value)return;const f=s.snapshot();f.tabs.length?X(o,i(f),e):Z(o,e)},{deep:!0})};r?m(r):t.onMounted(()=>{const s=j({optional:!0});s&&m(s)})}const he=t.defineComponent({name:"RouterTab",components:{RouterView:le.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:x},persistence:{type:Object,default:null}},setup(e){const o=t.getCurrentInstance();if(!o)throw new Error("[RouterTab] component must be used within a Vue application context.");const i=o.appContext.app.config.globalProperties.$router;if(!i)throw new Error("[RouterTab] Vue Router is required. Make sure to call app.use(router) before RouterTab.");const n=fe(i,{initialTabs:e.tabs,keepAlive:e.keepAlive,maxAlive:e.maxAlive,keepLastTab:e.keepLastTab,appendPosition:e.append,defaultRoute:e.defaultPage});t.provide(A,n),o.appContext.config.globalProperties.$tabs=n;const r=t.computed(()=>!!o?.slots?.default);if(e.cookieKey!==null||e.persistence){const a={...e.persistence??{}};e.cookieKey!==null?a.cookieKey=e.cookieKey||x:a.cookieKey||(a.cookieKey=x),D(a)}const d=t.computed(()=>W(e.tabTransition)),m=t.computed(()=>W(e.pageTransition)),s=t.reactive({visible:!1,target:null,position:{x:0,y:0}}),f=["refresh","refreshAll","close","closeLefts","closeRights","closeOthers"];function T(a){return n.tabs.findIndex(p=>p.id===a)}function P(a){const p=T(a.id);return p>0?n.tabs.slice(0,p):[]}function B(a){const p=T(a.id);return p>-1?n.tabs.slice(p+1):[]}function $(a){return n.tabs.filter(p=>p.id!==a.id)}async function v(a,p){const y=a.filter(k=>k.closable!==!1);if(y.length){for(const k of y)n.activeId.value===k.id?await n.closeTab(k.id,{redirect:p.to,force:!0}):await n.removeTab(k.id,{force:!0});n.activeId.value!==p.id&&await n.openTab(p.to,!0,!1)}}const V={refresh:{label:"Refresh",handler:async({target:a})=>{await n.refreshTab(a.id,!0)}},refreshAll:{label:"Refresh All",handler:async()=>{await n.refreshAll(!0)}},close:{label:"Close",handler:async({target:a})=>{await n.closeTab(a.id)},enable:({target:a})=>S(a)},closeLefts:{label:"Close to the Left",handler:async({target:a})=>{await v(P(a),a)},enable:({target:a})=>P(a).some(p=>p.closable!==!1)},closeRights:{label:"Close to the Right",handler:async({target:a})=>{await v(B(a),a)},enable:({target:a})=>B(a).some(p=>p.closable!==!1)},closeOthers:{label:"Close Others",handler:async({target:a})=>{await v($(a),a)},enable:({target:a})=>$(a).some(p=>p.closable!==!1)}};function g(){s.visible=!1,s.target=null}function O(a,p){e.contextmenu&&(s.visible=!0,s.target=a,s.position.x=p.clientX,s.position.y=p.clientY,document.addEventListener("click",g,{once:!0}))}function F(a,p){const y=typeof a=="string"?{id:a}:a,k=V[y.id],Ve=y.label??k?.label??String(y.id),G=y.visible??k?.visible??!0;if(!(typeof G=="function"?G(p):G!==!1))return null;const J=y.enable??k?.enable??!0,Me=typeof J=="function"?J(p):J!==!1,ae=y.handler??k?.handler;if(!ae)return null;const Le=async()=>{await Promise.resolve(ae(p))};return{id:String(y.id),label:Ve,disabled:!Me,action:Le}}const E=t.computed(()=>{if(!s.visible||!s.target||e.contextmenu===!1)return[];const a=Array.isArray(e.contextmenu)?e.contextmenu:f,p={target:s.target,controller:n};return a.map(y=>F(y,p)).filter(y=>!!y)});async function Y(a){a.disabled||(g(),await a.action())}function q(a){return typeof a.title=="string"?a.title:Array.isArray(a.title)&&a.title.length?String(a.title[0]):a.fullPath}function S(a){return!(a.closable===!1||n.options.keepLastTab&&n.tabs.length<=1)}async function l(a){await n.closeTab(a.id)}function c(a){n.activeId.value!==a.id&&n.openTab(a.to,!1)}function u(a){return["router-tab__item",{"is-active":n.activeId.value===a.id,"is-closable":S(a)},a.tabClass]}function h(a){return n.refreshingKey.value===n.getRouteKey(a)}t.onMounted(()=>{document.addEventListener("keydown",g)}),t.onBeforeUnmount(()=>{document.removeEventListener("keydown",g),o.appContext.config.globalProperties.$tabs=null}),t.watch(()=>e.keepAlive,a=>{n.options.keepAlive=a}),t.watch(()=>n.activeId.value,()=>g()),t.watch(()=>e.contextmenu,a=>{a||g()}),t.watch(()=>E.value.length,a=>{s.visible&&a===0&&g()});const w=n.includeKeys;return{controller:n,tabs:n.tabs,includeKeys:w,tabTransitionProps:d,pageTransitionProps:m,buildTabClass:u,activate:c,close:l,context:s,menuItems:E,handleMenuAction:Y,showContextMenu:O,hideContextMenu:g,tabTitle:q,isClosable:S,isRefreshing:h,hasCustomSlot:r}}}),ye=(e,o)=>{const i=e.__vccOpts||e;for(const[n,r]of o)i[n]=r;return i},ge={class:"router-tab"},ke={class:"router-tab__header"},Te={class:"router-tab__slot-start"},we={class:"router-tab__scroll"},Re=["onClick","onAuxclick","onContextmenu"],Ce=["title"],Pe=["onClick"],Ae={class:"router-tab__slot-end"},_e={class:"router-tab__container"},ve=["aria-disabled","onClick"];function Ee(e,o,i,n,r,d){const m=t.resolveComponent("RouterView");return t.openBlock(),t.createElementBlock("div",ge,[t.createElementVNode("header",ke,[t.createElementVNode("div",Te,[t.renderSlot(e.$slots,"start")]),t.createElementVNode("div",we,[t.createVNode(t.TransitionGroup,t.mergeProps({tag:"ul",class:"router-tab__nav"},e.tabTransitionProps),{default:t.withCtx(()=>[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(e.tabs,s=>(t.openBlock(),t.createElementBlock("li",{key:s.id,class:t.normalizeClass(e.buildTabClass(s)),onClick:f=>e.activate(s),onAuxclick:t.withModifiers(f=>e.close(s),["middle","prevent"]),onContextmenu:t.withModifiers(f=>e.showContextMenu(s,f),["prevent"])},[t.createElementVNode("span",{class:"router-tab__item-title",title:e.tabTitle(s)},[s.icon?(t.openBlock(),t.createElementBlock("i",{key:0,class:t.normalizeClass(["router-tab__item-icon",s.icon])},null,2)):t.createCommentVNode("",!0),t.createTextVNode(" "+t.toDisplayString(e.tabTitle(s)),1)],8,Ce),e.isClosable(s)?(t.openBlock(),t.createElementBlock("a",{key:0,class:"router-tab__item-close",type:"button",onClick:t.withModifiers(f=>e.close(s),["stop"])},null,8,Pe)):t.createCommentVNode("",!0)],42,Re))),128))]),_:1},16)]),t.createElementVNode("div",Ae,[t.renderSlot(e.$slots,"end")])]),t.createElementVNode("div",_e,[t.createVNode(m,null,{default:t.withCtx(s=>[e.hasCustomSlot?t.renderSlot(e.$slots,"default",t.normalizeProps(t.mergeProps({key:0},{...s,controller:e.controller}))):(t.openBlock(),t.createElementBlock(t.Fragment,{key:1},[t.createVNode(t.Transition,t.mergeProps(e.pageTransitionProps,{appear:""}),{default:t.withCtx(()=>[e.controller.options.keepAlive?(t.openBlock(),t.createBlock(t.KeepAlive,{key:0,include:e.includeKeys,max:e.controller.options.maxAlive||void 0},[e.isRefreshing(s.route)?t.createCommentVNode("",!0):(t.openBlock(),t.createBlock(t.resolveDynamicComponent(s.Component),{key:e.controller.getRouteKey(s.route),class:"router-tab-page"}))],1032,["include","max"])):t.createCommentVNode("",!0)]),_:2},1040),t.createVNode(t.Transition,t.mergeProps(e.pageTransitionProps,{appear:""}),{default:t.withCtx(()=>[!e.controller.options.keepAlive||e.isRefreshing(s.route)?(t.openBlock(),t.createBlock(t.resolveDynamicComponent(s.Component),{key:e.controller.getRouteKey(s.route)+(e.isRefreshing(s.route)?"-refresh":""),class:"router-tab-page"})):t.createCommentVNode("",!0)]),_:2},1040)],64))]),_:3})]),e.context.visible&&e.context.target?(t.openBlock(),t.createElementBlock("div",{key:0,class:"router-tab__contextmenu",style:t.normalizeStyle({left:e.context.position.x+"px",top:e.context.position.y+"px"})},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(e.menuItems,s=>(t.openBlock(),t.createElementBlock("a",{key:s.id,class:"router-tab__contextmenu-item","aria-disabled":s.disabled,onClick:t.withModifiers(f=>e.handleMenuAction(s),["prevent"])},t.toDisplayString(s.label),9,ve))),128))],4)):t.createCommentVNode("",!0)])}const U=ye(he,[["render",Ee]]),Se={class:"router-tabs","aria-hidden":"true"},I=t.defineComponent({name:"RouterTabs",__name:"RouterTabs",props:{cookieKey:{},expiresInDays:{},path:{},domain:{},secure:{type:Boolean},sameSite:{},serialize:{type:Function},deserialize:{type:Function},fallbackRoute:{}},setup(e){return D(e),(i,n)=>(t.openBlock(),t.createElementBlock("span",Se))}}),ee="theme-style",te="theme-primary-color",Ke="system",xe="#635bff",Ie="(prefers-color-scheme: dark)";let _=null;function ne(e){typeof document>"u"||(document.documentElement.style.setProperty("--theme-primary",e),document.documentElement.style.setProperty("--router-tab-primary",e))}function oe(e){if(typeof document>"u")return;const o=document.documentElement,i=window.matchMedia(Ie),n=()=>{o.dataset.theme=i.matches?"dark":"light"};_&&(i.removeEventListener("change",_),_=null),e==="system"?(n(),_=()=>n(),i.addEventListener("change",_)):o.dataset.theme=e}function ie(e={}){if(typeof window>"u")return;const{styleKey:o=ee,primaryKey:i=te,defaultStyle:n=Ke,defaultPrimary:r=xe}=e,d=window.localStorage.getItem(o)??n,m=window.localStorage.getItem(i)??r;oe(d),ne(m)}function Be(e,o){if(typeof window>"u")return;const i=o?.styleKey??ee;window.localStorage.setItem(i,e),oe(e)}function $e(e,o){if(typeof window>"u")return;const i=o?.primaryKey??te;window.localStorage.setItem(i,e),ne(e)}const z={install(e){if(z._installed)return;z._installed=!0,ie();const o=U.name||"RouterTab",i=I.name||"RouterTabs";e.component(o,U),e.component(i,I),i!=="router-tabs"&&e.component("router-tabs",I),Object.defineProperty(e.config.globalProperties,"$tabs",{configurable:!0,enumerable:!1,get(){return e._context.provides[A]},set(n){n&&e.provide(A,n)}})}};b.RouterTab=U,b.RouterTabs=I,b.default=z,b.initRouterTabsTheme=ie,b.routerTabsKey=A,b.setRouterTabsPrimary=$e,b.setRouterTabsTheme=Be,b.useRouterTabs=j,b.useRouterTabsPersistence=D,Object.defineProperties(b,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
|
1
|
+
(function(b,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue"),require("vue-router")):typeof define=="function"&&define.amd?define(["exports","vue","vue-router"],t):(b=typeof globalThis<"u"?globalThis:b||self,t(b["vue3-router-tab"]={},b.Vue,b.VueRouter))})(this,(function(b,t,le){"use strict";function se(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 R(e,o){const i=e.resolve(o);if(!i||!i.matched.length)throw new Error(`[RouterTabs] Unable to resolve route: ${String(o)}`);return i}const re={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 C(e){const o=e.meta?.key;if(typeof o=="function"){const i=o(e);if(typeof i=="string"&&i.length)return i}else if(typeof o=="string"&&o.length){const i=re[o.toLowerCase()];return i?i(e):o}return e.fullPath}function M(e,o){const i=e.meta?.keepAlive;return typeof i=="boolean"?i:o}function L(e,o){const i=e.meta?.reuse;return typeof i=="boolean"?i:o}function H(e){const o=e.meta??{},i={};return"title"in o&&(i.title=o.title),"tips"in o&&(i.tips=o.tips),"icon"in o&&(i.icon=o.icon),"closable"in o&&(i.closable=o.closable),"tabClass"in o&&(i.tabClass=o.tabClass),"target"in o&&(i.target=o.target),"href"in o&&(i.href=o.href),i}function K(e,o,i){const n=H(e);return{id:C(e),to:e.fullPath,fullPath:e.fullPath,matched:e,alive:M(e,i),reusable:L(e,!1),closable:n.closable??!0,...n,...o}}function N(e,o,i,n){if(!e.find(d=>d.id===o.id)){if(i==="next"&&n){const d=e.findIndex(m=>m.id===n);if(d>-1){e.splice(d+1,0,o);return}}e.push(o)}}function Q(e,o,i){if(!o||o<=0)return;const n=e.filter(r=>r.alive);for(;n.length>o;){const r=n.shift();if(!r||r.id===i)continue;const d=e.findIndex(m=>m.id===r.id);d>-1&&(e[d].alive=!1)}}function ce(e){return{to:e.to,title:e.title,tips:e.tips,icon:e.icon,tabClass:e.tabClass,closable:e.closable}}function ue(e){const o={};return"title"in e&&(o.title=e.title),"tips"in e&&(o.tips=e.tips),"icon"in e&&(o.icon=e.icon),"tabClass"in e&&(o.tabClass=e.tabClass),"closable"in e&&(o.closable=e.closable),o}function fe(e,o={}){const i=se(o),n=t.reactive([]),r=t.ref(null),d=t.shallowRef(),m=t.ref(null),s=t.computed(()=>n.filter(l=>l.alive).map(l=>l.id));let f=!1;function T(l){const c=typeof l.matched=="object"?l:R(e,l);return{key:C(c),fullPath:c.fullPath,alive:M(c,i.keepAlive),reusable:L(c,!1),matched:c}}function P(l){const c=C(l);let u=n.find(h=>h.id===c);return u?(u.fullPath=l.fullPath,u.to=l.fullPath,u.matched=l,u.alive=M(l,i.keepAlive),u.reusable=L(l,u.reusable),Object.assign(u,H(l)),u):(u=K(l,{},i.keepAlive),N(n,u,i.appendPosition,r.value),Q(n,i.maxAlive,r.value),u)}async function B(l,c=!1,u=!0){const h=R(e,l),w=C(h),a=r.value===w;u==="sameTab"&&(u=a),u&&await g(w,!0),await e[c?"replace":"push"](h),a&&await E()}function $(l){const c=n.findIndex(h=>h.id===l),u=n[c]||n[c-1]||n[0];return u?u.to:i.defaultRoute}async function v(l=r.value,c={}){if(l){if(!c.force&&i.keepLastTab&&n.length===1)throw new Error("[RouterTabs] Unable to close the final tab when keepLastTab is true.");if(await V(l,{force:c.force}),c.redirect!==null)if(r.value===l){const u=c.redirect??$(l);u&&await e.replace(u)}else c.redirect&&await e.replace(c.redirect)}}async function V(l,c={}){const u=n.findIndex(h=>h.id===l);u!==-1&&(n.splice(u,1),m.value===l&&(m.value=null),r.value===l&&(r.value=null,d.value=void 0))}async function g(l=r.value??void 0,c=!1){l&&(m.value=l,await t.nextTick(),c||await t.nextTick(),m.value=null)}async function O(l=!1){for(const c of n)await g(c.id,l)}async function F(l=i.defaultRoute){n.splice(0,n.length),r.value=null,d.value=void 0;for(const c of i.initialTabs){const u=R(e,c.to),h=K(u,c,i.keepAlive);n.push(h)}await e.replace(l)}async function E(){const l=r.value;l&&await g(l,!0)}function Y(l){return typeof l.matched=="object"?C(l):C(R(e,l))}function q(){const l=n.find(c=>c.id===r.value);return{tabs:n.map(ce),active:l?l.to:null}}async function S(l){f=!0,n.splice(0,n.length),r.value=null,d.value=void 0;const c=l?.tabs??[];for(const h of c)try{const w=R(e,h.to),a=ue(h),p=K(w,a,i.keepAlive);N(n,p,"last",null)}catch{}f=!1;const u=l?.active??c[c.length-1]?.to??i.defaultRoute;if(u)try{await e.replace(u)}catch{}}return t.watch(()=>e.currentRoute.value,l=>{if(f)return;const c=P(l);r.value=c.id,d.value=c,Q(n,i.maxAlive,r.value)},{immediate:!0}),i.initialTabs.length&&i.initialTabs.forEach(l=>{const c=R(e,l.to),u=K(c,l,i.keepAlive);N(n,u,"last",null)}),{options:i,tabs:n,activeId:r,current:d,includeKeys:s,refreshingKey:m,openTab:B,closeTab:v,removeTab:V,refreshTab:g,refreshAll:O,reset:F,reload:E,getRouteKey:Y,matchRoute:T,snapshot:q,hydrate:S}}function W(e){return e?typeof e=="string"?{name:e}:e:{}}const A=Symbol("RouterTabsContext"),x="router-tabs:snapshot";function j(e={}){const{optional:o=!1}=e,i=t.inject(A,null);if(i)return i;const n=t.inject("$tabs",null);if(n)return n;const d=t.getCurrentInstance()?.appContext.config.globalProperties.$tabs;if(d)return d;if(!o)throw new Error("[RouterTabs] useRouterTabs must be used within <router-tab>.");return null}const de=864e5;function pe(e){if(typeof document>"u")return null;const o=`${encodeURIComponent(e)}=`,i=document.cookie?document.cookie.split("; "):[];for(const n of i)if(n.startsWith(o))return decodeURIComponent(n.slice(o.length));return null}function X(e,o,i){if(typeof document>"u")return;const{expiresInDays:n=7,path:r="/",domain:d,secure:m,sameSite:s="lax"}=i,f=[`${encodeURIComponent(e)}=${encodeURIComponent(o)}`];if(n!==1/0){const T=new Date(Date.now()+n*de).toUTCString();f.push(`Expires=${T}`)}r&&f.push(`Path=${r}`),d&&f.push(`Domain=${d}`),m&&f.push("Secure"),s&&f.push(`SameSite=${s.charAt(0).toUpperCase()}${s.slice(1)}`),document.cookie=f.join("; ")}function Z(e,o){if(typeof document>"u")return;const{path:i="/",domain:n}=o,r=[`${encodeURIComponent(e)}=`];r.push("Expires=Thu, 01 Jan 1970 00:00:01 GMT"),i&&r.push(`Path=${i}`),n&&r.push(`Domain=${n}`),document.cookie=r.join("; ")}const me=e=>JSON.stringify(e??null),be=e=>{if(!e)return null;try{return JSON.parse(e)}catch{return null}};function D(e={}){const{cookieKey:o=x,serialize:i=me,deserialize:n=be}=e,r=j({optional:!0}),d=t.ref(!0),m=s=>{t.onMounted(async()=>{const f=n(pe(o));if(f&&f.tabs?.length)try{d.value=!0,await s.hydrate(f)}finally{d.value=!1}else try{d.value=!0;const P=e.fallbackRoute??s.options.defaultRoute;await s.reset(P)}finally{d.value=!1}const T=s.snapshot();T.tabs.length?X(o,i(T),e):Z(o,e),d.value=!1}),t.watch(()=>({tabs:s.tabs.map(f=>({to:f.to,title:f.title,tips:f.tips,icon:f.icon,tabClass:f.tabClass,closable:f.closable})),active:s.activeId.value}),()=>{if(d.value)return;const f=s.snapshot();f.tabs.length?X(o,i(f),e):Z(o,e)},{deep:!0})};r?m(r):t.onMounted(()=>{const s=j({optional:!0});s&&m(s)})}const he=t.defineComponent({name:"RouterTab",components:{RouterView:le.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:x},persistence:{type:Object,default:null}},setup(e){const o=t.getCurrentInstance();if(!o)throw new Error("[RouterTab] component must be used within a Vue application context.");const i=o.appContext.app.config.globalProperties.$router;if(!i)throw new Error("[RouterTab] Vue Router is required. Make sure to call app.use(router) before RouterTab.");const n=fe(i,{initialTabs:e.tabs,keepAlive:e.keepAlive,maxAlive:e.maxAlive,keepLastTab:e.keepLastTab,appendPosition:e.append,defaultRoute:e.defaultPage});t.provide(A,n),o.appContext.config.globalProperties.$tabs=n;const r=t.computed(()=>!!o?.slots?.default);if(e.cookieKey!==null||e.persistence){const a={...e.persistence??{}};e.cookieKey!==null?a.cookieKey=e.cookieKey||x:a.cookieKey||(a.cookieKey=x),D(a)}const d=t.computed(()=>W(e.tabTransition)),m=t.computed(()=>W(e.pageTransition)),s=t.reactive({visible:!1,target:null,position:{x:0,y:0}}),f=["refresh","refreshAll","close","closeLefts","closeRights","closeOthers"];function T(a){return n.tabs.findIndex(p=>p.id===a)}function P(a){const p=T(a.id);return p>0?n.tabs.slice(0,p):[]}function B(a){const p=T(a.id);return p>-1?n.tabs.slice(p+1):[]}function $(a){return n.tabs.filter(p=>p.id!==a.id)}async function v(a,p){const y=a.filter(k=>k.closable!==!1);if(y.length){for(const k of y)n.activeId.value===k.id?await n.closeTab(k.id,{redirect:p.to,force:!0}):await n.removeTab(k.id,{force:!0});n.activeId.value!==p.id&&await n.openTab(p.to,!0,!1)}}const V={refresh:{label:"Refresh",handler:async({target:a})=>{await n.refreshTab(a.id,!0)}},refreshAll:{label:"Refresh All",handler:async()=>{await n.refreshAll(!0)}},close:{label:"Close",handler:async({target:a})=>{await n.closeTab(a.id)},enable:({target:a})=>S(a)},closeLefts:{label:"Close to the Left",handler:async({target:a})=>{await v(P(a),a)},enable:({target:a})=>P(a).some(p=>p.closable!==!1)},closeRights:{label:"Close to the Right",handler:async({target:a})=>{await v(B(a),a)},enable:({target:a})=>B(a).some(p=>p.closable!==!1)},closeOthers:{label:"Close Others",handler:async({target:a})=>{await v($(a),a)},enable:({target:a})=>$(a).some(p=>p.closable!==!1)}};function g(){s.visible=!1,s.target=null}function O(a,p){e.contextmenu&&(s.visible=!0,s.target=a,s.position.x=p.clientX,s.position.y=p.clientY,document.addEventListener("click",g,{once:!0}))}function F(a,p){const y=typeof a=="string"?{id:a}:a,k=V[y.id],Ve=y.label??k?.label??String(y.id),G=y.visible??k?.visible??!0;if(!(typeof G=="function"?G(p):G!==!1))return null;const J=y.enable??k?.enable??!0,Me=typeof J=="function"?J(p):J!==!1,ae=y.handler??k?.handler;if(!ae)return null;const Le=async()=>{await Promise.resolve(ae(p))};return{id:String(y.id),label:Ve,disabled:!Me,action:Le}}const E=t.computed(()=>{if(!s.visible||!s.target||e.contextmenu===!1)return[];const a=Array.isArray(e.contextmenu)?e.contextmenu:f,p={target:s.target,controller:n};return a.map(y=>F(y,p)).filter(y=>!!y)});async function Y(a){a.disabled||(g(),await a.action())}function q(a){return typeof a.title=="string"?a.title:Array.isArray(a.title)&&a.title.length?String(a.title[0]):a.fullPath}function S(a){return!(a.closable===!1||n.options.keepLastTab&&n.tabs.length<=1)}async function l(a){await n.closeTab(a.id)}function c(a){n.activeId.value!==a.id&&n.openTab(a.to,!1)}function u(a){return["router-tab__item",{"is-active":n.activeId.value===a.id,"is-closable":S(a)},a.tabClass]}function h(a){return n.refreshingKey.value===n.getRouteKey(a)}t.onMounted(()=>{document.addEventListener("keydown",g)}),t.onBeforeUnmount(()=>{document.removeEventListener("keydown",g),o.appContext.config.globalProperties.$tabs=null}),t.watch(()=>e.keepAlive,a=>{n.options.keepAlive=a}),t.watch(()=>n.activeId.value,()=>g()),t.watch(()=>e.contextmenu,a=>{a||g()}),t.watch(()=>E.value.length,a=>{s.visible&&a===0&&g()});const w=n.includeKeys;return{controller:n,tabs:n.tabs,includeKeys:w,tabTransitionProps:d,pageTransitionProps:m,buildTabClass:u,activate:c,close:l,context:s,menuItems:E,handleMenuAction:Y,showContextMenu:O,hideContextMenu:g,tabTitle:q,isClosable:S,isRefreshing:h,hasCustomSlot:r}}}),ye=(e,o)=>{const i=e.__vccOpts||e;for(const[n,r]of o)i[n]=r;return i},ge={class:"router-tab"},ke={class:"router-tab__header"},Te={class:"router-tab__slot-start"},we={class:"router-tab__scroll"},Re=["onClick","onAuxclick","onContextmenu"],Ce=["title"],Pe=["onClick"],Ae={class:"router-tab__slot-end"},_e={class:"router-tab__container"},ve=["aria-disabled","onClick"];function Ee(e,o,i,n,r,d){const m=t.resolveComponent("RouterView");return t.openBlock(),t.createElementBlock("div",ge,[t.createElementVNode("header",ke,[t.createElementVNode("div",Te,[t.renderSlot(e.$slots,"start")]),t.createElementVNode("div",we,[t.createVNode(t.TransitionGroup,t.mergeProps({tag:"ul",class:"router-tab__nav"},e.tabTransitionProps),{default:t.withCtx(()=>[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(e.tabs,s=>(t.openBlock(),t.createElementBlock("li",{key:s.id,class:t.normalizeClass(e.buildTabClass(s)),onClick:f=>e.activate(s),onAuxclick:t.withModifiers(f=>e.close(s),["middle","prevent"]),onContextmenu:t.withModifiers(f=>e.showContextMenu(s,f),["prevent"])},[t.createElementVNode("span",{class:"router-tab__item-title",title:e.tabTitle(s)},[s.icon?(t.openBlock(),t.createElementBlock("i",{key:0,class:t.normalizeClass(["router-tab__item-icon",s.icon])},null,2)):t.createCommentVNode("",!0),t.createTextVNode(" "+t.toDisplayString(e.tabTitle(s)),1)],8,Ce),e.isClosable(s)?(t.openBlock(),t.createElementBlock("a",{key:0,class:"router-tab__item-close",type:"button",onClick:t.withModifiers(f=>e.close(s),["stop"])},null,8,Pe)):t.createCommentVNode("",!0)],42,Re))),128))]),_:1},16)]),t.createElementVNode("div",Ae,[t.renderSlot(e.$slots,"end")])]),t.createElementVNode("div",_e,[t.createVNode(m,null,{default:t.withCtx(s=>[e.hasCustomSlot?t.renderSlot(e.$slots,"default",t.normalizeProps(t.mergeProps({key:0},{...s,controller:e.controller}))):(t.openBlock(),t.createElementBlock(t.Fragment,{key:1},[t.createVNode(t.Transition,t.mergeProps(e.pageTransitionProps,{appear:""}),{default:t.withCtx(()=>[e.controller.options.keepAlive?(t.openBlock(),t.createBlock(t.KeepAlive,{key:0,include:e.includeKeys,max:e.controller.options.maxAlive||void 0},[e.isRefreshing(s.route)?t.createCommentVNode("",!0):(t.openBlock(),t.createBlock(t.resolveDynamicComponent(s.Component),{key:e.controller.getRouteKey(s.route),class:"router-tab-page"}))],1032,["include","max"])):t.createCommentVNode("",!0)]),_:2},1040),t.createVNode(t.Transition,t.mergeProps(e.pageTransitionProps,{appear:""}),{default:t.withCtx(()=>[!e.controller.options.keepAlive||e.isRefreshing(s.route)?(t.openBlock(),t.createBlock(t.resolveDynamicComponent(s.Component),{key:e.controller.getRouteKey(s.route)+(e.isRefreshing(s.route)?"-refresh":""),class:"router-tab-page"})):t.createCommentVNode("",!0)]),_:2},1040)],64))]),_:3})]),e.context.visible&&e.context.target?(t.openBlock(),t.createElementBlock("div",{key:0,class:"router-tab__contextmenu",style:t.normalizeStyle({left:e.context.position.x+"px",top:e.context.position.y+"px"})},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(e.menuItems,s=>(t.openBlock(),t.createElementBlock("a",{key:s.id,class:"router-tab__contextmenu-item","aria-disabled":s.disabled,onClick:t.withModifiers(f=>e.handleMenuAction(s),["prevent"])},t.toDisplayString(s.label),9,ve))),128))],4)):t.createCommentVNode("",!0)])}const U=ye(he,[["render",Ee]]),Se={class:"router-tabs","aria-hidden":"true"},I=t.defineComponent({name:"RouterTabs",__name:"RouterTabs",props:{cookieKey:{},expiresInDays:{},path:{},domain:{},secure:{type:Boolean},sameSite:{},serialize:{type:Function},deserialize:{type:Function},fallbackRoute:{}},setup(e){return D(e),(i,n)=>(t.openBlock(),t.createElementBlock("span",Se))}}),ee="tab-theme-style",te="tab-theme-primary-color",Ke="system",xe="#635bff",Ie="(prefers-color-scheme: dark)";let _=null;function ne(e){typeof document>"u"||(document.documentElement.style.setProperty("--theme-primary",e),document.documentElement.style.setProperty("--router-tab-primary",e))}function oe(e){if(typeof document>"u")return;const o=document.documentElement,i=window.matchMedia(Ie),n=()=>{o.dataset.theme=i.matches?"dark":"light"};_&&(i.removeEventListener("change",_),_=null),e==="system"?(n(),_=()=>n(),i.addEventListener("change",_)):o.dataset.theme=e}function ie(e={}){if(typeof window>"u")return;const{styleKey:o=ee,primaryKey:i=te,defaultStyle:n=Ke,defaultPrimary:r=xe}=e,d=window.localStorage.getItem(o)??n,m=window.localStorage.getItem(i)??r;oe(d),ne(m)}function Be(e,o){if(typeof window>"u")return;const i=o?.styleKey??ee;window.localStorage.setItem(i,e),oe(e)}function $e(e,o){if(typeof window>"u")return;const i=o?.primaryKey??te;window.localStorage.setItem(i,e),ne(e)}const z={install(e){if(z._installed)return;z._installed=!0,ie();const o=U.name||"RouterTab",i=I.name||"RouterTabs";e.component(o,U),e.component(i,I),i!=="router-tabs"&&e.component("router-tabs",I),Object.defineProperty(e.config.globalProperties,"$tabs",{configurable:!0,enumerable:!1,get(){return e._context.provides[A]},set(n){n&&e.provide(A,n)}})}};b.RouterTab=U,b.RouterTabs=I,b.default=z,b.initRouterTabsTheme=ie,b.routerTabsKey=A,b.setRouterTabsPrimary=$e,b.setRouterTabsTheme=Be,b.useRouterTabs=j,b.useRouterTabsPersistence=D,Object.defineProperties(b,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
package/lib/scss/index.scss
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
@use "sass:math";
|
|
2
|
-
@use "sass:color";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
$
|
|
6
|
-
$
|
|
7
|
-
$
|
|
8
|
-
$
|
|
9
|
-
$default-dark-text: #e2e8f0;
|
|
10
|
-
$default-dark-border: rgba(148, 163, 184, 0.35);
|
|
3
|
+
// Fallback palette (overridden by CSS vars when present)
|
|
4
|
+
$primary-fallback: #635bff;
|
|
5
|
+
$light-bg: #ffffff;
|
|
6
|
+
$light-text: #1e293b;
|
|
7
|
+
$light-border: rgba(15, 23, 42, 0.08);
|
|
11
8
|
|
|
12
9
|
$font-size: 14px;
|
|
13
10
|
$tab-trans: all 0.3s ease-in-out;
|
|
@@ -16,48 +13,23 @@ $tab-padding: 20px;
|
|
|
16
13
|
$close-icon-margin: 4px;
|
|
17
14
|
$close-icon-size: 13px;
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
--router-tab-background: #{$default-bg};
|
|
23
|
-
--router-tab-foreground: #{$default-text};
|
|
24
|
-
--router-tab-border: #{$default-border};
|
|
25
|
-
--router-tab-header-bg: #{$default-bg};
|
|
26
|
-
color-scheme: light;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
:root[data-theme='light'] {
|
|
30
|
-
color-scheme: light;
|
|
31
|
-
--router-tab-background: #{$default-bg};
|
|
32
|
-
--router-tab-foreground: #{$default-text};
|
|
33
|
-
--router-tab-border: #{$default-border};
|
|
34
|
-
--router-tab-header-bg: #{$default-bg};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
:root[data-theme='dark'] {
|
|
38
|
-
color-scheme: dark;
|
|
39
|
-
--router-tab-background: #{$default-dark-bg};
|
|
40
|
-
--router-tab-foreground: #{$default-dark-text};
|
|
41
|
-
--router-tab-border: #{$default-dark-border};
|
|
42
|
-
--router-tab-header-bg: #{color.adjust($default-dark-bg, $lightness: 5%)};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
@media (prefers-color-scheme: dark) {
|
|
46
|
-
:root:not([data-theme]) {
|
|
47
|
-
color-scheme: dark;
|
|
48
|
-
--router-tab-background: #{$default-dark-bg};
|
|
49
|
-
--router-tab-foreground: #{$default-dark-text};
|
|
50
|
-
--router-tab-border: #{$default-dark-border};
|
|
51
|
-
--router-tab-header-bg: #{color.adjust($default-dark-bg, $lightness: 5%)};
|
|
52
|
-
}
|
|
16
|
+
/// Utility to fetch a CSS variable with a graceful fallback.
|
|
17
|
+
@function css-var($name, $fallback) {
|
|
18
|
+
@return unquote("var(#{$name}, #{$fallback})");
|
|
53
19
|
}
|
|
54
20
|
|
|
55
21
|
.router-tab {
|
|
22
|
+
$bg: css-var(--router-tab-background, css-var(--theme-background, $light-bg));
|
|
23
|
+
$fg: css-var(--router-tab-foreground, css-var(--theme-foreground, $light-text));
|
|
24
|
+
$border: css-var(--router-tab-border, css-var(--theme-border, $light-border));
|
|
25
|
+
$primary: css-var(--router-tab-primary, css-var(--theme-primary, $primary-fallback));
|
|
26
|
+
$header-bg: css-var(--router-tab-header-bg, $bg);
|
|
27
|
+
|
|
56
28
|
display: flex;
|
|
57
29
|
flex-direction: column;
|
|
58
30
|
min-height: 300px;
|
|
59
|
-
background-color:
|
|
60
|
-
color:
|
|
31
|
+
background-color: $bg;
|
|
32
|
+
color: $fg;
|
|
61
33
|
|
|
62
34
|
&__header {
|
|
63
35
|
position: relative;
|
|
@@ -66,8 +38,8 @@ $close-icon-size: 13px;
|
|
|
66
38
|
flex: none;
|
|
67
39
|
box-sizing: border-box;
|
|
68
40
|
height: $hd-height;
|
|
69
|
-
border-bottom: 1px solid
|
|
70
|
-
background-color:
|
|
41
|
+
border-bottom: 1px solid $border;
|
|
42
|
+
background-color: $header-bg;
|
|
71
43
|
transition: all 0.2s ease-in-out;
|
|
72
44
|
}
|
|
73
45
|
|
|
@@ -141,7 +113,7 @@ $close-icon-size: 13px;
|
|
|
141
113
|
padding: 0 $tab-padding;
|
|
142
114
|
color: inherit;
|
|
143
115
|
font-size: $font-size;
|
|
144
|
-
border: 1px solid
|
|
116
|
+
border: 1px solid $border;
|
|
145
117
|
border-left: none;
|
|
146
118
|
transform-origin: left bottom;
|
|
147
119
|
cursor: pointer;
|
|
@@ -150,11 +122,11 @@ $close-icon-size: 13px;
|
|
|
150
122
|
background-color: transparent;
|
|
151
123
|
|
|
152
124
|
&:first-child {
|
|
153
|
-
border-left: 1px solid
|
|
125
|
+
border-left: 1px solid $border;
|
|
154
126
|
}
|
|
155
127
|
|
|
156
128
|
&.is-contextmenu {
|
|
157
|
-
color:
|
|
129
|
+
color: $primary;
|
|
158
130
|
}
|
|
159
131
|
|
|
160
132
|
&.is-drag-over {
|
|
@@ -177,7 +149,7 @@ $close-icon-size: 13px;
|
|
|
177
149
|
|
|
178
150
|
&:hover,
|
|
179
151
|
&.is-active {
|
|
180
|
-
color:
|
|
152
|
+
color: $primary;
|
|
181
153
|
|
|
182
154
|
&.is-closable {
|
|
183
155
|
padding: 0 ($tab-padding - math.div($close-icon-size + $close-icon-margin, 2));
|
|
@@ -195,7 +167,7 @@ $close-icon-size: 13px;
|
|
|
195
167
|
}
|
|
196
168
|
|
|
197
169
|
&.is-active {
|
|
198
|
-
border-bottom-color:
|
|
170
|
+
border-bottom-color: $bg;
|
|
199
171
|
}
|
|
200
172
|
|
|
201
173
|
&-close {
|
|
@@ -236,7 +208,7 @@ $close-icon-size: 13px;
|
|
|
236
208
|
}
|
|
237
209
|
|
|
238
210
|
&:hover {
|
|
239
|
-
background-color: color-mix(in srgb,
|
|
211
|
+
background-color: color-mix(in srgb, $primary 40%, #ffffff 60%);
|
|
240
212
|
|
|
241
213
|
&::before,
|
|
242
214
|
&::after {
|
|
@@ -252,8 +224,8 @@ $close-icon-size: 13px;
|
|
|
252
224
|
min-width: 140px;
|
|
253
225
|
padding: 8px 0;
|
|
254
226
|
font-size: $font-size;
|
|
255
|
-
background:
|
|
256
|
-
border: 1px solid
|
|
227
|
+
background: $bg;
|
|
228
|
+
border: 1px solid $border;
|
|
257
229
|
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.15);
|
|
258
230
|
border-radius: 8px;
|
|
259
231
|
|
|
@@ -278,19 +250,20 @@ $close-icon-size: 13px;
|
|
|
278
250
|
|
|
279
251
|
&:hover,
|
|
280
252
|
&:focus-visible {
|
|
281
|
-
background: color-mix(in srgb,
|
|
282
|
-
color:
|
|
253
|
+
background: color-mix(in srgb, $primary 20%, #ffffff 80%);
|
|
254
|
+
color: $primary;
|
|
283
255
|
}
|
|
284
256
|
}
|
|
285
257
|
}
|
|
286
258
|
}
|
|
287
259
|
|
|
288
260
|
.router-tab__container {
|
|
261
|
+
padding: 1rem;
|
|
289
262
|
position: relative;
|
|
290
263
|
flex: 1 1 auto;
|
|
291
|
-
background-color: var(--router-tab-background);
|
|
264
|
+
background-color: css-var(--router-tab-background, css-var(--theme-background, $light-bg));
|
|
292
265
|
}
|
|
293
266
|
|
|
294
267
|
.router-tab__item.is-active + .router-tab__item {
|
|
295
|
-
border-left-color: var(--router-tab-border);
|
|
268
|
+
border-left-color: css-var(--router-tab-border, css-var(--theme-border, $light-border));
|
|
296
269
|
}
|