feat: inputnumber add status & upIcon & downIcon
parent
093fa555ba
commit
6e41fbd01f
|
@ -0,0 +1,47 @@
|
||||||
|
<docs>
|
||||||
|
---
|
||||||
|
order: 99
|
||||||
|
title:
|
||||||
|
zh-CN: 图标按钮
|
||||||
|
en-US: Icon
|
||||||
|
---
|
||||||
|
|
||||||
|
## zh-CN
|
||||||
|
|
||||||
|
使用 `upIcon` `downIcon` 插槽自定义图标。
|
||||||
|
|
||||||
|
## en-US
|
||||||
|
|
||||||
|
use `upIcon` `downIcon` custom icon
|
||||||
|
|
||||||
|
</docs>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-input-number id="inputNumber" v-model:value="value" :min="1" :max="10">
|
||||||
|
<template #upIcon>
|
||||||
|
<ArrowUpOutlined />
|
||||||
|
</template>
|
||||||
|
<template #downIcon>
|
||||||
|
<ArrowDownOutlined />
|
||||||
|
</template>
|
||||||
|
</a-input-number>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref } from 'vue';
|
||||||
|
import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons-vue';
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
ArrowUpOutlined,
|
||||||
|
ArrowDownOutlined,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const value = ref<number>(3);
|
||||||
|
|
||||||
|
return {
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -10,6 +10,8 @@
|
||||||
<outOfRangeVue />
|
<outOfRangeVue />
|
||||||
<borderlessVue />
|
<borderlessVue />
|
||||||
<prefixVue />
|
<prefixVue />
|
||||||
|
<statusVue />
|
||||||
|
<iconVue />
|
||||||
</demo-sort>
|
</demo-sort>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -23,6 +25,8 @@ import borderlessVue from './borderless.vue';
|
||||||
import keyboardVue from './keyboard.vue';
|
import keyboardVue from './keyboard.vue';
|
||||||
import outOfRangeVue from './out-of-range.vue';
|
import outOfRangeVue from './out-of-range.vue';
|
||||||
import prefixVue from './prefix.vue';
|
import prefixVue from './prefix.vue';
|
||||||
|
import statusVue from './status.vue';
|
||||||
|
import iconVue from './icon.vue';
|
||||||
import CN from '../index.zh-CN.md';
|
import CN from '../index.zh-CN.md';
|
||||||
import US from '../index.en-US.md';
|
import US from '../index.en-US.md';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
@ -31,6 +35,8 @@ export default defineComponent({
|
||||||
CN,
|
CN,
|
||||||
US,
|
US,
|
||||||
components: {
|
components: {
|
||||||
|
iconVue,
|
||||||
|
statusVue,
|
||||||
prefixVue,
|
prefixVue,
|
||||||
Basic,
|
Basic,
|
||||||
Disabled,
|
Disabled,
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<docs>
|
||||||
|
---
|
||||||
|
order: 19
|
||||||
|
version: 3.3.0
|
||||||
|
title:
|
||||||
|
zh-CN: 自定义状态
|
||||||
|
en-US: Status
|
||||||
|
---
|
||||||
|
|
||||||
|
## zh-CN
|
||||||
|
|
||||||
|
使用 `status` 为 InputNumber 添加状态,可选 `error` 或者 `warning`。
|
||||||
|
|
||||||
|
## en-US
|
||||||
|
|
||||||
|
Add status to InputNumber with `status`, which could be `error` or `warning`.
|
||||||
|
|
||||||
|
</docs>
|
||||||
|
<template>
|
||||||
|
<a-space direction="vertical" style="width: 100%">
|
||||||
|
<a-input-number status="error" style="width: 100%" />
|
||||||
|
<a-input-number status="warning" style="width: 100%" />
|
||||||
|
<a-input-number status="error" style="width: 100%">
|
||||||
|
<template #prefix><ClockCircleOutlined /></template>
|
||||||
|
</a-input-number>
|
||||||
|
<a-input-number status="warning" style="width: 100%">
|
||||||
|
<template #prefix><ClockCircleOutlined /></template>
|
||||||
|
</a-input-number>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { ClockCircleOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
ClockCircleOutlined,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -31,9 +31,12 @@ When a numeric value needs to be provided.
|
||||||
| precision | precision of input value | number | - | |
|
| precision | precision of input value | number | - | |
|
||||||
| prefix | The prefix icon for the Input | slot | - | 3.0 |
|
| prefix | The prefix icon for the Input | slot | - | 3.0 |
|
||||||
| size | height of input box | string | - | |
|
| size | height of input box | string | - | |
|
||||||
|
| status | Set validation status | 'error' \| 'warning' | - | 3.3.0 |
|
||||||
| step | The number to which the current value is increased or decreased. It can be an integer or decimal. | number\|string | 1 | |
|
| step | The number to which the current value is increased or decreased. It can be an integer or decimal. | number\|string | 1 | |
|
||||||
| stringMode | Set value as string to support high precision decimals. Will return string value by `change` | boolean | false | 3.0 |
|
| stringMode | Set value as string to support high precision decimals. Will return string value by `change` | boolean | false | 3.0 |
|
||||||
| value(v-model) | current value | number | | |
|
| value(v-model) | current value | number | | |
|
||||||
|
| upIcon | custom up icon | slot | `<UpOutlined />` | 3.3.0 |
|
||||||
|
| downIcon | custom up down | slot | `<DownOutlined />` | 3.3.0 |
|
||||||
|
|
||||||
### events
|
### events
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
import type { PropType, ExtractPropTypes, HTMLAttributes, App } from 'vue';
|
import type { PropType, ExtractPropTypes, HTMLAttributes, App } from 'vue';
|
||||||
import { watch, defineComponent, nextTick, onMounted, ref } from 'vue';
|
import { watch, defineComponent, nextTick, onMounted, ref, computed } from 'vue';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import UpOutlined from '@ant-design/icons-vue/UpOutlined';
|
import UpOutlined from '@ant-design/icons-vue/UpOutlined';
|
||||||
import DownOutlined from '@ant-design/icons-vue/DownOutlined';
|
import DownOutlined from '@ant-design/icons-vue/DownOutlined';
|
||||||
import VcInputNumber, { inputNumberProps as baseInputNumberProps } from './src/InputNumber';
|
import VcInputNumber, { inputNumberProps as baseInputNumberProps } from './src/InputNumber';
|
||||||
import type { SizeType } from '../config-provider';
|
import type { SizeType } from '../config-provider';
|
||||||
import { useInjectFormItemContext } from '../form/FormItemContext';
|
import {
|
||||||
|
FormItemInputContext,
|
||||||
|
NoFormStatus,
|
||||||
|
useInjectFormItemContext,
|
||||||
|
} from '../form/FormItemContext';
|
||||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
import { cloneElement } from '../_util/vnode';
|
import { cloneElement } from '../_util/vnode';
|
||||||
import omit from '../_util/omit';
|
import omit from '../_util/omit';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import isValidValue from '../_util/isValidValue';
|
import isValidValue from '../_util/isValidValue';
|
||||||
|
import type { InputStatus } from '../_util/statusUtils';
|
||||||
|
import { getStatusClassNames, getMergedStatus } from '../_util/statusUtils';
|
||||||
const baseProps = baseInputNumberProps();
|
const baseProps = baseInputNumberProps();
|
||||||
export const inputNumberProps = () => ({
|
export const inputNumberProps = () => ({
|
||||||
...baseProps,
|
...baseProps,
|
||||||
|
@ -25,6 +31,7 @@ export const inputNumberProps = () => ({
|
||||||
prefix: PropTypes.any,
|
prefix: PropTypes.any,
|
||||||
'onUpdate:value': baseProps.onChange,
|
'onUpdate:value': baseProps.onChange,
|
||||||
valueModifiers: Object,
|
valueModifiers: Object,
|
||||||
|
status: String as PropType<InputStatus>,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type InputNumberProps = Partial<ExtractPropTypes<ReturnType<typeof inputNumberProps>>>;
|
export type InputNumberProps = Partial<ExtractPropTypes<ReturnType<typeof inputNumberProps>>>;
|
||||||
|
@ -37,6 +44,8 @@ const InputNumber = defineComponent({
|
||||||
slots: ['addonBefore', 'addonAfter', 'prefix'],
|
slots: ['addonBefore', 'addonAfter', 'prefix'],
|
||||||
setup(props, { emit, expose, attrs, slots }) {
|
setup(props, { emit, expose, attrs, slots }) {
|
||||||
const formItemContext = useInjectFormItemContext();
|
const formItemContext = useInjectFormItemContext();
|
||||||
|
const formItemInputContext = FormItemInputContext.useInject();
|
||||||
|
const mergedStatus = computed(() => getMergedStatus(formItemInputContext.status, props.status));
|
||||||
const { prefixCls, size, direction } = useConfigInject('input-number', props);
|
const { prefixCls, size, direction } = useConfigInject('input-number', props);
|
||||||
const mergedValue = ref(props.value === undefined ? props.defaultValue : props.value);
|
const mergedValue = ref(props.value === undefined ? props.defaultValue : props.value);
|
||||||
const focused = ref(false);
|
const focused = ref(false);
|
||||||
|
@ -84,6 +93,7 @@ const InputNumber = defineComponent({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
|
const { hasFeedback, isFormItemInput, feedbackIcon } = formItemInputContext;
|
||||||
const {
|
const {
|
||||||
class: className,
|
class: className,
|
||||||
bordered,
|
bordered,
|
||||||
|
@ -106,7 +116,9 @@ const InputNumber = defineComponent({
|
||||||
[`${preCls}-rtl`]: direction.value === 'rtl',
|
[`${preCls}-rtl`]: direction.value === 'rtl',
|
||||||
[`${preCls}-readonly`]: readonly,
|
[`${preCls}-readonly`]: readonly,
|
||||||
[`${preCls}-borderless`]: !bordered,
|
[`${preCls}-borderless`]: !bordered,
|
||||||
|
[`${preCls}-in-form-item`]: isFormItemInput,
|
||||||
},
|
},
|
||||||
|
getStatusClassNames(preCls, mergedStatus.value),
|
||||||
className,
|
className,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -123,14 +135,22 @@ const InputNumber = defineComponent({
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
onFocus={handleFocus}
|
onFocus={handleFocus}
|
||||||
v-slots={{
|
v-slots={{
|
||||||
upHandler: () => <UpOutlined class={`${preCls}-handler-up-inner`} />,
|
upHandler: slots.upIcon
|
||||||
downHandler: () => <DownOutlined class={`${preCls}-handler-down-inner`} />,
|
? () => <span class={`${preCls}-handler-up-inner`}>{slots.upIcon()}</span>
|
||||||
|
: () => <UpOutlined class={`${preCls}-handler-up-inner`} />,
|
||||||
|
downHandler: slots.downIcon
|
||||||
|
? () => <span class={`${preCls}-handler-down-inner`}>{slots.downIcon()}</span>
|
||||||
|
: () => <DownOutlined class={`${preCls}-handler-down-inner`} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const hasAddon = isValidValue(addonBefore) || isValidValue(addonAfter);
|
const hasAddon = isValidValue(addonBefore) || isValidValue(addonAfter);
|
||||||
if (isValidValue(prefix)) {
|
const hasPrefix = isValidValue(prefix);
|
||||||
const affixWrapperCls = classNames(`${preCls}-affix-wrapper`, {
|
if (hasPrefix || hasFeedback) {
|
||||||
|
const affixWrapperCls = classNames(
|
||||||
|
`${preCls}-affix-wrapper`,
|
||||||
|
getStatusClassNames(`${preCls}-affix-wrapper`, mergedStatus.value, hasFeedback),
|
||||||
|
{
|
||||||
[`${preCls}-affix-wrapper-focused`]: focused.value,
|
[`${preCls}-affix-wrapper-focused`]: focused.value,
|
||||||
[`${preCls}-affix-wrapper-disabled`]: props.disabled,
|
[`${preCls}-affix-wrapper-disabled`]: props.disabled,
|
||||||
[`${preCls}-affix-wrapper-sm`]: size.value === 'small',
|
[`${preCls}-affix-wrapper-sm`]: size.value === 'small',
|
||||||
|
@ -140,15 +160,17 @@ const InputNumber = defineComponent({
|
||||||
[`${preCls}-affix-wrapper-borderless`]: !bordered,
|
[`${preCls}-affix-wrapper-borderless`]: !bordered,
|
||||||
// className will go to addon wrapper
|
// className will go to addon wrapper
|
||||||
[`${className}`]: !hasAddon && className,
|
[`${className}`]: !hasAddon && className,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
element = (
|
element = (
|
||||||
<div
|
<div
|
||||||
class={affixWrapperCls}
|
class={affixWrapperCls}
|
||||||
style={style}
|
style={style}
|
||||||
onMouseup={() => inputNumberRef.value!.focus()}
|
onMouseup={() => inputNumberRef.value!.focus()}
|
||||||
>
|
>
|
||||||
<span class={`${preCls}-prefix`}>{prefix}</span>
|
{hasPrefix && <span class={`${preCls}-prefix`}>{prefix}</span>}
|
||||||
{element}
|
{element}
|
||||||
|
{hasFeedback && <span class={`${preCls}-suffix`}>{feedbackIcon}</span>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -172,14 +194,15 @@ const InputNumber = defineComponent({
|
||||||
[`${preCls}-group-wrapper-lg`]: mergeSize === 'large',
|
[`${preCls}-group-wrapper-lg`]: mergeSize === 'large',
|
||||||
[`${preCls}-group-wrapper-rtl`]: direction.value === 'rtl',
|
[`${preCls}-group-wrapper-rtl`]: direction.value === 'rtl',
|
||||||
},
|
},
|
||||||
|
getStatusClassNames(`${prefixCls}-group-wrapper`, mergedStatus.value, hasFeedback),
|
||||||
className,
|
className,
|
||||||
);
|
);
|
||||||
element = (
|
element = (
|
||||||
<div class={mergedGroupClassName} style={style}>
|
<div class={mergedGroupClassName} style={style}>
|
||||||
<div class={mergedWrapperClassName}>
|
<div class={mergedWrapperClassName}>
|
||||||
{addonBeforeNode}
|
{addonBeforeNode && <NoFormStatus>{addonBeforeNode}</NoFormStatus>}
|
||||||
{element}
|
{element}
|
||||||
{addonAfterNode}
|
{addonAfterNode && <NoFormStatus>{addonAfterNode}</NoFormStatus>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -34,8 +34,11 @@ cover: https://gw.alipayobjects.com/zos/alicdn/XOS8qZ0kU/InputNumber.svg
|
||||||
| precision | 数值精度 | number | - | |
|
| precision | 数值精度 | number | - | |
|
||||||
| prefix | 带有前缀图标的 input | slot | - | 3.0 |
|
| prefix | 带有前缀图标的 input | slot | - | 3.0 |
|
||||||
| size | 输入框大小 | string | 无 | |
|
| size | 输入框大小 | string | 无 | |
|
||||||
|
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
|
||||||
| step | 每次改变步数,可以为小数 | number\|string | 1 | |
|
| step | 每次改变步数,可以为小数 | number\|string | 1 | |
|
||||||
| stringMode | 字符值模式,开启后支持高精度小数。同时 `change` 事件将返回 string 类型 | boolean | false | 3.0 |
|
| stringMode | 字符值模式,开启后支持高精度小数。同时 `change` 事件将返回 string 类型 | boolean | false | 3.0 |
|
||||||
|
| upIcon | 自定义上箭头图标 | slot | `<UpOutlined />` | 3.3.0 |
|
||||||
|
| downIcon | 自定义下箭头图标 | slot | `<DownOutlined />` | 3.3.0 |
|
||||||
| value(v-model) | 当前值 | number | | |
|
| value(v-model) | 当前值 | number | | |
|
||||||
|
|
||||||
### 事件
|
### 事件
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
&-affix-wrapper {
|
&-affix-wrapper {
|
||||||
.input();
|
.input();
|
||||||
// or number handler will cover form status
|
// or number handler will cover form status
|
||||||
position: static;
|
position: relative;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
width: 90px;
|
width: 90px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -49,14 +49,33 @@
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
content: '\a0';
|
content: '\a0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.@{ant-prefix}-input-number-handler-wrap {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-prefix {
|
&-prefix,
|
||||||
|
&-suffix {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: none;
|
flex: none;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-prefix {
|
||||||
margin-inline-end: @input-affix-margin;
|
margin-inline-end: @input-affix-margin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-suffix {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1;
|
||||||
|
height: 100%;
|
||||||
|
margin-right: @input-padding-horizontal-base;
|
||||||
|
margin-left: @input-affix-margin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{ant-prefix}-input-number-group-wrapper .@{ant-prefix}-input-number-affix-wrapper {
|
.@{ant-prefix}-input-number-group-wrapper .@{ant-prefix}-input-number-affix-wrapper {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
@import '../../style/mixins/index';
|
@import '../../style/mixins/index';
|
||||||
@import '../../input/style/mixin';
|
@import '../../input/style/mixin';
|
||||||
@import './affix';
|
@import './affix';
|
||||||
|
@import './status';
|
||||||
|
|
||||||
@input-number-prefix-cls: ~'@{ant-prefix}-input-number';
|
@input-number-prefix-cls: ~'@{ant-prefix}-input-number';
|
||||||
@form-item-prefix-cls: ~'@{ant-prefix}-form-item';
|
@form-item-prefix-cls: ~'@{ant-prefix}-form-item';
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
@import '../../input/style/mixin';
|
||||||
|
|
||||||
|
@input-number-prefix-cls: ~'@{ant-prefix}-input-number';
|
||||||
|
|
||||||
|
@input-number-wrapper-cls: @input-number-prefix-cls, ~'@{input-number-prefix-cls}-affix-wrapper';
|
||||||
|
|
||||||
|
each(@input-number-wrapper-cls, {
|
||||||
|
.@{value} {
|
||||||
|
&-status-error {
|
||||||
|
.status-color(@value, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);
|
||||||
|
.status-color-common(@input-number-prefix-cls, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline)
|
||||||
|
}
|
||||||
|
|
||||||
|
&-status-warning {
|
||||||
|
.status-color(@value, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
|
||||||
|
.status-color-common(@input-number-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
.@{input-number-prefix-cls}-group-wrapper {
|
||||||
|
&-status-error {
|
||||||
|
.group-status-color(@input-number-prefix-cls, @error-color, @error-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-status-warning {
|
||||||
|
.group-status-color(@input-number-prefix-cls, @warning-color, @warning-color);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue