Skip to content

Commit 6e41fbd

Browse files
committed
feat: inputnumber add status & upIcon & downIcon
1 parent 093fa55 commit 6e41fbd

File tree

9 files changed

+195
-21
lines changed

9 files changed

+195
-21
lines changed

components/input-number/demo/icon.vue

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<docs>
2+
---
3+
order: 99
4+
title:
5+
zh-CN: 图标按钮
6+
en-US: Icon
7+
---
8+
9+
## zh-CN
10+
11+
使用 `upIcon` `downIcon` 插槽自定义图标。
12+
13+
## en-US
14+
15+
use `upIcon` `downIcon` custom icon
16+
17+
</docs>
18+
19+
<template>
20+
<div>
21+
<a-input-number id="inputNumber" v-model:value="value" :min="1" :max="10">
22+
<template #upIcon>
23+
<ArrowUpOutlined />
24+
</template>
25+
<template #downIcon>
26+
<ArrowDownOutlined />
27+
</template>
28+
</a-input-number>
29+
</div>
30+
</template>
31+
<script lang="ts">
32+
import { defineComponent, ref } from 'vue';
33+
import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons-vue';
34+
export default defineComponent({
35+
components: {
36+
ArrowUpOutlined,
37+
ArrowDownOutlined,
38+
},
39+
setup() {
40+
const value = ref<number>(3);
41+
42+
return {
43+
value,
44+
};
45+
},
46+
});
47+
</script>

components/input-number/demo/index.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
<outOfRangeVue />
1111
<borderlessVue />
1212
<prefixVue />
13+
<statusVue />
14+
<iconVue />
1315
</demo-sort>
1416
</template>
1517
<script lang="ts">
@@ -23,6 +25,8 @@ import borderlessVue from './borderless.vue';
2325
import keyboardVue from './keyboard.vue';
2426
import outOfRangeVue from './out-of-range.vue';
2527
import prefixVue from './prefix.vue';
28+
import statusVue from './status.vue';
29+
import iconVue from './icon.vue';
2630
import CN from '../index.zh-CN.md';
2731
import US from '../index.en-US.md';
2832
import { defineComponent } from 'vue';
@@ -31,6 +35,8 @@ export default defineComponent({
3135
CN,
3236
US,
3337
components: {
38+
iconVue,
39+
statusVue,
3440
prefixVue,
3541
Basic,
3642
Disabled,
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<docs>
2+
---
3+
order: 19
4+
version: 3.3.0
5+
title:
6+
zh-CN: 自定义状态
7+
en-US: Status
8+
---
9+
10+
## zh-CN
11+
12+
使用 `status` 为 InputNumber 添加状态,可选 `error` 或者 `warning`。
13+
14+
## en-US
15+
16+
Add status to InputNumber with `status`, which could be `error` or `warning`.
17+
18+
</docs>
19+
<template>
20+
<a-space direction="vertical" style="width: 100%">
21+
<a-input-number status="error" style="width: 100%" />
22+
<a-input-number status="warning" style="width: 100%" />
23+
<a-input-number status="error" style="width: 100%">
24+
<template #prefix><ClockCircleOutlined /></template>
25+
</a-input-number>
26+
<a-input-number status="warning" style="width: 100%">
27+
<template #prefix><ClockCircleOutlined /></template>
28+
</a-input-number>
29+
</a-space>
30+
</template>
31+
32+
<script lang="ts">
33+
import { ClockCircleOutlined } from '@ant-design/icons-vue';
34+
import { defineComponent } from 'vue';
35+
export default defineComponent({
36+
components: {
37+
ClockCircleOutlined,
38+
},
39+
setup() {
40+
return {};
41+
},
42+
});
43+
</script>

components/input-number/index.en-US.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ When a numeric value needs to be provided.
3131
| precision | precision of input value | number | - | |
3232
| prefix | The prefix icon for the Input | slot | - | 3.0 |
3333
| size | height of input box | string | - | |
34+
| status | Set validation status | 'error' \| 'warning' | - | 3.3.0 |
3435
| step | The number to which the current value is increased or decreased. It can be an integer or decimal. | number\|string | 1 | |
3536
| stringMode | Set value as string to support high precision decimals. Will return string value by `change` | boolean | false | 3.0 |
3637
| value(v-model) | current value | number | | |
38+
| upIcon | custom up icon | slot | `<UpOutlined />` | 3.3.0 |
39+
| downIcon | custom up down | slot | `<DownOutlined />` | 3.3.0 |
3740

3841
### events
3942

components/input-number/index.tsx

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
import type { PropType, ExtractPropTypes, HTMLAttributes, App } from 'vue';
2-
import { watch, defineComponent, nextTick, onMounted, ref } from 'vue';
2+
import { watch, defineComponent, nextTick, onMounted, ref, computed } from 'vue';
33
import classNames from '../_util/classNames';
44
import UpOutlined from '@ant-design/icons-vue/UpOutlined';
55
import DownOutlined from '@ant-design/icons-vue/DownOutlined';
66
import VcInputNumber, { inputNumberProps as baseInputNumberProps } from './src/InputNumber';
77
import type { SizeType } from '../config-provider';
8-
import { useInjectFormItemContext } from '../form/FormItemContext';
8+
import {
9+
FormItemInputContext,
10+
NoFormStatus,
11+
useInjectFormItemContext,
12+
} from '../form/FormItemContext';
913
import useConfigInject from '../_util/hooks/useConfigInject';
1014
import { cloneElement } from '../_util/vnode';
1115
import omit from '../_util/omit';
1216
import PropTypes from '../_util/vue-types';
1317
import isValidValue from '../_util/isValidValue';
18+
import type { InputStatus } from '../_util/statusUtils';
19+
import { getStatusClassNames, getMergedStatus } from '../_util/statusUtils';
1420
const baseProps = baseInputNumberProps();
1521
export const inputNumberProps = () => ({
1622
...baseProps,
@@ -25,6 +31,7 @@ export const inputNumberProps = () => ({
2531
prefix: PropTypes.any,
2632
'onUpdate:value': baseProps.onChange,
2733
valueModifiers: Object,
34+
status: String as PropType<InputStatus>,
2835
});
2936

3037
export type InputNumberProps = Partial<ExtractPropTypes<ReturnType<typeof inputNumberProps>>>;
@@ -37,6 +44,8 @@ const InputNumber = defineComponent({
3744
slots: ['addonBefore', 'addonAfter', 'prefix'],
3845
setup(props, { emit, expose, attrs, slots }) {
3946
const formItemContext = useInjectFormItemContext();
47+
const formItemInputContext = FormItemInputContext.useInject();
48+
const mergedStatus = computed(() => getMergedStatus(formItemInputContext.status, props.status));
4049
const { prefixCls, size, direction } = useConfigInject('input-number', props);
4150
const mergedValue = ref(props.value === undefined ? props.defaultValue : props.value);
4251
const focused = ref(false);
@@ -84,6 +93,7 @@ const InputNumber = defineComponent({
8493
});
8594
});
8695
return () => {
96+
const { hasFeedback, isFormItemInput, feedbackIcon } = formItemInputContext;
8797
const {
8898
class: className,
8999
bordered,
@@ -106,7 +116,9 @@ const InputNumber = defineComponent({
106116
[`${preCls}-rtl`]: direction.value === 'rtl',
107117
[`${preCls}-readonly`]: readonly,
108118
[`${preCls}-borderless`]: !bordered,
119+
[`${preCls}-in-form-item`]: isFormItemInput,
109120
},
121+
getStatusClassNames(preCls, mergedStatus.value),
110122
className,
111123
);
112124

@@ -123,32 +135,42 @@ const InputNumber = defineComponent({
123135
onBlur={handleBlur}
124136
onFocus={handleFocus}
125137
v-slots={{
126-
upHandler: () => <UpOutlined class={`${preCls}-handler-up-inner`} />,
127-
downHandler: () => <DownOutlined class={`${preCls}-handler-down-inner`} />,
138+
upHandler: slots.upIcon
139+
? () => <span class={`${preCls}-handler-up-inner`}>{slots.upIcon()}</span>
140+
: () => <UpOutlined class={`${preCls}-handler-up-inner`} />,
141+
downHandler: slots.downIcon
142+
? () => <span class={`${preCls}-handler-down-inner`}>{slots.downIcon()}</span>
143+
: () => <DownOutlined class={`${preCls}-handler-down-inner`} />,
128144
}}
129145
/>
130146
);
131147
const hasAddon = isValidValue(addonBefore) || isValidValue(addonAfter);
132-
if (isValidValue(prefix)) {
133-
const affixWrapperCls = classNames(`${preCls}-affix-wrapper`, {
134-
[`${preCls}-affix-wrapper-focused`]: focused.value,
135-
[`${preCls}-affix-wrapper-disabled`]: props.disabled,
136-
[`${preCls}-affix-wrapper-sm`]: size.value === 'small',
137-
[`${preCls}-affix-wrapper-lg`]: size.value === 'large',
138-
[`${preCls}-affix-wrapper-rtl`]: direction.value === 'rtl',
139-
[`${preCls}-affix-wrapper-readonly`]: readonly,
140-
[`${preCls}-affix-wrapper-borderless`]: !bordered,
141-
// className will go to addon wrapper
142-
[`${className}`]: !hasAddon && className,
143-
});
148+
const hasPrefix = isValidValue(prefix);
149+
if (hasPrefix || hasFeedback) {
150+
const affixWrapperCls = classNames(
151+
`${preCls}-affix-wrapper`,
152+
getStatusClassNames(`${preCls}-affix-wrapper`, mergedStatus.value, hasFeedback),
153+
{
154+
[`${preCls}-affix-wrapper-focused`]: focused.value,
155+
[`${preCls}-affix-wrapper-disabled`]: props.disabled,
156+
[`${preCls}-affix-wrapper-sm`]: size.value === 'small',
157+
[`${preCls}-affix-wrapper-lg`]: size.value === 'large',
158+
[`${preCls}-affix-wrapper-rtl`]: direction.value === 'rtl',
159+
[`${preCls}-affix-wrapper-readonly`]: readonly,
160+
[`${preCls}-affix-wrapper-borderless`]: !bordered,
161+
// className will go to addon wrapper
162+
[`${className}`]: !hasAddon && className,
163+
},
164+
);
144165
element = (
145166
<div
146167
class={affixWrapperCls}
147168
style={style}
148169
onMouseup={() => inputNumberRef.value!.focus()}
149170
>
150-
<span class={`${preCls}-prefix`}>{prefix}</span>
171+
{hasPrefix && <span class={`${preCls}-prefix`}>{prefix}</span>}
151172
{element}
173+
{hasFeedback && <span class={`${preCls}-suffix`}>{feedbackIcon}</span>}
152174
</div>
153175
);
154176
}
@@ -172,14 +194,15 @@ const InputNumber = defineComponent({
172194
[`${preCls}-group-wrapper-lg`]: mergeSize === 'large',
173195
[`${preCls}-group-wrapper-rtl`]: direction.value === 'rtl',
174196
},
197+
getStatusClassNames(`${prefixCls}-group-wrapper`, mergedStatus.value, hasFeedback),
175198
className,
176199
);
177200
element = (
178201
<div class={mergedGroupClassName} style={style}>
179202
<div class={mergedWrapperClassName}>
180-
{addonBeforeNode}
203+
{addonBeforeNode && <NoFormStatus>{addonBeforeNode}</NoFormStatus>}
181204
{element}
182-
{addonAfterNode}
205+
{addonAfterNode && <NoFormStatus>{addonAfterNode}</NoFormStatus>}
183206
</div>
184207
</div>
185208
);

components/input-number/index.zh-CN.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ cover: https://gw.alipayobjects.com/zos/alicdn/XOS8qZ0kU/InputNumber.svg
3434
| precision | 数值精度 | number | - | |
3535
| prefix | 带有前缀图标的 input | slot | - | 3.0 |
3636
| size | 输入框大小 | string || |
37+
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
3738
| step | 每次改变步数,可以为小数 | number\|string | 1 | |
3839
| stringMode | 字符值模式,开启后支持高精度小数。同时 `change` 事件将返回 string 类型 | boolean | false | 3.0 |
40+
| upIcon | 自定义上箭头图标 | slot | `<UpOutlined />` | 3.3.0 |
41+
| downIcon | 自定义下箭头图标 | slot | `<DownOutlined />` | 3.3.0 |
3942
| value(v-model) | 当前值 | number | | |
4043

4144
### 事件

components/input-number/style/affix.less

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
&-affix-wrapper {
99
.input();
1010
// or number handler will cover form status
11-
position: static;
11+
position: relative;
1212
display: inline-flex;
1313
width: 90px;
1414
padding: 0;
@@ -49,14 +49,33 @@
4949
visibility: hidden;
5050
content: '\a0';
5151
}
52+
53+
.@{ant-prefix}-input-number-handler-wrap {
54+
z-index: 2;
55+
}
5256
}
5357

54-
&-prefix {
58+
&-prefix,
59+
&-suffix {
5560
display: flex;
5661
flex: none;
5762
align-items: center;
63+
pointer-events: none;
64+
}
65+
66+
&-prefix {
5867
margin-inline-end: @input-affix-margin;
5968
}
69+
70+
&-suffix {
71+
position: absolute;
72+
top: 0;
73+
right: 0;
74+
z-index: 1;
75+
height: 100%;
76+
margin-right: @input-padding-horizontal-base;
77+
margin-left: @input-affix-margin;
78+
}
6079
}
6180

6281
.@{ant-prefix}-input-number-group-wrapper .@{ant-prefix}-input-number-affix-wrapper {

components/input-number/style/index.less

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
@import '../../style/mixins/index';
33
@import '../../input/style/mixin';
44
@import './affix';
5+
@import './status';
56

67
@input-number-prefix-cls: ~'@{ant-prefix}-input-number';
78
@form-item-prefix-cls: ~'@{ant-prefix}-form-item';
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@import '../../input/style/mixin';
2+
3+
@input-number-prefix-cls: ~'@{ant-prefix}-input-number';
4+
5+
@input-number-wrapper-cls: @input-number-prefix-cls, ~'@{input-number-prefix-cls}-affix-wrapper';
6+
7+
each(@input-number-wrapper-cls, {
8+
.@{value} {
9+
&-status-error {
10+
.status-color(@value, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);
11+
.status-color-common(@input-number-prefix-cls, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline)
12+
}
13+
14+
&-status-warning {
15+
.status-color(@value, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
16+
.status-color-common(@input-number-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline)
17+
}
18+
}
19+
});
20+
21+
.@{input-number-prefix-cls}-group-wrapper {
22+
&-status-error {
23+
.group-status-color(@input-number-prefix-cls, @error-color, @error-color);
24+
}
25+
26+
&-status-warning {
27+
.group-status-color(@input-number-prefix-cls, @warning-color, @warning-color);
28+
}
29+
}

0 commit comments

Comments
 (0)