@veltra/desktop 1.2.4 → 1.2.6

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.
Files changed (140) hide show
  1. package/dist/components/auto-complete/auto-complete.js +25 -13
  2. package/dist/components/auto-complete/auto-complete.js.map +1 -1
  3. package/dist/components/auto-complete/auto-complete.vue.d.ts +3 -2
  4. package/dist/components/batch-edit/batch-edit-form.js +33 -26
  5. package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
  6. package/dist/components/batch-edit/batch-edit-list.js +4 -1
  7. package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
  8. package/dist/components/batch-edit/batch-edit.js +29 -50
  9. package/dist/components/batch-edit/batch-edit.js.map +1 -1
  10. package/dist/components/batch-edit/batch-edit.vue.d.ts +3 -3
  11. package/dist/components/batch-edit/di.js.map +1 -1
  12. package/dist/components/batch-edit/style2.css +3 -0
  13. package/dist/components/batch-edit/use-edit.js +39 -71
  14. package/dist/components/batch-edit/use-edit.js.map +1 -1
  15. package/dist/components/batch-edit/use-features.js +38 -0
  16. package/dist/components/batch-edit/use-features.js.map +1 -0
  17. package/dist/components/cascade/cascade.vue.d.ts +1 -1
  18. package/dist/components/contextmenu/style2.css +7 -7
  19. package/dist/components/dual-nav/dual-nav-app.js +70 -0
  20. package/dist/components/dual-nav/dual-nav-app.js.map +1 -0
  21. package/dist/components/dual-nav/dual-nav.js +128 -0
  22. package/dist/components/dual-nav/dual-nav.js.map +1 -0
  23. package/dist/components/dual-nav/dual-nav.vue.d.ts +13 -0
  24. package/dist/components/dual-nav/helper.js +21 -0
  25. package/dist/components/dual-nav/helper.js.map +1 -0
  26. package/dist/components/dual-nav/index.d.ts +1 -0
  27. package/dist/components/dual-nav/style.js +5 -0
  28. package/dist/components/dual-nav/style2.css +174 -0
  29. package/dist/components/index.d.ts +23 -22
  30. package/dist/components/index.js +28 -26
  31. package/dist/components/index.js.map +1 -1
  32. package/dist/components/loading/loading.js +1 -1
  33. package/dist/components/loading/loading.js.map +1 -1
  34. package/dist/components/loading/style2.css +61 -81
  35. package/dist/components/nav/di.js +7 -0
  36. package/dist/components/nav/di.js.map +1 -0
  37. package/dist/components/nav/helper.js +18 -0
  38. package/dist/components/nav/helper.js.map +1 -0
  39. package/dist/components/nav/index.d.ts +3 -0
  40. package/dist/components/{menu/menu-icon.js → nav/nav-icon.js} +4 -4
  41. package/dist/components/nav/nav-icon.js.map +1 -0
  42. package/dist/components/{menu/menu-item-collapsed.js → nav/nav-item-collapsed.js} +23 -23
  43. package/dist/components/nav/nav-item-collapsed.js.map +1 -0
  44. package/dist/components/{menu/menu-item.js → nav/nav-item.js} +13 -13
  45. package/dist/components/nav/nav-item.js.map +1 -0
  46. package/dist/components/{menu/menu-item.vue.d.ts → nav/nav-item.vue.d.ts} +4 -4
  47. package/dist/components/{menu/menu-sub-collapsed.js → nav/nav-sub-collapsed.js} +19 -19
  48. package/dist/components/nav/nav-sub-collapsed.js.map +1 -0
  49. package/dist/components/{menu/menu-sub.js → nav/nav-sub.js} +24 -24
  50. package/dist/components/nav/nav-sub.js.map +1 -0
  51. package/dist/components/{menu/menu-sub.vue.d.ts → nav/nav-sub.vue.d.ts} +4 -4
  52. package/dist/components/{menu/menu.js → nav/nav.js} +45 -36
  53. package/dist/components/nav/nav.js.map +1 -0
  54. package/dist/components/nav/nav.vue.d.ts +18 -0
  55. package/dist/components/nav/style.d.ts +1 -0
  56. package/dist/components/{menu → nav}/style2.css +105 -105
  57. package/dist/components/{menu/use-menu-item.js → nav/use-nav-item.js} +11 -11
  58. package/dist/components/nav/use-nav-item.js.map +1 -0
  59. package/dist/components/{menu/walk-menu-path.js → nav/walk-nav-path.js} +5 -5
  60. package/dist/components/nav/walk-nav-path.js.map +1 -0
  61. package/dist/components/number/number.vue.d.ts +1 -1
  62. package/dist/components/select/style2.css +4 -4
  63. package/dist/components/steps/steps.vue.d.ts +2 -2
  64. package/dist/components/tabs/tabs-horizontal.vue.d.ts +2 -2
  65. package/dist/components/tabs/tabs-vertical.vue.d.ts +2 -2
  66. package/dist/components/tabs/tabs.vue.d.ts +2 -2
  67. package/dist/components/watermark/watermark.vue.d.ts +1 -1
  68. package/dist/index.d.ts +63 -61
  69. package/dist/index.js +56 -55
  70. package/dist/style.js +2 -1
  71. package/dist/types/auto-complete.d.ts +6 -1
  72. package/dist/types/batch-edit.d.ts +15 -2
  73. package/dist/types/dual-nav.d.ts +27 -0
  74. package/dist/types/index.d.ts +4 -3
  75. package/dist/types/loading.d.ts +1 -1
  76. package/dist/types/nav.d.ts +48 -0
  77. package/package.json +6 -6
  78. package/src/components/auto-complete/auto-complete.vue +24 -13
  79. package/src/components/batch-edit/batch-edit-form.vue +29 -18
  80. package/src/components/batch-edit/batch-edit-list.vue +6 -1
  81. package/src/components/batch-edit/batch-edit.vue +36 -73
  82. package/src/components/batch-edit/di.ts +3 -1
  83. package/src/components/batch-edit/style.scss +5 -0
  84. package/src/components/batch-edit/use-edit.ts +63 -116
  85. package/src/components/batch-edit/use-features.ts +58 -0
  86. package/src/components/contextmenu/style.scss +5 -5
  87. package/src/components/dual-nav/dual-nav-app.vue +61 -0
  88. package/src/components/dual-nav/dual-nav.vue +156 -0
  89. package/src/components/dual-nav/helper.ts +25 -0
  90. package/src/components/dual-nav/index.ts +1 -0
  91. package/src/components/dual-nav/style.scss +188 -0
  92. package/src/components/dual-nav/style.ts +5 -0
  93. package/src/components/index.ts +3 -1
  94. package/src/components/loading/loading.vue +1 -1
  95. package/src/components/loading/style.scss +68 -104
  96. package/src/components/nav/di.ts +17 -0
  97. package/src/components/nav/helper.ts +22 -0
  98. package/src/components/nav/index.ts +3 -0
  99. package/src/components/{menu/menu-icon.vue → nav/nav-icon.vue} +1 -1
  100. package/src/components/nav/nav-item-collapsed.vue +66 -0
  101. package/src/components/nav/nav-item.vue +36 -0
  102. package/src/components/{menu/menu-sub-collapsed.vue → nav/nav-sub-collapsed.vue} +15 -15
  103. package/src/components/{menu/menu-sub.vue → nav/nav-sub.vue} +19 -19
  104. package/src/components/{menu/menu.vue → nav/nav.vue} +42 -42
  105. package/src/components/{menu → nav}/style.scss +16 -14
  106. package/src/components/{menu/use-menu-item.ts → nav/use-nav-item.ts} +14 -14
  107. package/src/components/{menu/walk-menu-path.ts → nav/walk-nav-path.ts} +2 -2
  108. package/src/components/select/style.scss +4 -4
  109. package/src/style.ts +2 -1
  110. package/src/types/auto-complete.ts +6 -1
  111. package/src/types/batch-edit.ts +18 -1
  112. package/src/types/dual-nav.ts +28 -0
  113. package/src/types/index.ts +2 -1
  114. package/src/types/loading.ts +1 -1
  115. package/src/types/nav.ts +49 -0
  116. package/dist/components/menu/di.js +0 -7
  117. package/dist/components/menu/di.js.map +0 -1
  118. package/dist/components/menu/helper.js +0 -8
  119. package/dist/components/menu/helper.js.map +0 -1
  120. package/dist/components/menu/index.d.ts +0 -3
  121. package/dist/components/menu/menu-icon.js.map +0 -1
  122. package/dist/components/menu/menu-item-collapsed.js.map +0 -1
  123. package/dist/components/menu/menu-item.js.map +0 -1
  124. package/dist/components/menu/menu-sub-collapsed.js.map +0 -1
  125. package/dist/components/menu/menu-sub.js.map +0 -1
  126. package/dist/components/menu/menu.js.map +0 -1
  127. package/dist/components/menu/menu.vue.d.ts +0 -14
  128. package/dist/components/menu/use-menu-item.js.map +0 -1
  129. package/dist/components/menu/walk-menu-path.js.map +0 -1
  130. package/dist/types/menu.d.ts +0 -40
  131. package/src/components/menu/di.ts +0 -17
  132. package/src/components/menu/helper.ts +0 -3
  133. package/src/components/menu/index.ts +0 -3
  134. package/src/components/menu/menu-item-collapsed.vue +0 -66
  135. package/src/components/menu/menu-item.vue +0 -36
  136. package/src/components/menu/menu-node.ts +0 -6
  137. package/src/types/menu.ts +0 -41
  138. /package/dist/components/{menu → dual-nav}/style.d.ts +0 -0
  139. /package/dist/components/{menu → nav}/style.js +0 -0
  140. /package/src/components/{menu → nav}/style.ts +0 -0
@@ -0,0 +1,188 @@
1
+ @use 'pkg:@veltra/styles/mixins' as m;
2
+ @use 'pkg:@veltra/styles/functions' as fn;
3
+ @use 'pkg:@veltra/styles/vars';
4
+
5
+ @include m.b(dual-nav) {
6
+ display: flex;
7
+ height: 100%;
8
+ min-height: 0;
9
+ background-color: var(--u-nav-bg-color);
10
+ border: 1px solid fn.use-var(border, color);
11
+ border-radius: calc(fn.use-var(radius, large) + 6px);
12
+ overflow: hidden;
13
+
14
+ @include m.e(rail) {
15
+ flex-shrink: 0;
16
+ width: var(--u-nav-rail-width);
17
+ display: flex;
18
+ flex-direction: column;
19
+ align-items: center;
20
+ gap: 4px;
21
+ padding: 8px 6px;
22
+ background-color: fn.use-var(bg-color, middle);
23
+ }
24
+
25
+ @include m.e(divider) {
26
+ flex-shrink: 0;
27
+ width: 1px;
28
+ background-color: fn.use-var(border, color);
29
+ }
30
+
31
+ @include m.e(panel) {
32
+ flex: 1;
33
+ min-width: 0;
34
+ min-height: 0;
35
+ display: flex;
36
+ flex-direction: column;
37
+ }
38
+
39
+ @include m.e(panel-header) {
40
+ flex-shrink: 0;
41
+ display: flex;
42
+ align-items: flex-start;
43
+ justify-content: space-between;
44
+ gap: 8px;
45
+ padding: 12px 12px 10px;
46
+ border-bottom: 1px solid fn.use-var(border, color);
47
+ }
48
+
49
+ @include m.e(panel-header-main) {
50
+ flex: 1;
51
+ min-width: 0;
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: 4px;
55
+ }
56
+
57
+ @include m.e(panel-title) {
58
+ margin: 0;
59
+ font-size: fn.use-var(font-size, default);
60
+ font-weight: 600;
61
+ line-height: 1.4;
62
+ color: fn.use-var(text-color, title);
63
+ }
64
+
65
+ @include m.e(description) {
66
+ margin: 0;
67
+ font-size: fn.use-var(font-size-assist, default);
68
+ line-height: 1.5;
69
+ color: fn.use-var(text-color, second);
70
+ }
71
+
72
+ @include m.e(toggle-expand) {
73
+ flex-shrink: 0;
74
+ display: inline-flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ width: 28px;
78
+ height: 28px;
79
+ padding: 0;
80
+ border: none;
81
+ border-radius: fn.use-var(radius, default);
82
+ background: transparent;
83
+ color: fn.use-var(text-color, second);
84
+ cursor: pointer;
85
+ transition:
86
+ background-color 0.15s ease,
87
+ color 0.15s ease;
88
+
89
+ &:hover {
90
+ background-color: var(--u-nav-hover-bg);
91
+ color: var(--u-nav-hover-color);
92
+ }
93
+ }
94
+
95
+ @include m.e(panel-body) {
96
+ flex: 1;
97
+ min-height: 0;
98
+
99
+ .u-nav {
100
+ height: 100%;
101
+ border: none;
102
+ border-radius: 0;
103
+ box-shadow: none;
104
+ background-color: transparent;
105
+ }
106
+ }
107
+
108
+ @include m.e(app) {
109
+ width: 100%;
110
+ aspect-ratio: 1;
111
+ max-width: calc(var(--u-nav-rail-width) - 12px);
112
+ display: inline-flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ padding: 0;
116
+ border: none;
117
+ border-radius: calc(fn.use-var(radius, default) + 2px);
118
+ background: transparent;
119
+ color: fn.use-var(text-color, second);
120
+ cursor: pointer;
121
+ transition:
122
+ background-color 0.15s ease,
123
+ color 0.15s ease;
124
+
125
+ &:hover:not(:disabled) {
126
+ background-color: var(--u-nav-hover-bg);
127
+ color: var(--u-nav-hover-color);
128
+ }
129
+
130
+ @include m.is(selected) {
131
+ background-color: var(--u-nav-hover-bg);
132
+ color: var(--u-nav-hover-color);
133
+
134
+ &:hover:not(:disabled) {
135
+ background-color: var(--u-nav-hover-bg);
136
+ color: var(--u-nav-hover-color);
137
+ }
138
+ }
139
+
140
+ @include m.is(active) {
141
+ background-color: var(--u-nav-active-bg);
142
+ color: var(--u-nav-active-color);
143
+
144
+ &:hover:not(:disabled) {
145
+ background-color: var(--u-nav-active-bg);
146
+ color: var(--u-nav-active-color);
147
+ }
148
+ }
149
+
150
+ @include m.is(disabled) {
151
+ opacity: 0.55;
152
+ cursor: not-allowed;
153
+ }
154
+ }
155
+
156
+ @include m.e(app-icon) {
157
+ width: 20px;
158
+ height: 20px;
159
+ font-size: 20px;
160
+ object-fit: contain;
161
+ }
162
+
163
+ @include m.e(app-fallback) {
164
+ font-size: 14px;
165
+ font-weight: 600;
166
+ line-height: 1;
167
+ }
168
+
169
+ @include m.e(app-tip) {
170
+ display: flex;
171
+ flex-direction: column;
172
+ gap: 4px;
173
+ max-width: 200px;
174
+ }
175
+
176
+ @include m.e(app-tip-title) {
177
+ font-weight: 600;
178
+ line-height: 1.4;
179
+ color: fn.use-var(text-color, title);
180
+ }
181
+
182
+ @include m.e(app-tip-description) {
183
+ margin: 0;
184
+ font-size: fn.use-var(font-size-assist, default);
185
+ line-height: 1.5;
186
+ color: fn.use-var(text-color, second);
187
+ }
188
+ }
@@ -0,0 +1,5 @@
1
+ import '@veltra/directives/ripple/style.js'
2
+ import '../icon/style'
3
+ import '../nav/style'
4
+ import '../tip/style'
5
+ import './style.scss'
@@ -108,7 +108,9 @@ export * from './list'
108
108
 
109
109
  export * from './rich-text-editor'
110
110
 
111
- export * from './menu'
111
+ export * from './nav'
112
+
113
+ export * from './dual-nav'
112
114
 
113
115
  export * from './grid-input'
114
116
 
@@ -15,7 +15,7 @@ import type { LoadingProps, ComponentSize } from '../../types'
15
15
 
16
16
  defineOptions({ name: 'Loading' })
17
17
 
18
- const props = withDefaults(defineProps<LoadingProps>(), { type: 'spinner' })
18
+ const props = withDefaults(defineProps<LoadingProps>(), { type: 'dual-ring' })
19
19
 
20
20
  const { size } = useFallbackProps([props], { size: 'default' as ComponentSize })
21
21
 
@@ -9,7 +9,7 @@ $root-name: loading;
9
9
  width: 100%;
10
10
  height: 100%;
11
11
  background-color: fn.use-var(bg-color, top, alpha);
12
- color: fn.use-var(text-color, main);
12
+ color: fn.use-var(color, primary);
13
13
  @include m.flex($justify: center, $align: center);
14
14
 
15
15
  @include m.e(container) {
@@ -17,123 +17,118 @@ $root-name: loading;
17
17
  }
18
18
 
19
19
  // ============================================================
20
- // spinner — 渐变圆弧旋转
21
- // 使用 conic-gradient + mask 实现缺口圆环旋转
20
+ // dual-ring — 双环反向旋转(经典 loader)
21
+ // 外环顺时针,内嵌小环逆时针,border + linear 旋转无缝循环
22
22
  // ============================================================
23
- @include m.e(spinner) {
23
+ @include m.e(dual-ring) {
24
24
  @include m.bem($root-name, loader) {
25
- width: 42px;
25
+ width: 36px;
26
26
  aspect-ratio: 1;
27
27
  border-radius: 50%;
28
- background: conic-gradient(from 0deg, transparent 25%, currentColor 70%, transparent 100%);
29
- mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 0);
30
- animation: loading-spin 0.85s linear infinite;
28
+ border: 3px solid color-mix(in srgb, currentColor 22%, transparent);
29
+ border-top-color: currentColor;
30
+ position: relative;
31
+ animation: loading-spin 0.8s linear infinite;
32
+
33
+ &::after {
34
+ content: '';
35
+ position: absolute;
36
+ inset: 5px;
37
+ border-radius: 50%;
38
+ border: 2px solid color-mix(in srgb, currentColor 22%, transparent);
39
+ border-bottom-color: currentColor;
40
+ animation: loading-spin 1.2s linear infinite reverse;
41
+ }
31
42
  }
32
43
  }
33
44
 
34
45
  // ============================================================
35
- // dot — 三点波浪弹跳
36
- // 元素自身 + 两个伪元素,交错弹跳
46
+ // dot — 三点呼吸弹跳
47
+ // 元素自身 + 两个伪元素,交错起伏
37
48
  // ============================================================
38
49
  @include m.e(dot) {
39
50
  @include m.bem($root-name, loader) {
40
- width: 10px;
41
- height: 10px;
51
+ width: 9px;
52
+ height: 9px;
42
53
  border-radius: 50%;
43
54
  background: currentColor;
44
55
  position: relative;
45
- animation: loading-dot 1.4s ease-in-out infinite;
56
+ animation: loading-dot 1.2s cubic-bezier(0.45, 0, 0.55, 1) infinite;
46
57
 
47
58
  &::before,
48
59
  &::after {
49
60
  content: '';
50
61
  position: absolute;
51
62
  top: 0;
52
- width: 10px;
53
- height: 10px;
63
+ width: 9px;
64
+ height: 9px;
54
65
  border-radius: 50%;
55
66
  background: currentColor;
56
67
  }
57
68
 
58
69
  &::before {
59
- left: -20px;
60
- animation: loading-dot 1.4s ease-in-out infinite;
61
- animation-delay: 0.2s;
70
+ left: -16px;
71
+ animation: loading-dot 1.2s cubic-bezier(0.45, 0, 0.55, 1) infinite;
72
+ animation-delay: 0.18s;
62
73
  }
63
74
 
64
75
  &::after {
65
- right: -20px;
66
- animation: loading-dot 1.4s ease-in-out infinite;
67
- animation-delay: 0.4s;
76
+ right: -16px;
77
+ animation: loading-dot 1.2s cubic-bezier(0.45, 0, 0.55, 1) infinite;
78
+ animation-delay: 0.36s;
68
79
  }
69
80
  }
70
81
  }
71
82
 
72
83
  // ============================================================
73
- // line — 流光扫过
74
- // 半透明底轨 + 渐变光条水平扫过
84
+ // ring — 单环旋转
75
85
  // ============================================================
76
- @include m.e(line) {
86
+ @include m.e(ring) {
77
87
  @include m.bem($root-name, loader) {
78
- width: 160px;
79
- height: 3px;
80
- border-radius: 1.5px;
81
- background: fn.use-var(bg-color, hover);
82
- overflow: hidden;
83
- position: relative;
84
-
85
- &::after {
86
- content: '';
87
- position: absolute;
88
- inset: 0;
89
- background: linear-gradient(
90
- 90deg,
91
- transparent 0%,
92
- currentColor 40%,
93
- currentColor 60%,
94
- transparent 100%
95
- );
96
- animation: loading-shimmer 1.4s ease-in-out infinite;
97
- }
88
+ width: 36px;
89
+ aspect-ratio: 1;
90
+ border-radius: 50%;
91
+ border: 3px solid color-mix(in srgb, currentColor 22%, transparent);
92
+ border-top-color: currentColor;
93
+ animation: loading-spin 0.9s linear infinite;
98
94
  }
99
95
  }
100
96
 
101
97
  // ============================================================
102
- // classic — 雷达波纹扩散
103
- // 两个同心圆环交替向外扩散并淡出
98
+ // bars — 三条音频跳动
99
+ // 三根竖条以容器中心为基准上下对称伸缩
104
100
  // ============================================================
105
- @include m.e(classic) {
101
+ @include m.e(bars) {
106
102
  @include m.bem($root-name, loader) {
107
- width: 44px;
108
- aspect-ratio: 1;
103
+ width: 6px;
104
+ height: 26px;
105
+ background: currentColor;
106
+ border-radius: 3px;
109
107
  position: relative;
108
+ animation: loading-bars 1s ease-in-out infinite;
109
+ animation-delay: 0.15s;
110
110
 
111
111
  &::before,
112
112
  &::after {
113
113
  content: '';
114
114
  position: absolute;
115
- inset: 0;
116
- border-radius: 50%;
117
- border: 3px solid currentColor;
118
- animation: loading-pulse 1.6s ease-out infinite;
115
+ top: 50%;
116
+ transform: translateY(-50%);
117
+ width: 6px;
118
+ height: 26px;
119
+ background: currentColor;
120
+ border-radius: 3px;
121
+ animation: loading-bars 1s ease-in-out infinite;
119
122
  }
120
123
 
121
- &::after {
122
- animation-delay: 0.8s;
124
+ &::before {
125
+ left: -12px;
123
126
  }
124
- }
125
- }
126
127
 
127
- // ============================================================
128
- // morph — 形态变换
129
- // 方块 ⟷ 圆形 来回变换,配合旋转
130
- // ============================================================
131
- @include m.e(morph) {
132
- @include m.bem($root-name, loader) {
133
- width: 34px;
134
- aspect-ratio: 1;
135
- background: currentColor;
136
- animation: loading-morph 2.4s ease-in-out infinite;
128
+ &::after {
129
+ right: -12px;
130
+ animation-delay: 0.3s;
131
+ }
137
132
  }
138
133
  }
139
134
  }
@@ -150,53 +145,22 @@ $root-name: loading;
150
145
 
151
146
  @keyframes loading-dot {
152
147
  0%,
153
- 80%,
154
148
  100% {
155
- transform: scale(0.4);
156
- opacity: 0.25;
149
+ transform: scale(0.5);
150
+ opacity: 0.3;
157
151
  }
158
- 40% {
152
+ 50% {
159
153
  transform: scale(1);
160
154
  opacity: 1;
161
155
  }
162
156
  }
163
157
 
164
- @keyframes loading-shimmer {
165
- 0% {
166
- transform: translateX(-100%);
167
- }
168
- 100% {
169
- transform: translateX(100%);
170
- }
171
- }
172
-
173
- @keyframes loading-pulse {
174
- 0% {
175
- transform: scale(0.2);
176
- opacity: 1;
177
- }
178
- 100% {
179
- transform: scale(1.35);
180
- opacity: 0;
181
- }
182
- }
183
-
184
- @keyframes loading-morph {
158
+ @keyframes loading-bars {
185
159
  0%,
186
160
  100% {
187
- border-radius: 50%;
188
- transform: rotate(0deg) scale(1);
189
- }
190
- 25% {
191
- border-radius: 8px;
192
- transform: rotate(45deg) scale(0.7);
161
+ height: 10px;
193
162
  }
194
163
  50% {
195
- border-radius: 2px;
196
- transform: rotate(90deg) scale(1);
197
- }
198
- 75% {
199
- border-radius: 8px;
200
- transform: rotate(135deg) scale(0.7);
164
+ height: 26px;
201
165
  }
202
166
  }
@@ -0,0 +1,17 @@
1
+ import { type BEM, ExpandTransition } from '@veltra/utils'
2
+ import type { ComputedRef, InjectionKey } from 'vue'
3
+
4
+ import type { NavProps, NavEmits } from '../../types'
5
+ import type { ComponentSize } from '../../types'
6
+
7
+ export interface NavContext {
8
+ cls: BEM<'nav', 'u-'>
9
+ collapsedCls: BEM<'collapsed-nav', 'u-'>
10
+ navProps: NavProps
11
+ navEmit: NavEmits
12
+ expandedPath: Set<string>
13
+ size: ComputedRef<ComponentSize>
14
+ expandTransition: ExpandTransition
15
+ }
16
+
17
+ export const NavDIKey: InjectionKey<NavContext> = Symbol('NavDIKey')
@@ -0,0 +1,22 @@
1
+ import type { NavItem } from '../../types'
2
+ import { walkNavWithPath } from './walk-nav-path'
3
+
4
+ export function getKey(index: number, parentKey: string): string {
5
+ return `${parentKey}-${index}`
6
+ }
7
+
8
+ /** 收集导航树中所有含子级的节点 path */
9
+ export function collectNavBranchPaths(menus?: NavItem[]): string[] {
10
+ const paths: string[] = []
11
+ if (!menus?.length) return paths
12
+
13
+ for (const menu of menus) {
14
+ walkNavWithPath(menu, (node) => {
15
+ if (node.children?.length) {
16
+ paths.push(node.path)
17
+ }
18
+ })
19
+ }
20
+
21
+ return paths
22
+ }
@@ -0,0 +1,3 @@
1
+ export { default as UNav } from './nav.vue'
2
+ export { default as UNavSub } from './nav-sub.vue'
3
+ export { default as UNavItem } from './nav-item.vue'
@@ -11,7 +11,7 @@ import type { DefineComponent } from 'vue'
11
11
 
12
12
  import { UIcon } from '../icon'
13
13
 
14
- defineOptions({ name: 'MenuIcon' })
14
+ defineOptions({ name: 'NavIcon' })
15
15
 
16
16
  defineProps<{ icon: string | DefineComponent }>()
17
17
  </script>
@@ -0,0 +1,66 @@
1
+ <template>
2
+ <!-- 一级导航 -->
3
+ <u-tip v-if="depth === 0" direction="right" hide-arrow>
4
+ <li
5
+ :class="[
6
+ collapsedCls.e('item'),
7
+ bem.is('active', active),
8
+ bem.is('first-level'),
9
+ bem.is('disabled', item.disabled ?? false)
10
+ ]"
11
+ ref="item"
12
+ @click="handleClickItem"
13
+ >
14
+ <UNavIcon v-if="item.icon" :icon="item.icon" :class="collapsedCls.e('icon')" />
15
+ <span v-else>{{ item.title[0] }}</span>
16
+ </li>
17
+
18
+ <template #content>
19
+ {{ item.title }}
20
+ </template>
21
+ </u-tip>
22
+
23
+ <!-- 二级以及二级以下导航 -->
24
+ <li
25
+ v-else
26
+ :class="[
27
+ collapsedCls.e('item'),
28
+ bem.is('active', active),
29
+ bem.is('disabled', item.disabled ?? false)
30
+ ]"
31
+ ref="item"
32
+ @click="_handleClickItem"
33
+ >
34
+ <UNavIcon v-if="item.icon" :icon="item.icon" :class="collapsedCls.e('icon')" />
35
+
36
+ <!-- 文本 -->
37
+ <span :class="collapsedCls.e('item-title')">
38
+ {{ item.title }}
39
+ </span>
40
+ </li>
41
+ </template>
42
+
43
+ <script setup lang="ts">
44
+ import { bem } from '@veltra/utils'
45
+ import { useTemplateRef } from 'vue'
46
+
47
+ import type { NavItem } from '../../types'
48
+ import { UTip } from '../tip'
49
+ import UNavIcon from './nav-icon.vue'
50
+ import { useNavItem } from './use-nav-item'
51
+
52
+ defineOptions({ name: 'NavItemCollapsed' })
53
+
54
+ const props = defineProps<{ item: NavItem; depth: number }>()
55
+
56
+ const itemRef = useTemplateRef('item')
57
+
58
+ const emit = defineEmits(['click'])
59
+
60
+ const { collapsedCls, active, handleClickItem } = useNavItem({ itemProps: props, itemRef })
61
+
62
+ function _handleClickItem() {
63
+ handleClickItem()
64
+ emit('click')
65
+ }
66
+ </script>
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <li
3
+ :class="[
4
+ cls.e('item'),
5
+ bem.is('first-level', depth === 0),
6
+ bem.is('active', active),
7
+ bem.is('disabled', item.disabled ?? false)
8
+ ]"
9
+ ref="item"
10
+ @click="handleClickItem"
11
+ >
12
+ <NavIcon v-if="item.icon" :icon="item.icon" :class="cls.e('icon')" />
13
+
14
+ <!-- 文本 -->
15
+ <span :class="cls.e('item-title')">
16
+ {{ item.title }}
17
+ </span>
18
+ </li>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import { bem } from '@veltra/utils'
23
+ import { useTemplateRef } from 'vue'
24
+
25
+ import type { NavItem } from '../../types'
26
+ import NavIcon from './nav-icon.vue'
27
+ import { useNavItem } from './use-nav-item'
28
+
29
+ defineOptions({ name: 'NavItem' })
30
+
31
+ const props = defineProps<{ item: NavItem; depth: number }>()
32
+
33
+ const itemRef = useTemplateRef('item')
34
+
35
+ const { cls, active, handleClickItem } = useNavItem({ itemProps: props, itemRef })
36
+ </script>