vue-stack-tabs 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +14 -0
- package/README.md +14 -0
- package/dist/StackTabs.vue.d.ts +2 -2
- package/dist/components/StackKeepAlive/StackCacheRenderer.vue.d.ts +0 -2
- package/dist/hooks/stackTabsContext.d.ts +0 -1
- package/dist/hooks/tabPageContext.d.ts +18 -0
- package/dist/hooks/tabPanel/evict.d.ts +2 -2
- package/dist/hooks/tabPanel/scroll.d.ts +0 -2
- package/dist/hooks/tabPanel/state.d.ts +0 -1
- package/dist/hooks/useIframeManager.d.ts +1 -1
- package/dist/hooks/useScrollShadow.d.ts +11 -2
- package/dist/hooks/useTabEventBus.d.ts +5 -0
- package/dist/hooks/useTabLoading.d.ts +2 -1
- package/dist/hooks/useTabRouter.d.ts +5 -1
- package/dist/model/TabModel.d.ts +12 -5
- package/dist/nuxt/module.mjs +1 -1
- package/dist/nuxt/runtime/plugin.mjs +8 -1598
- package/dist/style.css +1 -1
- package/dist/utils/scrollUtils.d.ts +0 -2
- package/dist/utils/tabInfoEncoder.d.ts +0 -2
- package/dist/utils/urlParser.d.ts +6 -7
- package/dist/vue-stack-tabs.es.js +1 -1
- package/package.json +2 -2
- package/src/lib/StackTabs.vue +16 -1
- package/src/lib/assets/image/open.svg +1 -1
- package/src/lib/assets/style/common/mixins.scss +6 -6
- package/src/lib/assets/style/common/theme.scss +148 -0
- package/src/lib/assets/style/common/var.scss +104 -1
- package/src/lib/assets/style/index.scss +1 -0
- package/src/lib/assets/style/loading.scss +3 -3
- package/src/lib/assets/style/stack-tab.scss +62 -56
- package/src/lib/components/ContextMenu/index.vue +3 -1
- package/src/lib/components/PageLoading.vue +10 -9
- package/src/lib/components/StackKeepAlive/StackCacheRenderer.vue +1 -5
- package/src/lib/components/TabHeader/TabHeaderScroll.vue +164 -90
- package/src/lib/components/TabHeader/index.vue +51 -10
- package/src/lib/hooks/stackTabsContext.ts +0 -1
- package/src/lib/hooks/tabPageContext.ts +50 -0
- package/src/lib/hooks/tabPanel/evict.ts +14 -6
- package/src/lib/hooks/tabPanel/pageComponentFactory.tsx +224 -47
- package/src/lib/hooks/tabPanel/scroll.ts +4 -15
- package/src/lib/hooks/tabPanel/session.ts +11 -4
- package/src/lib/hooks/tabPanel/state.ts +0 -2
- package/src/lib/hooks/tabPanel/tabStore.ts +28 -10
- package/src/lib/hooks/useIframeManager.ts +11 -15
- package/src/lib/hooks/useScrollShadow.ts +74 -19
- package/src/lib/hooks/useTabActions.ts +10 -4
- package/src/lib/hooks/useTabEventBus.ts +3 -0
- package/src/lib/hooks/useTabLoading.ts +6 -4
- package/src/lib/hooks/useTabPanel.tsx +46 -34
- package/src/lib/hooks/useTabRouter.ts +11 -14
- package/src/lib/model/TabModel.ts +14 -5
- package/src/lib/nuxt/module.ts +3 -1
- package/src/lib/nuxt/runtime/plugin.ts +7 -3
- package/src/lib/utils/scrollUtils.ts +0 -18
- package/src/lib/utils/tabInfoEncoder.ts +21 -2
- package/src/lib/utils/urlParser.ts +40 -37
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
$stack-tab-color-white: #fff !default;
|
|
9
9
|
$stack-tab-color-black: #000 !default;
|
|
10
10
|
|
|
11
|
+
// 主色上的文字/图标(深色主题下会反转为深色)
|
|
12
|
+
$stack-tab-color-accent-contrast: $stack-tab-color-white !default;
|
|
13
|
+
|
|
11
14
|
// 主色
|
|
12
15
|
$stack-tab-color-primary: #409eff !default;
|
|
13
16
|
$stack-tab-color-primary-invert: #ffac30 !default;
|
|
@@ -42,6 +45,7 @@ $stack-tab-iframe-error-bg: rgb(255 255 255 / 92%) !default;
|
|
|
42
45
|
|
|
43
46
|
$stack-tab-border-color: #f0f0f0 !default;
|
|
44
47
|
$stack-tab-border: 1px solid $stack-tab-border-color !default;
|
|
48
|
+
$stack-tab-color-divider: #a9a9a9 !default;
|
|
45
49
|
$stack-tab-tab-radius: 8px 8px 0 0 !default;
|
|
46
50
|
$stack-tab-contextmenu-radius: 10px 0 !default;
|
|
47
51
|
|
|
@@ -88,13 +92,14 @@ $stack-tab-transition-slide:
|
|
|
88
92
|
// ============================================================
|
|
89
93
|
|
|
90
94
|
$stack-tab-shadow-color: rgb(0 0 0 / 60%) !default;
|
|
95
|
+
$stack-tab-shadow-soft-color: rgb(0 0 0 / 10%) !default;
|
|
91
96
|
$stack-tab-shadow-left: -5px 0 5px -5px $stack-tab-shadow-color !default;
|
|
92
97
|
$stack-tab-shadow-right: 5px 0 5px -5px $stack-tab-shadow-color !default;
|
|
93
98
|
$stack-tab-shadow-right-inset: inset -5px 0 5px -5px $stack-tab-shadow-color !default;
|
|
94
99
|
$stack-tab-shadow-left-inset: inset 5px 0 5px -5px $stack-tab-shadow-color !default;
|
|
95
100
|
$stack-tab-shadow-top-inset: inset 0 5px 5px -5px $stack-tab-shadow-color !default;
|
|
96
101
|
$stack-tab-shadow-bottom-inset: inset 0 -5px 5px -5px $stack-tab-shadow-color !default;
|
|
97
|
-
$stack-tab-shadow-context-menu: 5px 5px 5px
|
|
102
|
+
$stack-tab-shadow-context-menu: 5px 5px 5px $stack-tab-shadow-soft-color !default;
|
|
98
103
|
|
|
99
104
|
// ============================================================
|
|
100
105
|
// 加载态
|
|
@@ -106,3 +111,101 @@ $stack-tab-loading-size: 50px !default;
|
|
|
106
111
|
$stack-tab-loading-border-width: 8px !default;
|
|
107
112
|
$stack-tab-loading-color: #007bff97 !default;
|
|
108
113
|
$stack-tab-loading-duration: 1s !default;
|
|
114
|
+
|
|
115
|
+
// ============================================================
|
|
116
|
+
// 主题令牌(运行时 CSS 变量)
|
|
117
|
+
//
|
|
118
|
+
// 规则统一消费这一组变量;默认值定义在 theme.scss 的 :root 中。
|
|
119
|
+
// var() 的 fallback 使用上面的编译期变量,保证单独编译的 scoped
|
|
120
|
+
// 样式或未加载主题入口时仍有正确颜色,同时保留 SCSS 变量定制能力。
|
|
121
|
+
// ============================================================
|
|
122
|
+
|
|
123
|
+
// accent
|
|
124
|
+
$stack-tab-accent: var(--stack-tab-accent, #{$stack-tab-color-primary}) !default;
|
|
125
|
+
$stack-tab-accent-active: var(
|
|
126
|
+
--stack-tab-accent-active,
|
|
127
|
+
#{$stack-tab-color-primary-activate}
|
|
128
|
+
) !default;
|
|
129
|
+
$stack-tab-accent-contrast: var(
|
|
130
|
+
--stack-tab-accent-contrast,
|
|
131
|
+
#{$stack-tab-color-accent-contrast}
|
|
132
|
+
) !default;
|
|
133
|
+
$stack-tab-accent-shadow: var(
|
|
134
|
+
--stack-tab-accent-shadow,
|
|
135
|
+
#{rgba($stack-tab-color-primary, 0.8)}
|
|
136
|
+
) !default;
|
|
137
|
+
|
|
138
|
+
// surface
|
|
139
|
+
$stack-tab-surface: var(--stack-tab-surface, #{$stack-tab-background-color-base}) !default;
|
|
140
|
+
$stack-tab-surface-muted: var(
|
|
141
|
+
--stack-tab-surface-muted,
|
|
142
|
+
#{$stack-tab-background-color-inactive}
|
|
143
|
+
) !default;
|
|
144
|
+
$stack-tab-overlay: var(--stack-tab-overlay, #{$stack-tab-loading-mask-color}) !default;
|
|
145
|
+
|
|
146
|
+
// text / icon
|
|
147
|
+
$stack-tab-text: var(--stack-tab-text, #{$stack-tab-text-color}) !default;
|
|
148
|
+
$stack-tab-text-strong: var(--stack-tab-text-strong, #{$stack-tab-color-black}) !default;
|
|
149
|
+
$stack-tab-text-disabled: var(--stack-tab-text-disabled, #{$stack-tab-color-disabled}) !default;
|
|
150
|
+
$stack-tab-icon-mask: var(--stack-tab-mask, #{$stack-tab-text-color}) !default;
|
|
151
|
+
$stack-tab-font-size-token: var(--stack-tab-font-size, #{$stack-tab-font-size}) !default;
|
|
152
|
+
|
|
153
|
+
// feedback
|
|
154
|
+
$stack-tab-scrollbar: var(--stack-tab-scrollbar, #{$stack-tab-color-scrollbar}) !default;
|
|
155
|
+
|
|
156
|
+
// border
|
|
157
|
+
$stack-tab-border-color-token: var(--stack-tab-border, #{$stack-tab-border-color}) !default;
|
|
158
|
+
$stack-tab-border-token: 1px solid $stack-tab-border-color-token !default;
|
|
159
|
+
$stack-tab-divider: var(--stack-tab-divider, #{$stack-tab-color-divider}) !default;
|
|
160
|
+
|
|
161
|
+
// shadow:颜色层
|
|
162
|
+
$stack-tab-shadow-color-token: var(--stack-tab-shadow-color, #{$stack-tab-shadow-color}) !default;
|
|
163
|
+
|
|
164
|
+
// shadow:整体层
|
|
165
|
+
$stack-tab-shadow-tab: var(
|
|
166
|
+
--stack-tab-shadow-tab,
|
|
167
|
+
#{$stack-tab-shadow-left},
|
|
168
|
+
#{$stack-tab-shadow-right}
|
|
169
|
+
) !default;
|
|
170
|
+
$stack-tab-shadow-tab-left: var(--stack-tab-shadow-tab-left, #{$stack-tab-shadow-left}) !default;
|
|
171
|
+
$stack-tab-shadow-tab-right: var(--stack-tab-shadow-tab-right, #{$stack-tab-shadow-right}) !default;
|
|
172
|
+
$stack-tab-shadow-menu: var(
|
|
173
|
+
--stack-tab-shadow-menu,
|
|
174
|
+
5px 5px 5px #{$stack-tab-shadow-soft-color}
|
|
175
|
+
) !default;
|
|
176
|
+
$stack-tab-shadow-drop: var(--stack-tab-shadow-drop, 0 0 6px #{$stack-tab-accent-shadow}) !default;
|
|
177
|
+
|
|
178
|
+
// shadow:inset 工具类
|
|
179
|
+
$stack-tab-shadow-inset-left: var(
|
|
180
|
+
--stack-tab-shadow-inset-left,
|
|
181
|
+
#{$stack-tab-shadow-left-inset}
|
|
182
|
+
) !default;
|
|
183
|
+
$stack-tab-shadow-inset-right: var(
|
|
184
|
+
--stack-tab-shadow-inset-right,
|
|
185
|
+
#{$stack-tab-shadow-right-inset}
|
|
186
|
+
) !default;
|
|
187
|
+
$stack-tab-shadow-inset-top: var(
|
|
188
|
+
--stack-tab-shadow-inset-top,
|
|
189
|
+
#{$stack-tab-shadow-top-inset}
|
|
190
|
+
) !default;
|
|
191
|
+
$stack-tab-shadow-inset-bottom: var(
|
|
192
|
+
--stack-tab-shadow-inset-bottom,
|
|
193
|
+
#{$stack-tab-shadow-bottom-inset}
|
|
194
|
+
) !default;
|
|
195
|
+
$stack-tab-shadow-inset-all: var(
|
|
196
|
+
--stack-tab-shadow-inset-all,
|
|
197
|
+
#{$stack-tab-shadow-left-inset},
|
|
198
|
+
#{$stack-tab-shadow-right-inset}
|
|
199
|
+
) !default;
|
|
200
|
+
$stack-tab-shadow-inset-vertical: var(
|
|
201
|
+
--stack-tab-shadow-inset-vertical,
|
|
202
|
+
#{$stack-tab-shadow-top-inset},
|
|
203
|
+
#{$stack-tab-shadow-bottom-inset}
|
|
204
|
+
) !default;
|
|
205
|
+
|
|
206
|
+
// badge
|
|
207
|
+
$stack-tab-badge-default: var(--stack-tab-badge-default, #{$stack-tab-color-danger}) !default;
|
|
208
|
+
$stack-tab-badge-primary: var(--stack-tab-badge-primary, #{$stack-tab-color-primary}) !default;
|
|
209
|
+
|
|
210
|
+
// loading
|
|
211
|
+
$stack-tab-loading-accent: var(--stack-tab-loading-accent, #{$stack-tab-loading-color}) !default;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
&__mask {
|
|
7
7
|
@include absolute-fill;
|
|
8
8
|
@include flex-center;
|
|
9
|
-
background-color: $stack-tab-
|
|
9
|
+
background-color: $stack-tab-overlay;
|
|
10
10
|
opacity: $stack-tab-loading-mask-opacity;
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
width: $stack-tab-loading-size;
|
|
17
17
|
aspect-ratio: 1;
|
|
18
18
|
border: $stack-tab-loading-border-width solid transparent;
|
|
19
|
-
border-right-color: $stack-tab-loading-
|
|
19
|
+
border-right-color: $stack-tab-loading-accent;
|
|
20
20
|
border-radius: 50%;
|
|
21
21
|
animation: stack-tab-loading-rotate $stack-tab-loading-duration infinite linear;
|
|
22
22
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
position: absolute;
|
|
27
27
|
inset: -$stack-tab-loading-border-width;
|
|
28
28
|
border: $stack-tab-loading-border-width solid transparent;
|
|
29
|
-
border-right-color: $stack-tab-loading-
|
|
29
|
+
border-right-color: $stack-tab-loading-accent;
|
|
30
30
|
border-radius: 50%;
|
|
31
31
|
animation: stack-tab-loading-rotate $stack-tab-loading-duration * 2 infinite linear;
|
|
32
32
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
.stack-tab {
|
|
6
6
|
display: flex;
|
|
7
7
|
min-height: 300px;
|
|
8
|
-
background-color: $stack-tab-
|
|
8
|
+
background-color: $stack-tab-surface;
|
|
9
9
|
flex-direction: column;
|
|
10
10
|
gap: 5px;
|
|
11
11
|
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
.stack-tab__header-button[disabled] & {
|
|
43
43
|
cursor: not-allowed;
|
|
44
|
-
background-color: $stack-tab-
|
|
44
|
+
background-color: $stack-tab-text-disabled;
|
|
45
45
|
transition: none;
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
display: flex;
|
|
58
58
|
width: 100%;
|
|
59
59
|
height: $stack-tab-head-height;
|
|
60
|
-
border-bottom: 1px solid $stack-tab-border-color;
|
|
60
|
+
border-bottom: 1px solid $stack-tab-border-color-token;
|
|
61
61
|
box-sizing: border-box;
|
|
62
62
|
|
|
63
63
|
// tab header 上面的按钮
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
height: $stack-tab-head-height;
|
|
67
67
|
width: fit-content;
|
|
68
68
|
overflow: hidden;
|
|
69
|
-
background-color: $stack-tab-
|
|
69
|
+
background-color: $stack-tab-surface;
|
|
70
70
|
cursor: pointer;
|
|
71
71
|
display: flex;
|
|
72
72
|
align-items: center;
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
|
|
77
77
|
// 按钮禁用样式
|
|
78
78
|
&[disabled] {
|
|
79
|
-
background-color: $stack-tab-
|
|
79
|
+
background-color: $stack-tab-surface-muted;
|
|
80
80
|
box-shadow: none;
|
|
81
81
|
cursor: not-allowed;
|
|
82
82
|
}
|
|
@@ -93,12 +93,16 @@
|
|
|
93
93
|
&-container {
|
|
94
94
|
width: 100%;
|
|
95
95
|
height: 100%;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
// 使用原生横向滚动以保留触摸/触控板惯性与手感;
|
|
97
|
+
// 原生滚动条隐藏,视觉上仍由下方自绘滚动条呈现。
|
|
98
|
+
overflow-x: auto;
|
|
99
|
+
overflow-y: hidden;
|
|
100
|
+
overscroll-behavior-x: contain;
|
|
101
|
+
scrollbar-width: none;
|
|
102
|
+
-ms-overflow-style: none;
|
|
103
|
+
|
|
104
|
+
&::-webkit-scrollbar {
|
|
105
|
+
display: none;
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
108
|
}
|
|
@@ -109,7 +113,7 @@
|
|
|
109
113
|
bottom: 0;
|
|
110
114
|
left: 0;
|
|
111
115
|
height: $stack-tab-scroll-height;
|
|
112
|
-
background-color: $stack-tab-
|
|
116
|
+
background-color: $stack-tab-scrollbar;
|
|
113
117
|
border-radius: $stack-tab-scroll-border-radius;
|
|
114
118
|
opacity: 0;
|
|
115
119
|
transition: $stack-tab-transition-fast;
|
|
@@ -125,9 +129,11 @@
|
|
|
125
129
|
top: 0;
|
|
126
130
|
left: 0;
|
|
127
131
|
height: 100%;
|
|
128
|
-
background-color: $stack-tab-
|
|
132
|
+
background-color: $stack-tab-scrollbar;
|
|
129
133
|
border-radius: $stack-tab-scroll-border-radius;
|
|
130
134
|
transition: background-color $stack-tab-transition-duration ease-in-out;
|
|
135
|
+
// 拖拽由 Pointer Events 接管,避免触摸时被浏览器手势打断
|
|
136
|
+
touch-action: none;
|
|
131
137
|
|
|
132
138
|
&:hover {
|
|
133
139
|
cursor: grab;
|
|
@@ -139,7 +145,7 @@
|
|
|
139
145
|
|
|
140
146
|
.stack-tab__scrollbar--dragging &,
|
|
141
147
|
&:hover {
|
|
142
|
-
background-color: $stack-tab-
|
|
148
|
+
background-color: $stack-tab-accent !important;
|
|
143
149
|
}
|
|
144
150
|
}
|
|
145
151
|
|
|
@@ -160,11 +166,11 @@
|
|
|
160
166
|
position: relative;
|
|
161
167
|
display: flex;
|
|
162
168
|
padding: 0 $stack-tab-padding;
|
|
163
|
-
font-size: $stack-tab-font-size;
|
|
164
|
-
color: $stack-tab-text
|
|
169
|
+
font-size: $stack-tab-font-size-token;
|
|
170
|
+
color: $stack-tab-text;
|
|
165
171
|
cursor: pointer;
|
|
166
|
-
background-color: $stack-tab-
|
|
167
|
-
border: $stack-tab-border;
|
|
172
|
+
background-color: $stack-tab-surface-muted;
|
|
173
|
+
border: $stack-tab-border-token;
|
|
168
174
|
border-left: none;
|
|
169
175
|
border-radius: $stack-tab-tab-radius;
|
|
170
176
|
transition: $stack-tab-transition-fast;
|
|
@@ -176,7 +182,7 @@
|
|
|
176
182
|
margin-top: 5px;
|
|
177
183
|
|
|
178
184
|
&:first-child {
|
|
179
|
-
border-left: $stack-tab-border;
|
|
185
|
+
border-left: $stack-tab-border-token;
|
|
180
186
|
}
|
|
181
187
|
|
|
182
188
|
&--dragging {
|
|
@@ -191,9 +197,9 @@
|
|
|
191
197
|
bottom: 2px;
|
|
192
198
|
width: 5px;
|
|
193
199
|
content: '';
|
|
194
|
-
background: $stack-tab-
|
|
200
|
+
background: $stack-tab-accent;
|
|
195
201
|
border-radius: 2px;
|
|
196
|
-
box-shadow:
|
|
202
|
+
box-shadow: $stack-tab-shadow-drop;
|
|
197
203
|
}
|
|
198
204
|
|
|
199
205
|
&--drop-before::before {
|
|
@@ -206,21 +212,21 @@
|
|
|
206
212
|
|
|
207
213
|
// 激活右键菜单的页签
|
|
208
214
|
&--context-menu {
|
|
209
|
-
color: $stack-tab-
|
|
215
|
+
color: $stack-tab-text-strong;
|
|
210
216
|
}
|
|
211
217
|
|
|
212
218
|
// 激活的页签
|
|
213
219
|
&--active {
|
|
214
220
|
z-index: 1;
|
|
215
|
-
background-color: $stack-tab-
|
|
216
|
-
border-bottom-color: $stack-tab-
|
|
217
|
-
box-shadow: $stack-tab-shadow-
|
|
221
|
+
background-color: $stack-tab-surface;
|
|
222
|
+
border-bottom-color: $stack-tab-surface;
|
|
223
|
+
box-shadow: $stack-tab-shadow-tab;
|
|
218
224
|
margin-top: unset;
|
|
219
225
|
}
|
|
220
226
|
|
|
221
227
|
&:hover,
|
|
222
228
|
&--active {
|
|
223
|
-
color: $stack-tab-
|
|
229
|
+
color: $stack-tab-accent;
|
|
224
230
|
}
|
|
225
231
|
|
|
226
232
|
// 可关闭标签在悬停/激活时给关闭按钮腾出空间
|
|
@@ -294,19 +300,19 @@
|
|
|
294
300
|
padding: 0.3rem;
|
|
295
301
|
font-size: 0.5rem;
|
|
296
302
|
line-height: 0.4rem;
|
|
297
|
-
color: $stack-tab-
|
|
303
|
+
color: $stack-tab-accent-contrast;
|
|
298
304
|
text-align: center;
|
|
299
|
-
border: 1px solid $stack-tab-
|
|
305
|
+
border: 1px solid $stack-tab-surface;
|
|
300
306
|
border-radius: 0.5rem;
|
|
301
307
|
transform: translateX(100%) translateY(-50%);
|
|
302
308
|
box-sizing: border-box;
|
|
303
309
|
|
|
304
310
|
&--default {
|
|
305
|
-
background: $stack-tab-
|
|
311
|
+
background: $stack-tab-badge-default;
|
|
306
312
|
}
|
|
307
313
|
|
|
308
314
|
&--primary {
|
|
309
|
-
background: $stack-tab-
|
|
315
|
+
background: $stack-tab-badge-primary;
|
|
310
316
|
}
|
|
311
317
|
}
|
|
312
318
|
}
|
|
@@ -355,11 +361,11 @@
|
|
|
355
361
|
|
|
356
362
|
&-retry,
|
|
357
363
|
&-open {
|
|
358
|
-
border: $stack-tab-border;
|
|
364
|
+
border: $stack-tab-border-token;
|
|
359
365
|
padding: 4px 10px;
|
|
360
|
-
color: $stack-tab-text
|
|
366
|
+
color: $stack-tab-text;
|
|
361
367
|
cursor: pointer;
|
|
362
|
-
background: $stack-tab-
|
|
368
|
+
background: $stack-tab-surface;
|
|
363
369
|
border-radius: 6px;
|
|
364
370
|
font: inherit;
|
|
365
371
|
}
|
|
@@ -371,11 +377,11 @@
|
|
|
371
377
|
z-index: 999;
|
|
372
378
|
min-width: 120px;
|
|
373
379
|
padding: 8px;
|
|
374
|
-
font-size: $stack-tab-font-size;
|
|
375
|
-
background: $stack-tab-
|
|
376
|
-
border: $stack-tab-border;
|
|
380
|
+
font-size: $stack-tab-font-size-token;
|
|
381
|
+
background: $stack-tab-surface;
|
|
382
|
+
border: $stack-tab-border-token;
|
|
377
383
|
border-radius: $stack-tab-contextmenu-radius;
|
|
378
|
-
box-shadow: $stack-tab-shadow-
|
|
384
|
+
box-shadow: $stack-tab-shadow-menu;
|
|
379
385
|
transform-origin: left top;
|
|
380
386
|
|
|
381
387
|
&-item {
|
|
@@ -390,7 +396,7 @@
|
|
|
390
396
|
padding: 0 10px;
|
|
391
397
|
line-height: 30px;
|
|
392
398
|
box-sizing: border-box;
|
|
393
|
-
color: $stack-tab-text
|
|
399
|
+
color: $stack-tab-text;
|
|
394
400
|
cursor: pointer;
|
|
395
401
|
background: transparent;
|
|
396
402
|
border-radius: $stack-tab-contextmenu-radius;
|
|
@@ -403,11 +409,11 @@
|
|
|
403
409
|
&:hover,
|
|
404
410
|
&:active,
|
|
405
411
|
&:focus-visible {
|
|
406
|
-
color: $stack-tab-
|
|
407
|
-
background-color: $stack-tab-
|
|
412
|
+
color: $stack-tab-accent-contrast;
|
|
413
|
+
background-color: $stack-tab-accent;
|
|
408
414
|
|
|
409
415
|
.stack-tab__icon--mask {
|
|
410
|
-
background-color: $stack-tab-
|
|
416
|
+
background-color: $stack-tab-accent-contrast;
|
|
411
417
|
}
|
|
412
418
|
}
|
|
413
419
|
|
|
@@ -416,62 +422,62 @@
|
|
|
416
422
|
}
|
|
417
423
|
|
|
418
424
|
&[disabled] {
|
|
419
|
-
color: $stack-tab-
|
|
425
|
+
color: $stack-tab-text-disabled;
|
|
420
426
|
pointer-events: none;
|
|
421
427
|
cursor: default;
|
|
422
428
|
background: none;
|
|
423
429
|
|
|
424
430
|
.stack-tab__icon--mask {
|
|
425
|
-
background-color: $stack-tab-
|
|
431
|
+
background-color: $stack-tab-text-disabled;
|
|
426
432
|
}
|
|
427
433
|
}
|
|
428
434
|
}
|
|
429
435
|
|
|
430
436
|
&-icon {
|
|
431
|
-
width: $stack-tab-font-size;
|
|
432
|
-
height: $stack-tab-font-size;
|
|
437
|
+
width: $stack-tab-font-size-token;
|
|
438
|
+
height: $stack-tab-font-size-token;
|
|
433
439
|
transition: background-color 0.2s ease-in-out;
|
|
434
440
|
|
|
435
441
|
&.stack-tab__icon--mask {
|
|
436
|
-
width: $stack-tab-font-size;
|
|
437
|
-
height: $stack-tab-font-size;
|
|
438
|
-
background-color: $stack-tab-
|
|
442
|
+
width: $stack-tab-font-size-token;
|
|
443
|
+
height: $stack-tab-font-size-token;
|
|
444
|
+
background-color: $stack-tab-icon-mask;
|
|
439
445
|
}
|
|
440
446
|
}
|
|
441
447
|
}
|
|
442
448
|
}
|
|
443
449
|
|
|
444
450
|
.stack-tab__shadow-left {
|
|
445
|
-
box-shadow: $stack-tab-shadow-left;
|
|
451
|
+
box-shadow: $stack-tab-shadow-tab-left;
|
|
446
452
|
}
|
|
447
453
|
|
|
448
454
|
.stack-tab__shadow-right {
|
|
449
|
-
box-shadow: $stack-tab-shadow-right;
|
|
455
|
+
box-shadow: $stack-tab-shadow-tab-right;
|
|
450
456
|
}
|
|
451
457
|
|
|
452
458
|
// 内阴影
|
|
453
459
|
.stack-tab__shadow-inset {
|
|
454
460
|
&-left {
|
|
455
|
-
@include inset-shadow($stack-tab-shadow-left
|
|
461
|
+
@include inset-shadow($stack-tab-shadow-inset-left);
|
|
456
462
|
}
|
|
457
463
|
|
|
458
464
|
&-right {
|
|
459
|
-
@include inset-shadow($stack-tab-shadow-right
|
|
465
|
+
@include inset-shadow($stack-tab-shadow-inset-right);
|
|
460
466
|
}
|
|
461
467
|
|
|
462
468
|
&-all {
|
|
463
|
-
@include inset-shadow($stack-tab-shadow-
|
|
469
|
+
@include inset-shadow($stack-tab-shadow-inset-all);
|
|
464
470
|
}
|
|
465
471
|
|
|
466
472
|
&-top {
|
|
467
|
-
@include inset-shadow($stack-tab-shadow-top
|
|
473
|
+
@include inset-shadow($stack-tab-shadow-inset-top);
|
|
468
474
|
}
|
|
469
475
|
|
|
470
476
|
&-bottom {
|
|
471
|
-
@include inset-shadow($stack-tab-shadow-bottom
|
|
477
|
+
@include inset-shadow($stack-tab-shadow-inset-bottom);
|
|
472
478
|
}
|
|
473
479
|
|
|
474
480
|
&-vertical {
|
|
475
|
-
@include inset-shadow($stack-tab-shadow-
|
|
481
|
+
@include inset-shadow($stack-tab-shadow-inset-vertical);
|
|
476
482
|
}
|
|
477
483
|
}
|
|
@@ -218,6 +218,8 @@ onMounted(() => {
|
|
|
218
218
|
</script>
|
|
219
219
|
|
|
220
220
|
<style lang="scss" scoped>
|
|
221
|
+
@use '../../assets/style/common/var' as *;
|
|
222
|
+
|
|
221
223
|
.divider {
|
|
222
224
|
position: relative;
|
|
223
225
|
height: 1px;
|
|
@@ -231,7 +233,7 @@ onMounted(() => {
|
|
|
231
233
|
left: 0;
|
|
232
234
|
width: 100%;
|
|
233
235
|
height: 1px;
|
|
234
|
-
background-image: linear-gradient(to right, transparent,
|
|
236
|
+
background-image: linear-gradient(to right, transparent, $stack-tab-divider, transparent);
|
|
235
237
|
content: '';
|
|
236
238
|
}
|
|
237
239
|
</style>
|
|
@@ -11,24 +11,19 @@
|
|
|
11
11
|
role="status"
|
|
12
12
|
aria-live="polite"
|
|
13
13
|
:aria-label="t('VueStackTab.loading')"
|
|
14
|
-
:style="{ zIndex: loadingZIndex
|
|
14
|
+
:style="{ zIndex: loadingZIndex }"
|
|
15
15
|
>
|
|
16
16
|
<div class="stack-tab-loading__spin" aria-hidden="true" />
|
|
17
17
|
</div>
|
|
18
18
|
</template>
|
|
19
19
|
<script setup lang="ts">
|
|
20
|
-
import { ref, onUnmounted } from 'vue'
|
|
20
|
+
import { ref, onUnmounted, watch } from 'vue'
|
|
21
21
|
import { useI18n } from 'vue-i18n-lite'
|
|
22
22
|
import { TabEventType, useTabEmitter } from '../hooks/useTabEventBus'
|
|
23
23
|
import { getMaxZIndex, invalidateZIndexCache } from '../utils/scrollUtils'
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
*/
|
|
28
|
-
const loadingZIndex = () => {
|
|
29
|
-
invalidateZIndexCache('.stack-tab__cache-page-wrapper *')
|
|
30
|
-
return getMaxZIndex('.stack-tab__cache-page-wrapper *')
|
|
31
|
-
}
|
|
25
|
+
/** 遮罩显示时的层叠值;只在显示时计算一次,避免每次重渲染都全量扫描 DOM。 */
|
|
26
|
+
const loadingZIndex = ref(0)
|
|
32
27
|
const props = defineProps<{
|
|
33
28
|
/** 当前标签 id,用于过滤 PAGE_LOADING 事件 */
|
|
34
29
|
tabId: string
|
|
@@ -37,6 +32,12 @@ const { t } = useI18n()
|
|
|
37
32
|
const emitter = useTabEmitter()
|
|
38
33
|
/** 是否显示 loading 遮罩 */
|
|
39
34
|
const isLoading = ref<boolean>(false)
|
|
35
|
+
watch(isLoading, (loading) => {
|
|
36
|
+
if (!loading) return
|
|
37
|
+
// 遮罩显隐会改变 .stack-tab__cache-page-wrapper 子树层叠,先失效缓存再读取避免旧值。
|
|
38
|
+
invalidateZIndexCache('.stack-tab__cache-page-wrapper *')
|
|
39
|
+
loadingZIndex.value = getMaxZIndex('.stack-tab__cache-page-wrapper *')
|
|
40
|
+
})
|
|
40
41
|
/** 处理 PAGE_LOADING 事件,仅当 tId 匹配时更新 */
|
|
41
42
|
const handleLoadingEvent = (payload: { tId: string; value: boolean }) => {
|
|
42
43
|
if (payload.tId === props.tabId) {
|
|
@@ -25,8 +25,6 @@ interface StackCacheRendererProps {
|
|
|
25
25
|
interface StackCacheRendererSlotProps {
|
|
26
26
|
wrappedComponent: DefineComponent
|
|
27
27
|
activeCacheKey: string
|
|
28
|
-
refreshKey: number
|
|
29
|
-
activePageRefreshVersion: number
|
|
30
28
|
component?: VNode | null
|
|
31
29
|
}
|
|
32
30
|
|
|
@@ -36,7 +34,7 @@ defineSlots<{
|
|
|
36
34
|
default(props: StackCacheRendererSlotProps): unknown
|
|
37
35
|
}>()
|
|
38
36
|
|
|
39
|
-
const { refreshKey, activeCacheKey,
|
|
37
|
+
const { refreshKey, activeCacheKey, addPage } = useTabPanel()
|
|
40
38
|
|
|
41
39
|
const wrappedComponent = shallowRef<DefineComponent>(getEmptyPlaceholderComponent())
|
|
42
40
|
|
|
@@ -57,8 +55,6 @@ watch(
|
|
|
57
55
|
<slot
|
|
58
56
|
:wrapped-component="wrappedComponent"
|
|
59
57
|
:active-cache-key="activeCacheKey"
|
|
60
|
-
:refresh-key="refreshKey"
|
|
61
|
-
:active-page-refresh-version="activePageRefreshVersion"
|
|
62
58
|
:component="component"
|
|
63
59
|
/>
|
|
64
60
|
</template>
|