vue3-router-tab 1.1.8 → 1.2.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.md CHANGED
@@ -115,7 +115,7 @@ The composable also exposes `serialize` / `deserialize` options so you can encry
115
115
  The plugin initialises a lightweight theme layer on install:
116
116
 
117
117
  - Reads `tab-theme-style` (`'light'`, `'dark'`, or `'system'`; defaults to `'system'`).
118
- - Reads `tab-theme-primary-color` (defaults to `#635bff`).
118
+ - Reads `tab-theme-primary-color` (defaults to `#0f172a`).
119
119
  - Applies the choice via `data-theme` and `--theme-primary` CSS variables, keeping “system” in sync with OS changes.
120
120
 
121
121
  Override the theme at runtime:
@@ -12,22 +12,28 @@
12
12
  v-bind="tabTransitionProps"
13
13
  >
14
14
  <li
15
- v-for="tab in tabs"
15
+ v-for="(tab, index) in tabs"
16
16
  :key="tab.id"
17
17
  :class="buildTabClass(tab)"
18
- :data-title="tabTitle(tab)"
18
+ :data-title="getTabTitle(tab)"
19
+ :draggable="sortable"
19
20
  @click="activate(tab)"
20
21
  @auxclick.middle.prevent="close(tab)"
21
22
  @contextmenu.prevent="showContextMenu(tab, $event)"
23
+ @dragstart="onDragStart(tab, index, $event)"
24
+ @dragover="onDragOver(index, $event)"
25
+ @dragenter="onDragEnter(index)"
26
+ @dragleave="onDragLeave"
27
+ @drop="onDrop(index, $event)"
28
+ @dragend="onDragEnd"
22
29
  >
23
- <span class="router-tab__item-title" :title="tabTitle(tab)">
30
+ <span class="router-tab__item-title" :title="getTabTitle(tab)">
24
31
  <i v-if="tab.icon" :class="['router-tab__item-icon', tab.icon]" />
25
- {{ tabTitle(tab) }}
32
+ {{ getTabTitle(tab) }}
26
33
  </span>
27
34
  <a
28
35
  v-if="isClosable(tab)"
29
36
  class="router-tab__item-close"
30
- type="button"
31
37
  @click.stop="close(tab)"
32
38
  />
33
39
  </li>
@@ -125,7 +131,6 @@ import { getTransOpt } from '../util/index'
125
131
  import { routerTabsKey, routerTabsCookie } from '../constants'
126
132
  import { useRouterTabsPersistence } from '../persistence'
127
133
 
128
-
129
134
  interface ResolvedMenuItem {
130
135
  id: string
131
136
  label: string
@@ -180,9 +185,18 @@ export default defineComponent({
180
185
  persistence: {
181
186
  type: Object as PropType<RouterTabsPersistenceOptions | null>,
182
187
  default: null
188
+ },
189
+ sortable: {
190
+ type: Boolean,
191
+ default: true
192
+ },
193
+ titleResolver: {
194
+ type: Function as PropType<(tab: TabRecord) => string>,
195
+ default: null
183
196
  }
184
197
  },
185
- setup(props) {
198
+ emits: ['tab-sort', 'tab-sorted'],
199
+ setup(props, { emit }) {
186
200
  const instance = getCurrentInstance()
187
201
  if (!instance) {
188
202
  throw new Error('[RouterTab] component must be used within a Vue application context.')
@@ -199,7 +213,7 @@ export default defineComponent({
199
213
  maxAlive: props.maxAlive,
200
214
  keepLastTab: props.keepLastTab,
201
215
  appendPosition: props.append,
202
- defaultRoute: props.defaultPage
216
+ defaultRoute: props.defaultPage,
203
217
  })
204
218
 
205
219
  provide(routerTabsKey, controller)
@@ -228,6 +242,14 @@ export default defineComponent({
228
242
  position: { x: 0, y: 0 }
229
243
  })
230
244
 
245
+ // Drag and drop state
246
+ const dragState = reactive({
247
+ dragging: false,
248
+ dragIndex: -1,
249
+ dropIndex: -1,
250
+ dragTab: null as TabRecord | null
251
+ })
252
+
231
253
  type MenuConfig = RouterTabsMenuConfig
232
254
  type MenuActionContext = RouterTabsMenuContext
233
255
  type CustomMenuOption = RouterTabsMenuItem
@@ -385,7 +407,10 @@ export default defineComponent({
385
407
  await item.action()
386
408
  }
387
409
 
388
- function tabTitle(tab: TabRecord) {
410
+ function getTabTitle(tab: TabRecord): string {
411
+ if (props.titleResolver) {
412
+ return props.titleResolver(tab)
413
+ }
389
414
  if (typeof tab.title === 'string') return tab.title
390
415
  if (Array.isArray(tab.title) && tab.title.length) return String(tab.title[0])
391
416
  return tab.fullPath
@@ -411,7 +436,9 @@ export default defineComponent({
411
436
  'router-tab__item',
412
437
  {
413
438
  'is-active': controller.activeId.value === tab.id,
414
- 'is-closable': isClosable(tab)
439
+ 'is-closable': isClosable(tab),
440
+ 'is-dragging': dragState.dragging && dragState.dragTab?.id === tab.id,
441
+ 'is-drag-over': dragState.dropIndex === getTabIndex(tab.id)
415
442
  },
416
443
  tab.tabClass
417
444
  ]
@@ -421,6 +448,66 @@ export default defineComponent({
421
448
  return controller.refreshingKey.value === controller.getRouteKey(route)
422
449
  }
423
450
 
451
+ // Drag and drop handlers
452
+ function onDragStart(tab: TabRecord, index: number, event: DragEvent) {
453
+ if (!props.sortable) return
454
+
455
+ dragState.dragging = true
456
+ dragState.dragIndex = index
457
+ dragState.dragTab = tab
458
+
459
+ if (event.dataTransfer) {
460
+ event.dataTransfer.effectAllowed = 'move'
461
+ event.dataTransfer.setData('text/plain', tab.id)
462
+ }
463
+
464
+ emit('tab-sort', { tab, index })
465
+ }
466
+
467
+ function onDragOver(index: number, event: DragEvent) {
468
+ if (!props.sortable || !dragState.dragging) return
469
+ event.preventDefault()
470
+ if (event.dataTransfer) {
471
+ event.dataTransfer.dropEffect = 'move'
472
+ }
473
+ }
474
+
475
+ function onDragEnter(index: number) {
476
+ if (!props.sortable || !dragState.dragging) return
477
+ dragState.dropIndex = index
478
+ }
479
+
480
+ function onDragLeave() {
481
+ if (!props.sortable || !dragState.dragging) return
482
+ // Don't reset dropIndex immediately to prevent flicker
483
+ }
484
+
485
+ function onDrop(index: number, event: DragEvent) {
486
+ if (!props.sortable || !dragState.dragging) return
487
+
488
+ event.preventDefault()
489
+
490
+ if (dragState.dragIndex !== -1 && dragState.dragIndex !== index) {
491
+ const movedTab = controller.tabs.splice(dragState.dragIndex, 1)[0]
492
+ controller.tabs.splice(index, 0, movedTab)
493
+
494
+ emit('tab-sorted', {
495
+ tab: movedTab,
496
+ fromIndex: dragState.dragIndex,
497
+ toIndex: index
498
+ })
499
+ }
500
+
501
+ onDragEnd()
502
+ }
503
+
504
+ function onDragEnd() {
505
+ dragState.dragging = false
506
+ dragState.dragIndex = -1
507
+ dragState.dropIndex = -1
508
+ dragState.dragTab = null
509
+ }
510
+
424
511
  onMounted(() => {
425
512
  document.addEventListener('keydown', hideContextMenu)
426
513
  })
@@ -474,11 +561,17 @@ export default defineComponent({
474
561
  handleMenuAction,
475
562
  showContextMenu,
476
563
  hideContextMenu,
477
- tabTitle,
564
+ getTabTitle,
478
565
  isClosable,
479
566
  isRefreshing,
480
- hasCustomSlot
567
+ hasCustomSlot,
568
+ onDragStart,
569
+ onDragOver,
570
+ onDragEnter,
571
+ onDragLeave,
572
+ onDrop,
573
+ onDragEnd
481
574
  }
482
575
  }
483
576
  })
484
- </script>
577
+ </script>
@@ -3,6 +3,7 @@ import type {
3
3
  CloseTabOptions,
4
4
  RouteMatchResult,
5
5
  RouterTabsContext,
6
+ RouterTabsMenuPreset,
6
7
  RouterTabsOptions,
7
8
  RouterTabsSnapshot,
8
9
  RouterTabsSnapshotTab,
@@ -215,7 +216,7 @@ export function createRouterTabs(
215
216
  return options.defaultRoute
216
217
  }
217
218
 
218
- async function closeTab(id: string | undefined = activeId.value, closeOptions: CloseTabOptions = {}) {
219
+ async function closeTab(id: string | null = activeId.value, closeOptions: CloseTabOptions = {}) {
219
220
  if (!id) return
220
221
  if (!closeOptions.force && options.keepLastTab && tabs.length === 1) {
221
222
  throw new Error('[RouterTabs] Unable to close the final tab when keepLastTab is true.')
@@ -1,4 +1,4 @@
1
- import { onMounted, ref, watch } from 'vue'
1
+ import { nextTick, onMounted, ref, watch } from 'vue'
2
2
  import type { RouteLocationRaw } from 'vue-router'
3
3
  import { useRouterTabs } from './useRouterTabs'
4
4
  import type { RouterTabsSnapshot } from './core/types'
@@ -108,6 +108,14 @@ export function useRouterTabsPersistence(options: RouterTabsPersistenceOptions =
108
108
  try {
109
109
  hydrating.value = true
110
110
  await ctrl.hydrate(initialSnapshot)
111
+ if (initialSnapshot.active) {
112
+ await nextTick()
113
+ const activeTab = ctrl.tabs.find(t => t.to === initialSnapshot.active)
114
+ if (activeTab) {
115
+ ctrl.activeId.value = activeTab.id
116
+ ctrl.current.value = activeTab
117
+ }
118
+ }
111
119
  } finally {
112
120
  hydrating.value = false
113
121
  }
@@ -1,11 +1,13 @@
1
1
  @use "sass:math";
2
- @use "sass:string";
2
+ @use "sass:color";
3
3
 
4
- // Fallback palette (overridden by CSS vars when present)
5
- $primary-fallback: #635bff;
6
- $light-bg: #ffffff;
7
- $light-text: #1e293b;
8
- $light-border: rgba(15, 23, 42, 0.08);
4
+ $default-primary: #0f172a;
5
+ $default-border: #e2e8f0;
6
+ $default-text: #1e293b;
7
+ $default-bg: #f8fafc;
8
+ $default-dark-bg: #0f172a;
9
+ $default-dark-text: #e2e8f0;
10
+ $default-dark-border: rgba(148, 163, 184, 0.35);
9
11
 
10
12
  $font-size: 14px;
11
13
  $tab-trans: all 0.3s ease-in-out;
@@ -14,26 +16,48 @@ $tab-padding: 20px;
14
16
  $close-icon-margin: 4px;
15
17
  $close-icon-size: 13px;
16
18
 
17
- /// Utility to fetch a CSS variable with a graceful fallback.
18
- @function css-var($name, $fallback) {
19
- @return string.unquote("var(#{$name}, #{$fallback})");
19
+ :root {
20
+ --theme-primary: #{$default-primary};
21
+ --router-tab-primary: var(--theme-primary);
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;
20
27
  }
21
28
 
22
- .router-tab {
23
- $bg: css-var(--router-tab-background, css-var(--theme-background, $light-bg));
24
- $fg: css-var(--router-tab-foreground, css-var(--theme-foreground, $light-text));
25
- $border: css-var(--router-tab-border, css-var(--theme-border, $light-border));
26
- $primary: css-var(--router-tab-primary, css-var(--theme-primary, $primary-fallback));
27
- $header-bg: css-var(--router-tab-header-bg, $bg);
28
- $tooltip-bg: css-var(--router-tab-tooltip-background, rgba(15, 23, 42, 0.88));
29
- $tooltip-fg: css-var(--router-tab-tooltip-foreground, #ffffff);
30
- $tooltip-shadow: css-var(--router-tab-tooltip-shadow, 0 8px 24px rgba(15, 23, 42, 0.18));
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: #{$default-dark-bg};
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: #{$default-dark-bg};
52
+ }
53
+ }
31
54
 
55
+ .router-tab {
32
56
  display: flex;
33
57
  flex-direction: column;
34
58
  min-height: 300px;
35
- background-color: transparent;
36
- color: inherit;
59
+ background-color: var(--router-tab-background);
60
+ color: var(--router-tab-foreground);
37
61
 
38
62
  &__header {
39
63
  position: relative;
@@ -42,8 +66,8 @@ $close-icon-size: 13px;
42
66
  flex: none;
43
67
  box-sizing: border-box;
44
68
  height: $hd-height;
45
- border-bottom: 1px solid $border;
46
- background-color: $header-bg;
69
+ background-color: var(--router-tab-header-bg);
70
+ border-bottom: 1px solid var(--router-tab-border); // FIXED: Added border
47
71
  transition: all 0.2s ease-in-out;
48
72
  }
49
73
 
@@ -117,38 +141,40 @@ $close-icon-size: 13px;
117
141
  padding: 0 $tab-padding;
118
142
  color: inherit;
119
143
  font-size: $font-size;
120
- border: 1px solid $border;
121
- border-left: none;
122
144
  transform-origin: left bottom;
123
145
  cursor: pointer;
124
146
  transition: $tab-trans;
125
147
  user-select: none;
126
148
  background-color: transparent;
149
+
150
+ // FIXED: Added proper borders
151
+ border-right: 1px solid var(--router-tab-border);
152
+ border-top: 1px solid transparent;
153
+ border-bottom: 2px solid transparent;
127
154
 
128
155
  &:first-child {
129
- border-left: 1px solid $border;
156
+ border-left: 1px solid var(--router-tab-border);
130
157
  }
131
158
 
132
159
  &.is-contextmenu {
133
- color: $primary;
160
+ color: var(--router-tab-primary);
161
+ }
162
+
163
+ // NEW: Drag states
164
+ &.is-dragging {
165
+ opacity: 0.5;
166
+ cursor: move;
134
167
  }
135
168
 
136
169
  &.is-drag-over {
137
- background: rgba(0, 0, 0, 0.05);
138
- transition: background 0.15s ease;
170
+ background: color-mix(in srgb, var(--router-tab-primary) 10%, transparent 90%);
171
+ border-left: 2px solid var(--router-tab-primary);
172
+ transition: background 0.15s ease, border-left 0.15s ease;
139
173
  }
140
174
 
141
175
  &-title {
142
- position: relative;
143
- display: inline-flex;
144
- align-items: center;
145
- gap: var(--router-tab-title-gap, 0);
146
- min-width: var(--router-tab-title-min-width, 30px);
147
- max-width: var(--router-tab-title-max-width, 120px);
148
- color: var(--router-tab-title-color, inherit);
149
- font-weight: var(--router-tab-title-font-weight, inherit);
150
- letter-spacing: var(--router-tab-title-letter-spacing, normal);
151
- text-transform: var(--router-tab-title-transform, none);
176
+ min-width: 30px;
177
+ max-width: 120px;
152
178
  overflow: hidden;
153
179
  white-space: nowrap;
154
180
  text-overflow: ellipsis;
@@ -161,7 +187,8 @@ $close-icon-size: 13px;
161
187
 
162
188
  &:hover,
163
189
  &.is-active {
164
- color: $primary;
190
+ color: var(--router-tab-primary);
191
+ background-color: color-mix(in srgb, var(--router-tab-primary) 5%, transparent 95%);
165
192
 
166
193
  &.is-closable {
167
194
  padding: 0 ($tab-padding - math.div($close-icon-size + $close-icon-margin, 2));
@@ -173,83 +200,19 @@ $close-icon-size: 13px;
173
200
 
174
201
  &::before,
175
202
  &::after {
176
- background-color: #fff;
203
+ background-color: currentColor;
177
204
  }
178
205
  }
179
206
  }
180
207
 
181
- &:hover {
182
- .router-tab__item-title {
183
- max-width: var(--router-tab-title-hover-max-width, 220px);
184
- }
185
- }
186
-
208
+ // FIXED: Enhanced active state
187
209
  &.is-active {
188
- border-bottom-color: $bg;
189
- background: color-mix(in srgb, $primary 12%, $bg 88%);
190
- box-shadow: inset 0 -2px 0 color-mix(in srgb, $primary 65%, transparent);
191
- color: color-mix(in srgb, $primary 80%, $fg 20%);
192
-
193
- &::after {
194
- content: '';
195
- position: absolute;
196
- left: 16px;
197
- right: 16px;
198
- bottom: 6px;
199
- height: 2px;
200
- border-radius: 999px;
201
- background: $primary;
202
- opacity: 0.6;
203
- pointer-events: none;
204
- }
205
- }
206
-
207
- &[data-title] {
208
- &::after {
209
- content: attr(data-title);
210
- position: absolute;
211
- left: 50%;
212
- bottom: calc(100% + 8px);
213
- display: inline-block;
214
- max-width: 320px;
215
- padding: 4px 10px;
216
- border-radius: 6px;
217
- background: $tooltip-bg;
218
- color: $tooltip-fg;
219
- font-size: 12px;
220
- line-height: 1.3;
221
- text-align: center;
222
- white-space: normal;
223
- word-break: break-word;
224
- transform: translate(-50%, 4px);
225
- box-shadow: $tooltip-shadow;
226
- opacity: 0;
227
- pointer-events: none;
228
- transition: opacity 0.2s ease, transform 0.2s ease;
229
- }
230
-
231
- &::before {
232
- content: '';
233
- position: absolute;
234
- left: 50%;
235
- bottom: calc(100% + 4px);
236
- width: 8px;
237
- height: 8px;
238
- background: $tooltip-bg;
239
- transform: translate(-50%, 6px) rotate(45deg);
240
- opacity: 0;
241
- pointer-events: none;
242
- transition: opacity 0.2s ease, transform 0.2s ease;
243
- }
244
-
245
- &:hover::after {
246
- opacity: 1;
247
- transform: translate(-50%, 0);
248
- }
249
-
250
- &:hover::before {
251
- opacity: 1;
252
- transform: translate(-50%, 0) rotate(45deg);
210
+ border-bottom: 2px solid var(--router-tab-primary);
211
+ background-color: var(--router-tab-background);
212
+ font-weight: 500;
213
+
214
+ &:not(:first-child) {
215
+ border-left-color: var(--router-tab-border);
253
216
  }
254
217
  }
255
218
 
@@ -279,7 +242,7 @@ $close-icon-size: 13px;
279
242
  margin-left: math.div(-$inner, 2);
280
243
  background-color: currentColor;
281
244
  transition: background-color 0.2s ease-in-out;
282
- content: '';
245
+ content: "";
283
246
  }
284
247
 
285
248
  &::before {
@@ -291,7 +254,7 @@ $close-icon-size: 13px;
291
254
  }
292
255
 
293
256
  &:hover {
294
- background-color: color-mix(in srgb, $primary 40%, #ffffff 60%);
257
+ background-color: color-mix(in srgb, var(--router-tab-primary) 40%, #ffffff 60%);
295
258
 
296
259
  &::before,
297
260
  &::after {
@@ -301,14 +264,15 @@ $close-icon-size: 13px;
301
264
  }
302
265
  }
303
266
 
267
+ // FIXED: Improved context menu z-index
304
268
  &__contextmenu {
305
269
  position: fixed;
306
- z-index: 1000;
270
+ z-index: 9999; // Increased from 1000
307
271
  min-width: 140px;
308
272
  padding: 8px 0;
309
273
  font-size: $font-size;
310
- background: $bg;
311
- border: 1px solid $border;
274
+ background: var(--router-tab-background);
275
+ border: 1px solid var(--router-tab-border);
312
276
  box-shadow: 0 10px 30px rgba(15, 23, 42, 0.15);
313
277
  border-radius: 8px;
314
278
 
@@ -324,29 +288,54 @@ $close-icon-size: 13px;
324
288
  color: inherit;
325
289
  cursor: pointer;
326
290
  font: inherit;
291
+ text-decoration: none;
327
292
  transition: background-color 0.2s ease-in-out;
328
293
 
329
- &[aria-disabled='true'] {
294
+ &[aria-disabled="true"] {
330
295
  color: rgba(148, 163, 184, 0.6);
331
296
  pointer-events: none;
297
+ cursor: not-allowed;
332
298
  }
333
299
 
334
- &:hover,
335
- &:focus-visible {
336
- background: color-mix(in srgb, $primary 20%, #ffffff 80%);
337
- color: $primary;
300
+ &:not([aria-disabled="true"]):hover,
301
+ &:not([aria-disabled="true"]):focus-visible {
302
+ background: color-mix(in srgb, var(--router-tab-primary) 15%, transparent 85%);
303
+ color: var(--router-tab-primary);
304
+ outline: none;
338
305
  }
339
306
  }
340
307
  }
308
+
309
+ &__container {
310
+ position: relative;
311
+ flex: 1 1 auto;
312
+ background-color: var(--router-tab-background);
313
+ border: 1px solid var(--router-tab-border);
314
+ border-top: none; // FIXED: Avoid double border with header
315
+ }
341
316
  }
342
317
 
343
- .router-tab__container {
344
- padding: 1rem;
345
- position: relative;
346
- flex: 1 1 auto;
347
- background-color: transparent;
318
+ // FIXED: Proper adjacent tab borders
319
+ .router-tab__item {
320
+ + .router-tab__item {
321
+ border-left-color: var(--router-tab-border);
322
+ }
323
+
324
+ &.is-active + .router-tab__item {
325
+ border-left-color: var(--router-tab-border);
326
+ }
348
327
  }
349
328
 
350
- .router-tab__item.is-active + .router-tab__item {
351
- border-left-color: css-var(--router-tab-border, css-var(--theme-border, $light-border));
329
+ // NEW: Smooth drag animations
330
+ @keyframes router-tab-drag-hint {
331
+ 0%, 100% {
332
+ transform: translateY(0);
333
+ }
334
+ 50% {
335
+ transform: translateY(-2px);
336
+ }
352
337
  }
338
+
339
+ .router-tab__item.is-dragging {
340
+ animation: router-tab-drag-hint 0.3s ease-in-out;
341
+ }
@@ -0,0 +1,47 @@
1
+ // variables.scss
2
+
3
+ // Tab colors (light + dark theme overrides in :root)
4
+ $router-tab-bg-light: #ffffff !default;
5
+ $router-tab-bg-dark: #1e293b !default;
6
+
7
+ $router-tab-text-light: #0f172a !default;
8
+ $router-tab-text-dark: #f1f5f9 !default;
9
+
10
+ $router-tab-border-light: #e2e8f0 !default;
11
+ $router-tab-border-dark: #334155 !default;
12
+
13
+ $router-tab-primary: #3b82f6 !default; // default primary color
14
+
15
+ // Sizes
16
+ $router-tab-header-height: 42px !default;
17
+ $router-tab-padding: 12px !default;
18
+ $router-tab-font-size: 14px !default;
19
+
20
+ // Title
21
+ $router-tab-title-min-width: 60px !default;
22
+ $router-tab-title-max-width: 180px !default;
23
+
24
+ // Icons
25
+ $router-tab-icon-size: 14px !default;
26
+ $router-tab-icon-margin: 6px !default;
27
+
28
+ // Close icon
29
+ $router-tab-close-icon-size: 12px !default;
30
+ $router-tab-close-icon-margin: 4px !default;
31
+
32
+ // Context menu
33
+ $router-tab-contextmenu-min-width: 160px !default;
34
+ $router-tab-contextmenu-padding: 6px 0 !default;
35
+ $router-tab-contextmenu-item-height: 32px !default;
36
+ $router-tab-contextmenu-item-padding: 0 12px !default;
37
+ $router-tab-contextmenu-border-radius: 8px !default;
38
+ $router-tab-contextmenu-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !default;
39
+
40
+ // Dragging
41
+ $router-tab-drag-opacity: 0.6 !default;
42
+ $router-tab-drag-cursor: grabbing !default;
43
+ $router-tab-drag-over-bg: rgba(0, 0, 0, 0.05) !default;
44
+
45
+ // Transitions
46
+ $router-tab-transition-fast: all 0.2s ease !default;
47
+ $router-tab-transition: all 0.3s ease !default;
package/lib/theme.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  const STYLE_KEY = 'tab-theme-style'
2
2
  const PRIMARY_KEY = 'tab-theme-primary-color'
3
3
  const DEFAULT_STYLE: 'light' | 'dark' | 'system' = 'system'
4
- const DEFAULT_PRIMARY = '#635bff'
4
+ const DEFAULT_PRIMARY = '#0f172a'
5
5
  const MEDIA_QUERY = '(prefers-color-scheme: dark)'
6
6
 
7
7
  let mediaListener: ((event: MediaQueryListEvent) => void) | null = null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue3-router-tab",
3
- "version": "1.1.8",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",