@veltra/desktop 1.0.15 → 1.1.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.
Files changed (108) hide show
  1. package/dist/components/action/action-group.vue.d.ts +2 -2
  2. package/dist/components/action/action.vue.d.ts +2 -2
  3. package/dist/components/action/style2.css +2 -2
  4. package/dist/components/auto-complete/style2.css +5 -4
  5. package/dist/components/badge/badge.js +2 -1
  6. package/dist/components/badge/badge.js.map +1 -1
  7. package/dist/components/batch-edit/style2.css +2 -2
  8. package/dist/components/breadcrumb/style2.css +1 -1
  9. package/dist/components/button/button.vue.d.ts +1 -1
  10. package/dist/components/button/style2.css +8 -7
  11. package/dist/components/card/style2.css +2 -0
  12. package/dist/components/cascade/cascade.vue.d.ts +5 -5
  13. package/dist/components/cascade/style2.css +4 -3
  14. package/dist/components/check-tag/check-tag.js +1 -1
  15. package/dist/components/checkbox/checkbox-button.vue.d.ts +1 -1
  16. package/dist/components/checkbox/style2.css +1 -1
  17. package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
  18. package/dist/components/code-editor/style2.css +7 -9
  19. package/dist/components/collapse/collapse.vue.d.ts +1 -1
  20. package/dist/components/collapse/style2.css +3 -3
  21. package/dist/components/context-menu/style2.css +3 -1
  22. package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
  23. package/dist/components/date-picker/date-picker.vue.d.ts +3 -3
  24. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +1 -1
  25. package/dist/components/date-range-picker/style2.css +5 -4
  26. package/dist/components/dialog/style2.css +2 -0
  27. package/dist/components/drawer/style2.css +2 -1
  28. package/dist/components/dropdown/style2.css +2 -0
  29. package/dist/components/expression-editor/style2.css +2 -2
  30. package/dist/components/file-viewer/style2.css +6 -6
  31. package/dist/components/form-item/style2.css +5 -2
  32. package/dist/components/input/input.js.map +1 -1
  33. package/dist/components/input/input.vue.d.ts +4 -4
  34. package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js +30 -13
  35. package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js.map +1 -1
  36. package/dist/components/input/style2.css +11 -14
  37. package/dist/components/menu/style2.css +4 -2
  38. package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
  39. package/dist/components/multi-select/style2.css +5 -4
  40. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +5 -5
  41. package/dist/components/multi-tree-select/style2.css +5 -4
  42. package/dist/components/notification/notification.vue.d.ts +1 -1
  43. package/dist/components/number-input/number-input.js +48 -10
  44. package/dist/components/number-input/number-input.js.map +1 -1
  45. package/dist/components/number-input/number-input.vue.d.ts +2 -0
  46. package/dist/components/number-input/style2.css +25 -0
  47. package/dist/components/palette/palette.js +10 -3
  48. package/dist/components/palette/palette.js.map +1 -1
  49. package/dist/components/progress-nodes/style2.css +1 -1
  50. package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
  51. package/dist/components/rich-text-editor/style2.css +2 -2
  52. package/dist/components/select/select.js +6 -2
  53. package/dist/components/select/select.js.map +1 -1
  54. package/dist/components/select/select.vue.d.ts +2 -2
  55. package/dist/components/switch/style2.css +3 -0
  56. package/dist/components/tabs/tabs-horizontal.vue.d.ts +3 -3
  57. package/dist/components/tabs/tabs-vertical.vue.d.ts +2 -2
  58. package/dist/components/tabs/tabs.vue.d.ts +3 -3
  59. package/dist/components/textarea/style2.css +7 -6
  60. package/dist/components/textarea/textarea.vue.d.ts +3 -3
  61. package/dist/components/theme/style2.css +2 -1
  62. package/dist/components/tip/tip.vue.d.ts +1 -1
  63. package/dist/components/tree-select/tree-select.vue.d.ts +5 -5
  64. package/dist/types/badge.d.ts +1 -1
  65. package/dist/types/check-tag.d.ts +1 -1
  66. package/dist/types/date-picker.d.ts +2 -2
  67. package/dist/types/number-input.d.ts +1 -0
  68. package/package.json +11 -11
  69. package/src/components/action/style.scss +2 -2
  70. package/src/components/auto-complete/style.scss +5 -4
  71. package/src/components/badge/badge.vue +4 -1
  72. package/src/components/batch-edit/style.scss +2 -2
  73. package/src/components/breadcrumb/style.scss +4 -2
  74. package/src/components/button/style.scss +2 -1
  75. package/src/components/card/style.scss +2 -0
  76. package/src/components/cascade/style.scss +4 -4
  77. package/src/components/checkbox/style.scss +2 -1
  78. package/src/components/code-editor/style.scss +7 -8
  79. package/src/components/collapse/style.scss +13 -7
  80. package/src/components/context-menu/style.scss +6 -2
  81. package/src/components/date-range-picker/style.scss +5 -5
  82. package/src/components/dialog/style.scss +2 -1
  83. package/src/components/drawer/style.scss +2 -1
  84. package/src/components/dropdown/style.scss +2 -0
  85. package/src/components/expression-editor/style.scss +8 -6
  86. package/src/components/file-viewer/style.scss +7 -7
  87. package/src/components/form-item/style.scss +3 -3
  88. package/src/components/input/input.vue +30 -11
  89. package/src/components/input/style.scss +16 -17
  90. package/src/components/menu/style.scss +4 -2
  91. package/src/components/multi-select/style.scss +5 -5
  92. package/src/components/multi-tree-select/style.scss +5 -4
  93. package/src/components/number-input/__test__/number-input.test.ts +60 -0
  94. package/src/components/number-input/number-input.vue +48 -5
  95. package/src/components/number-input/style.scss +30 -0
  96. package/src/components/palette/palette.vue +14 -4
  97. package/src/components/progress-nodes/style.scss +1 -1
  98. package/src/components/rich-text-editor/style.scss +8 -4
  99. package/src/components/select/select.vue +9 -2
  100. package/src/components/switch/style.scss +3 -0
  101. package/src/components/tabs/style.scss +4 -2
  102. package/src/components/textarea/style.scss +9 -8
  103. package/src/components/theme/style.scss +2 -1
  104. package/src/components/tree/style.scss +2 -2
  105. package/src/types/badge.ts +1 -1
  106. package/src/types/check-tag.ts +1 -1
  107. package/src/types/date-picker.ts +2 -2
  108. package/src/types/number-input.ts +1 -0
@@ -73,8 +73,10 @@ $header-padding-y: (
73
73
  color $transition-fast,
74
74
  background-color $transition-fast;
75
75
 
76
- &:hover:not(.is-disabled) {
77
- background-color: fn.use-var(bg-color, hover);
76
+ @include m.is-not(disabled) {
77
+ &:hover {
78
+ background-color: fn.use-var(bg-color, hover);
79
+ }
78
80
  }
79
81
 
80
82
  &:focus-visible {
@@ -158,7 +160,7 @@ $header-padding-y: (
158
160
 
159
161
  // ===== Ghost(无边框):项级胶囊化,反馈完全由 item hover 承担 =====
160
162
  // 嵌入卡片 / 对话框时使用,不引入额外的容器边界
161
- &:not(.is-bordered) {
163
+ @include m.is-not(bordered) {
162
164
  background-color: transparent;
163
165
 
164
166
  #{fn.bem($root-name, item)} {
@@ -169,8 +171,10 @@ $header-padding-y: (
169
171
  margin-top: 4px;
170
172
  }
171
173
 
172
- &:hover:not(.is-disabled) {
173
- background-color: fn.use-var(bg-color, hover);
174
+ @include m.is-not(disabled) {
175
+ &:hover {
176
+ background-color: fn.use-var(bg-color, hover);
177
+ }
174
178
  }
175
179
  }
176
180
 
@@ -178,8 +182,10 @@ $header-padding-y: (
178
182
  #{fn.bem($root-name, header)} {
179
183
  border-radius: inherit;
180
184
 
181
- &:hover:not(.is-disabled) {
182
- background-color: transparent;
185
+ @include m.is-not(disabled) {
186
+ &:hover {
187
+ background-color: transparent;
188
+ }
183
189
  }
184
190
  }
185
191
  }
@@ -11,6 +11,8 @@ $root-name: context-menu;
11
11
  box-shadow: fn.use-var(shadow);
12
12
  border-radius: fn.use-var(radius, default);
13
13
  padding: fn.use-var(gap, small);
14
+ backdrop-filter: fn.use-var(bg-filter);
15
+ -webkit-backdrop-filter: fn.use-var(bg-filter);
14
16
 
15
17
  @include m.e(label) {
16
18
  margin-left: fn.use-var(gap, small);
@@ -31,8 +33,10 @@ $root-name: context-menu;
31
33
  border-radius: fn.use-var(radius, default);
32
34
  @include m.flex;
33
35
 
34
- &:not(.is-disabled, .is-loading):hover {
35
- background-color: fn.use-var(color, primary, light-9);
36
+ @include m.is-not(disabled, loading) {
37
+ &:hover {
38
+ background-color: fn.use-var(color, primary, light-9);
39
+ }
36
40
  }
37
41
 
38
42
  @include m.is(disabled, loading) {
@@ -9,8 +9,9 @@ $root-name: date-range-picker;
9
9
  width: 100%;
10
10
  vertical-align: middle;
11
11
  line-height: 1;
12
- box-shadow: inset 0 0 1px 1px fn.use-var(border, color);
13
- transition: box-shadow 0.25s ease;
12
+ border: fn.use-var(border);
13
+ box-shadow: fn.use-var(shadow, emboss);
14
+ transition: border-color 0.25s ease, box-shadow 0.25s ease;
14
15
  overflow: hidden;
15
16
 
16
17
  @include m.flex($display: inline-flex);
@@ -26,8 +27,7 @@ $root-name: date-range-picker;
26
27
  }
27
28
 
28
29
  &:hover {
29
- // 悬浮时边框颜色为 var(--u-color-primary);
30
- box-shadow: inset 0 0 0px 1px fn.use-var(color, primary);
30
+ border-color: fn.use-var(color, primary);
31
31
  }
32
32
 
33
33
  @include m.e(input) {
@@ -71,7 +71,7 @@ $root-name: date-range-picker;
71
71
 
72
72
  @include m.is(disabled) {
73
73
  background-color: fn.use-var(color, disabled);
74
- box-shadow: inset 0 0 1px 1px fn.use-var(border, color);
74
+ box-shadow: none;
75
75
 
76
76
  @include m.bem($root-name, input) {
77
77
  cursor: not-allowed;
@@ -40,7 +40,8 @@ $root-name: dialog;
40
40
  flex-shrink: 0;
41
41
  overflow: hidden;
42
42
  background-color: fn.use-var(bg-color, middle);
43
- // backdrop-filter: fn.use-var(bg-filter);
43
+ backdrop-filter: fn.use-var(bg-filter);
44
+ -webkit-backdrop-filter: fn.use-var(bg-filter);
44
45
  }
45
46
 
46
47
  // 弹框头
@@ -24,7 +24,8 @@ $direction-map: (
24
24
  position: absolute;
25
25
  border-radius: fn.use-var(radius, large);
26
26
  background-color: fn.use-var(bg-color, top);
27
- backdrop-filter: blur(10px);
27
+ backdrop-filter: fn.use-var(bg-filter);
28
+ -webkit-backdrop-filter: fn.use-var(bg-filter);
28
29
  box-shadow: 0 0 10px 2px fn.use-var(shadow, color);
29
30
 
30
31
  @include m.e(close) {
@@ -12,6 +12,8 @@ $root-name: dropdown;
12
12
  border: fn.use-var(border);
13
13
  border-radius: fn.use-var(radius, default);
14
14
  box-shadow: fn.use-var(shadow);
15
+ backdrop-filter: fn.use-var(bg-filter);
16
+ -webkit-backdrop-filter: fn.use-var(bg-filter);
15
17
  top: 0;
16
18
  left: 0;
17
19
  }
@@ -12,13 +12,15 @@ $root-name: expression-editor;
12
12
  border-color: fn.use-var(border, color);
13
13
  border-radius: fn.use-var(radius, default);
14
14
 
15
- &:hover:not(.is-disabled):not(.is-readonly) {
16
- border-color: fn.use-var(color, primary);
17
- }
15
+ @include m.is-not(disabled, readonly) {
16
+ &:hover {
17
+ border-color: fn.use-var(color, primary);
18
+ }
18
19
 
19
- &:focus-within:not(.is-disabled):not(.is-readonly) {
20
- border-color: fn.use-var(color, primary);
21
- outline: none;
20
+ &:focus-within {
21
+ border-color: fn.use-var(color, primary);
22
+ outline: none;
23
+ }
22
24
  }
23
25
 
24
26
  @include m.is('disabled') {
@@ -52,8 +52,8 @@
52
52
  transparent 76%,
53
53
  rgba(255, 255, 255, 0.035)
54
54
  );
55
- backdrop-filter: blur(18px) saturate(1.16);
56
- -webkit-backdrop-filter: blur(18px) saturate(1.16);
55
+ backdrop-filter: fn.use-var(bg-filter);
56
+ -webkit-backdrop-filter: fn.use-var(bg-filter);
57
57
  }
58
58
 
59
59
  &.is-modal &__inner {
@@ -90,8 +90,8 @@
90
90
  );
91
91
  border-right: 1px solid rgba(255, 255, 255, 0.055);
92
92
  box-shadow: none;
93
- backdrop-filter: blur(18px) saturate(1.08);
94
- -webkit-backdrop-filter: blur(18px) saturate(1.08);
93
+ backdrop-filter: fn.use-var(bg-filter);
94
+ -webkit-backdrop-filter: fn.use-var(bg-filter);
95
95
  }
96
96
 
97
97
  @include m.e(sidebar-head) {
@@ -326,8 +326,8 @@
326
326
  );
327
327
  border-bottom-color: transparent;
328
328
  box-shadow: none;
329
- backdrop-filter: blur(16px) saturate(1.08);
330
- -webkit-backdrop-filter: blur(16px) saturate(1.08);
329
+ backdrop-filter: fn.use-var(bg-filter);
330
+ -webkit-backdrop-filter: fn.use-var(bg-filter);
331
331
  }
332
332
 
333
333
  @include m.e(stage-title) {
@@ -784,7 +784,7 @@
784
784
  }
785
785
 
786
786
  @media (max-width: 720px) {
787
- &:not(.is-modal) {
787
+ @include m.is-not(modal) {
788
788
  flex-direction: column;
789
789
  }
790
790
 
@@ -51,11 +51,11 @@ $root-name: form-item;
51
51
 
52
52
  @include m.is(error) {
53
53
  #{fn.bem(input)},
54
- #{fn.bem(multi-select),
54
+ #{fn.bem(multi-select)},
55
55
  #{fn.bem(multi-tree-select)},
56
56
  #{fn.bem(auto-complete)},
57
- #{fn.bem(textarea--more)}} {
58
- box-shadow: inset 0 0 1px 1px fn.use-var(color, danger);
57
+ #{fn.bem(textarea--more)} {
58
+ border-color: fn.use-var(color, danger);
59
59
  }
60
60
  }
61
61
 
@@ -26,17 +26,24 @@
26
26
  :disabled="disabled"
27
27
  :readonly="nativeReadonly"
28
28
  />
29
- <UIcon
30
- v-if="clearable && !disabled && model"
31
- :class="[cls.e('clear'), bem.is('hidden', !hovered)]"
32
- title="清除"
33
- @click.stop="clearModelValue"
34
- >
35
- <Close />
36
- </UIcon>
37
- <span :class="suffixClass" @click="handleSuffixClick" v-if="$slots.suffix || suffix">
38
- {{ suffix }}
39
- <slot name="suffix"></slot>
29
+
30
+ <span :class="suffixClass" v-if="hasSuffix">
31
+ <Transition name="zoom-in" mode="out-in">
32
+ <UIcon
33
+ v-if="showClear"
34
+ :class="cls.e('clear')"
35
+ title="清除"
36
+ @click.stop="clearModelValue"
37
+ key="clear"
38
+ >
39
+ <Close />
40
+ </UIcon>
41
+
42
+ <span v-else :class="cls.e('suffix-content')" @click="handleSuffixClick" key="suffix">
43
+ {{ suffix }}
44
+ <slot name="suffix"></slot>
45
+ </span>
46
+ </Transition>
40
47
  </span>
41
48
  </div>
42
49
 
@@ -144,6 +151,18 @@ const handleMouseLeave = () => {
144
151
  hovered.value = false
145
152
  }
146
153
 
154
+ const showClear = computed(() => {
155
+ return props.clearable && !disabled.value && !!model.value && hovered.value
156
+ })
157
+
158
+ const hasSuffixContent = computed(() => {
159
+ return !!inst?.slots.suffix || !!props.suffix
160
+ })
161
+
162
+ const hasSuffix = computed(() => {
163
+ return hasSuffixContent.value || showClear.value
164
+ })
165
+
147
166
  const handleChange = (e: Event) => {
148
167
  const target = e.target as HTMLInputElement
149
168
 
@@ -8,16 +8,20 @@ $root-name: input;
8
8
  @include m.b($root-name) {
9
9
  vertical-align: middle;
10
10
  line-height: 1;
11
- box-shadow: inset 0 0 1px 1px fn.use-var(border, color);
12
- transition: box-shadow 0.25s ease;
11
+ border: fn.use-var(border);
12
+ box-shadow: fn.use-var(shadow, emboss);
13
+ transition:
14
+ border-color 0.25s ease,
15
+ box-shadow 0.25s ease;
13
16
  overflow: hidden;
14
17
  width: 100%;
15
18
 
16
19
  @include m.flex($display: inline-flex);
17
20
 
18
- &:hover {
19
- // 悬浮时边框颜色为 var(--u-color-primary);
20
- box-shadow: inset 0 0 0px 1px fn.use-var(color, primary);
21
+ @include m.is-not(disabled) {
22
+ &:hover {
23
+ border-color: fn.use-var(color, primary);
24
+ }
21
25
  }
22
26
 
23
27
  @include m.size using ($size) {
@@ -36,8 +40,7 @@ $root-name: input;
36
40
  }
37
41
 
38
42
  @include m.is(focus) {
39
- // 使用变量 color 和 primary 设置内阴影和边框颜色
40
- box-shadow: inset 0 0 1px 1px fn.use-var(color, primary);
43
+ border-color: fn.use-var(color, primary);
41
44
  }
42
45
 
43
46
  @include m.e(native) {
@@ -77,23 +80,19 @@ $root-name: input;
77
80
  }
78
81
 
79
82
  @include m.e(clear) {
80
- flex-shrink: 0;
81
- width: 20px;
82
- display: inline-flex;
83
- align-items: center;
84
- justify-content: center;
85
83
  cursor: pointer;
86
84
  color: fn.use-var(text-color, main);
85
+ }
87
86
 
88
- @include m.is(hidden) {
89
- opacity: 0;
90
- pointer-events: none;
91
- }
87
+ @include m.e(suffix-content) {
88
+ display: inline-flex;
89
+ align-items: center;
90
+ justify-content: center;
92
91
  }
93
92
 
94
93
  @include m.is(disabled) {
95
94
  background-color: fn.use-var(color, disabled);
96
- box-shadow: inset 0 0 1px 1px fn.use-var(border, color);
95
+ box-shadow: none;
97
96
  @include m.bem($root-name, native) {
98
97
  cursor: not-allowed;
99
98
  }
@@ -105,7 +105,8 @@ $collapsed-menu: collapsed-menu;
105
105
  margin: 0;
106
106
  padding: 0;
107
107
  background-color: var(--u-menu-bg-color);
108
- backdrop-filter: var(--u-menu-bg-blur) var(--u-menu-bg-saturate);
108
+ backdrop-filter: fn.use-var(bg-filter);
109
+ -webkit-backdrop-filter: fn.use-var(bg-filter);
109
110
  background-image: var(--u-menu-bg-image);
110
111
  background-size: cover;
111
112
  background-repeat: no-repeat;
@@ -212,7 +213,8 @@ $collapsed-menu: collapsed-menu;
212
213
  min-width: 240px;
213
214
  padding: 8px !important;
214
215
  background-color: var(--u-menu-bg-color);
215
- backdrop-filter: var(--u-menu-bg-blur) var(--u-menu-bg-saturate);
216
+ backdrop-filter: fn.use-var(bg-filter);
217
+ -webkit-backdrop-filter: fn.use-var(bg-filter);
216
218
  border: 1px solid fn.use-var(border, color);
217
219
  border-radius: calc(fn.use-var(radius, large) + 4px);
218
220
  box-shadow:
@@ -8,8 +8,9 @@ $root-name: multi-select;
8
8
  @include m.b($root-name) {
9
9
  width: 100%;
10
10
  line-height: 1;
11
- box-shadow: inset 0 0 1px 1px fn.use-var(border, color);
12
- transition: box-shadow 0.25s ease;
11
+ border: fn.use-var(border);
12
+ box-shadow: fn.use-var(shadow, emboss);
13
+ transition: border-color 0.25s ease, box-shadow 0.25s ease;
13
14
  overflow: hidden;
14
15
  cursor: pointer;
15
16
  @include m.flex($display: inline-flex);
@@ -30,8 +31,7 @@ $root-name: multi-select;
30
31
  }
31
32
 
32
33
  &:hover {
33
- // 悬浮时边框颜色为 var(--u-color-primary);
34
- box-shadow: inset 0 0 1px 1px fn.use-var(color, primary);
34
+ border-color: fn.use-var(color, primary);
35
35
  }
36
36
 
37
37
  @include m.e(ripple) {
@@ -129,7 +129,7 @@ $root-name: multi-select;
129
129
 
130
130
  @include m.is(disabled) {
131
131
  background-color: fn.use-var(color, disabled);
132
- box-shadow: inset 0 0 1px 1px fn.use-var(border, color);
132
+ box-shadow: none;
133
133
  cursor: not-allowed;
134
134
 
135
135
  @include m.bem($root-name, arrow) {
@@ -7,8 +7,9 @@ $root-name: multi-tree-select;
7
7
 
8
8
  @include m.b($root-name) {
9
9
  width: 100%;
10
- box-shadow: inset 0 0 1px 1px fn.use-var(border, color);
11
- transition: box-shadow 0.25s ease;
10
+ border: fn.use-var(border);
11
+ box-shadow: fn.use-var(shadow, emboss);
12
+ transition: border-color 0.25s ease, box-shadow 0.25s ease;
12
13
  overflow: hidden;
13
14
  cursor: pointer;
14
15
  line-height: 1;
@@ -16,7 +17,7 @@ $root-name: multi-tree-select;
16
17
  @include m.flex($display: inline-flex);
17
18
 
18
19
  &:hover {
19
- box-shadow: inset 0 0 1px 1px fn.use-var(color, primary);
20
+ border-color: fn.use-var(color, primary);
20
21
  }
21
22
 
22
23
  @include m.size using ($size) {
@@ -37,7 +38,7 @@ $root-name: multi-tree-select;
37
38
  @include m.is(disabled) {
38
39
  cursor: not-allowed;
39
40
  background-color: fn.use-var(color, disabled);
40
- box-shadow: inset 0 0 1px 1px fn.use-var(border, color);
41
+ box-shadow: none;
41
42
 
42
43
  @include m.bem($root-name, arrow) {
43
44
  color: fn.use-var(text-color, disabled);
@@ -0,0 +1,60 @@
1
+ // @vitest-environment happy-dom
2
+ import { createApp, h, nextTick, ref } from 'vue'
3
+
4
+ import UNumberInput from '../number-input.vue'
5
+
6
+ function mountNumberInput(props: Record<string, unknown>) {
7
+ const host = document.createElement('div')
8
+ document.body.appendChild(host)
9
+
10
+ const model = ref(props.modelValue as number | undefined)
11
+ const app = createApp({
12
+ render() {
13
+ return h(UNumberInput, {
14
+ ...props,
15
+ modelValue: model.value,
16
+ 'onUpdate:modelValue': (value: number | undefined) => {
17
+ model.value = value
18
+ }
19
+ })
20
+ }
21
+ })
22
+
23
+ app.mount(host)
24
+
25
+ return {
26
+ host,
27
+ unmount() {
28
+ app.unmount()
29
+ host.remove()
30
+ }
31
+ }
32
+ }
33
+
34
+ describe('NumberInput', () => {
35
+ it('keeps step controls visible while clear control is shown', async () => {
36
+ const { host, unmount } = mountNumberInput({ modelValue: 1, step: 1, clearable: true })
37
+
38
+ try {
39
+ expect(host.querySelector('.u-number-input__step')).not.toBeNull()
40
+
41
+ host.querySelector('.u-number-input')?.dispatchEvent(new MouseEvent('mouseenter'))
42
+ await nextTick()
43
+
44
+ expect(host.querySelector('.u-number-input__clear')).not.toBeNull()
45
+ expect(host.querySelector('.u-number-input__step')).not.toBeNull()
46
+ } finally {
47
+ unmount()
48
+ }
49
+ })
50
+
51
+ it('reserves clear control space before hover when clearable', () => {
52
+ const { host, unmount } = mountNumberInput({ modelValue: 1, clearable: true })
53
+
54
+ try {
55
+ expect(host.querySelector('.u-number-input__clear')).not.toBeNull()
56
+ } finally {
57
+ unmount()
58
+ }
59
+ })
60
+ })
@@ -10,13 +10,30 @@
10
10
  @keydown.stop="handleKeydown"
11
11
  @focus="handleFocus"
12
12
  @blur="handleBlur"
13
+ @mouseenter="handleMouseEnter"
14
+ @mouseleave="handleMouseLeave"
13
15
  :size="size"
14
16
  :readonly="readonly"
15
17
  :disabled="disabled"
18
+ :clearable="false"
16
19
  >
17
- <template #suffix v-if="step !== undefined && step !== false">
18
- <slot name="suffix" />
19
- <div :class="cls.e('step')">
20
+ <template #suffix v-if="hasSuffix">
21
+ <span :class="cls.e('suffix')">
22
+ <u-icon
23
+ v-if="props.clearable"
24
+ :class="[cls.e('clear'), bem.is('hidden', !showClear)]"
25
+ :title="showClear ? '清除' : undefined"
26
+ @click.stop="handleClear"
27
+ >
28
+ <Close />
29
+ </u-icon>
30
+ <span v-if="hasCustomSuffix" :class="cls.e('suffix-content')">
31
+ {{ suffix }}
32
+ <slot name="suffix" />
33
+ </span>
34
+ </span>
35
+
36
+ <div v-if="showStep" :class="cls.e('step')">
20
37
  <u-icon
21
38
  @click="increase"
22
39
  v-ripple="!disabled && increasable"
@@ -48,7 +65,7 @@
48
65
  import { $n, n, o, isUndef } from '@cat-kit/core'
49
66
  import { useFormComponent, useFormFallbackProps } from '@veltra/compositions'
50
67
  import { vRipple } from '@veltra/directives'
51
- import { ArrowDown, ArrowUp } from '@veltra/icons/normal'
68
+ import { ArrowDown, ArrowUp, Close } from '@veltra/icons/normal'
52
69
  import { bem, FORM_EMPTY_CONTENT, Tween } from '@veltra/utils'
53
70
  import { computed, shallowRef, watch } from 'vue'
54
71
 
@@ -82,7 +99,7 @@ const { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, prop
82
99
  })
83
100
 
84
101
  const inputProps = computed(() => {
85
- return o(props).pick(['clearable', 'disabled', 'placeholder', 'size', 'prefix', 'suffix'])
102
+ return o(props).pick(['disabled', 'placeholder', 'size', 'prefix'])
86
103
  })
87
104
 
88
105
  const inputRef = shallowRef<InputExposed>()
@@ -102,6 +119,7 @@ const model = defineModel<NumberInputProps['modelValue']>()
102
119
  const displayed = shallowRef('')
103
120
 
104
121
  const focused = shallowRef(false)
122
+ const hovered = shallowRef(false)
105
123
 
106
124
  const generateDisplayed = computed(() => {
107
125
  if (!displayed.value) return ''
@@ -109,6 +127,16 @@ const generateDisplayed = computed(() => {
109
127
  return `${props.prefix ?? ''}${displayed.value}${props.suffix ?? ''}`
110
128
  })
111
129
 
130
+ const showStep = computed(() => props.step !== undefined && props.step !== false)
131
+
132
+ const hasCustomSuffix = computed(() => !!props.suffix || !!slots.suffix)
133
+
134
+ const hasSuffix = computed(() => props.clearable || hasCustomSuffix.value || showStep.value)
135
+
136
+ const showClear = computed(() => {
137
+ return props.clearable && !disabled.value && displayed.value !== '' && hovered.value
138
+ })
139
+
112
140
  /** 步长 */
113
141
  const stepVal = computed<number>(() => {
114
142
  const { step } = props
@@ -252,6 +280,13 @@ function handleUpdateModelValue(input: string): void {
252
280
  displayed.value = input
253
281
  }
254
282
 
283
+ function handleClear(): void {
284
+ if (!showClear.value) return
285
+ model.value = undefined
286
+ displayed.value = ''
287
+ emit('clear')
288
+ }
289
+
255
290
  /**
256
291
  * 处理输入值变化的函数, 该函数仅在输入框失去焦点时触发,
257
292
  * 主要用于在输入非数字的情况下的修正处理
@@ -376,4 +411,12 @@ function handleBlur(): void {
376
411
  focused.value = false
377
412
  model.value = props.modelValue
378
413
  }
414
+
415
+ function handleMouseEnter(): void {
416
+ hovered.value = true
417
+ }
418
+
419
+ function handleMouseLeave(): void {
420
+ hovered.value = false
421
+ }
379
422
  </script>
@@ -4,6 +4,36 @@
4
4
 
5
5
  $root-name: number-input;
6
6
  @include m.b($root-name) {
7
+ @include m.e(suffix) {
8
+ display: inline-flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ height: 100%;
12
+ }
13
+
14
+ @include m.e(suffix-content) {
15
+ display: inline-flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ }
19
+
20
+ @include m.e(clear) {
21
+ cursor: pointer;
22
+ flex-shrink: 0;
23
+ width: 20px;
24
+ border-radius: fn.use-var(radius, default);
25
+ transition: color 0.25s;
26
+
27
+ &:hover {
28
+ color: fn.use-var(color, primary);
29
+ }
30
+
31
+ @include m.is(hidden) {
32
+ visibility: hidden;
33
+ pointer-events: none;
34
+ }
35
+ }
36
+
7
37
  @include m.e(step) {
8
38
  display: flex;
9
39
  flex-direction: column;
@@ -63,18 +63,28 @@ const color = defineModel<string>()
63
63
  const RGB = computed(() => HSV2RGB(HSV))
64
64
  const { userAction, isUserActive } = useUserAction()
65
65
 
66
- watch([alpha, RGB], ([alpha, RGB]) => {
67
- color.value = `#${RGB2HEX(RGB, alpha)}`
68
- })
69
-
70
66
  const visible = shallowRef(false)
71
67
 
68
+ /** 清除时跳过一次内部状态到 color 的同步,防止 updateAlpha 把已清空的 color 覆盖回来 */
69
+ let skipColorUpdate = false
70
+
72
71
  const handleClear = userAction(() => {
72
+ if (alpha.value !== 1) {
73
+ skipColorUpdate = true
74
+ }
73
75
  color.value = ''
74
76
  rest.updateAlpha(1)
75
77
  visible.value = false
76
78
  })
77
79
 
80
+ watch([alpha, RGB], ([alpha, RGB]) => {
81
+ if (skipColorUpdate) {
82
+ skipColorUpdate = false
83
+ return
84
+ }
85
+ color.value = `#${RGB2HEX(RGB, alpha)}`
86
+ })
87
+
78
88
  const paletteSVRef = useTemplateRef('palette-sv')
79
89
  const paletteHueRef = useTemplateRef('palette-hue')
80
90
  const paletteAlphaRef = useTemplateRef('palette-alpha')
@@ -64,7 +64,7 @@ $root-name: progress-nodes;
64
64
  @include m.e(link) {
65
65
  position: absolute;
66
66
  border-style: dashed;
67
- border-color: fn.use-var(border, color);
67
+ border-color: fn.use-var(text, color, placeholder);
68
68
  }
69
69
 
70
70
  // 节点圆点