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 />
|
||||
<borderlessVue />
|
||||
<prefixVue />
|
||||
<statusVue />
|
||||
<iconVue />
|
||||
</demo-sort>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
@ -23,6 +25,8 @@ import borderlessVue from './borderless.vue';
|
|||
import keyboardVue from './keyboard.vue';
|
||||
import outOfRangeVue from './out-of-range.vue';
|
||||
import prefixVue from './prefix.vue';
|
||||
import statusVue from './status.vue';
|
||||
import iconVue from './icon.vue';
|
||||
import CN from '../index.zh-CN.md';
|
||||
import US from '../index.en-US.md';
|
||||
import { defineComponent } from 'vue';
|
||||
|
@ -31,6 +35,8 @@ export default defineComponent({
|
|||
CN,
|
||||
US,
|
||||
components: {
|
||||
iconVue,
|
||||
statusVue,
|
||||
prefixVue,
|
||||
Basic,
|
||||
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 | - | |
|
||||
| prefix | The prefix icon for the Input | slot | - | 3.0 |
|
||||
| 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 | |
|
||||
| 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 | | |
|
||||
| upIcon | custom up icon | slot | `<UpOutlined />` | 3.3.0 |
|
||||
| downIcon | custom up down | slot | `<DownOutlined />` | 3.3.0 |
|
||||
|
||||
### events
|
||||
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
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 UpOutlined from '@ant-design/icons-vue/UpOutlined';
|
||||
import DownOutlined from '@ant-design/icons-vue/DownOutlined';
|
||||
import VcInputNumber, { inputNumberProps as baseInputNumberProps } from './src/InputNumber';
|
||||
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 { cloneElement } from '../_util/vnode';
|
||||
import omit from '../_util/omit';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import isValidValue from '../_util/isValidValue';
|
||||
import type { InputStatus } from '../_util/statusUtils';
|
||||
import { getStatusClassNames, getMergedStatus } from '../_util/statusUtils';
|
||||
const baseProps = baseInputNumberProps();
|
||||
export const inputNumberProps = () => ({
|
||||
...baseProps,
|
||||
|
@ -25,6 +31,7 @@ export const inputNumberProps = () => ({
|
|||
prefix: PropTypes.any,
|
||||
'onUpdate:value': baseProps.onChange,
|
||||
valueModifiers: Object,
|
||||
status: String as PropType<InputStatus>,
|
||||
});
|
||||
|
||||
export type InputNumberProps = Partial<ExtractPropTypes<ReturnType<typeof inputNumberProps>>>;
|
||||
|
@ -37,6 +44,8 @@ const InputNumber = defineComponent({
|
|||
slots: ['addonBefore', 'addonAfter', 'prefix'],
|
||||
setup(props, { emit, expose, attrs, slots }) {
|
||||
const formItemContext = useInjectFormItemContext();
|
||||
const formItemInputContext = FormItemInputContext.useInject();
|
||||
const mergedStatus = computed(() => getMergedStatus(formItemInputContext.status, props.status));
|
||||
const { prefixCls, size, direction } = useConfigInject('input-number', props);
|
||||
const mergedValue = ref(props.value === undefined ? props.defaultValue : props.value);
|
||||
const focused = ref(false);
|
||||
|
@ -84,6 +93,7 @@ const InputNumber = defineComponent({
|
|||
});
|
||||
});
|
||||
return () => {
|
||||
const { hasFeedback, isFormItemInput, feedbackIcon } = formItemInputContext;
|
||||
const {
|
||||
class: className,
|
||||
bordered,
|
||||
|
@ -106,7 +116,9 @@ const InputNumber = defineComponent({
|
|||
[`${preCls}-rtl`]: direction.value === 'rtl',
|
||||
[`${preCls}-readonly`]: readonly,
|
||||
[`${preCls}-borderless`]: !bordered,
|
||||
[`${preCls}-in-form-item`]: isFormItemInput,
|
||||
},
|
||||
getStatusClassNames(preCls, mergedStatus.value),
|
||||
className,
|
||||
);
|
||||
|
||||
|
@ -123,32 +135,42 @@ const InputNumber = defineComponent({
|
|||
onBlur={handleBlur}
|
||||
onFocus={handleFocus}
|
||||
v-slots={{
|
||||
upHandler: () => <UpOutlined class={`${preCls}-handler-up-inner`} />,
|
||||
downHandler: () => <DownOutlined class={`${preCls}-handler-down-inner`} />,
|
||||
upHandler: slots.upIcon
|
||||
? () => <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);
|
||||
if (isValidValue(prefix)) {
|
||||
const affixWrapperCls = classNames(`${preCls}-affix-wrapper`, {
|
||||
[`${preCls}-affix-wrapper-focused`]: focused.value,
|
||||
[`${preCls}-affix-wrapper-disabled`]: props.disabled,
|
||||
[`${preCls}-affix-wrapper-sm`]: size.value === 'small',
|
||||
[`${preCls}-affix-wrapper-lg`]: size.value === 'large',
|
||||
[`${preCls}-affix-wrapper-rtl`]: direction.value === 'rtl',
|
||||
[`${preCls}-affix-wrapper-readonly`]: readonly,
|
||||
[`${preCls}-affix-wrapper-borderless`]: !bordered,
|
||||
// className will go to addon wrapper
|
||||
[`${className}`]: !hasAddon && className,
|
||||
});
|
||||
const hasPrefix = isValidValue(prefix);
|
||||
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-disabled`]: props.disabled,
|
||||
[`${preCls}-affix-wrapper-sm`]: size.value === 'small',
|
||||
[`${preCls}-affix-wrapper-lg`]: size.value === 'large',
|
||||
[`${preCls}-affix-wrapper-rtl`]: direction.value === 'rtl',
|
||||
[`${preCls}-affix-wrapper-readonly`]: readonly,
|
||||
[`${preCls}-affix-wrapper-borderless`]: !bordered,
|
||||
// className will go to addon wrapper
|
||||
[`${className}`]: !hasAddon && className,
|
||||
},
|
||||
);
|
||||
element = (
|
||||
<div
|
||||
class={affixWrapperCls}
|
||||
style={style}
|
||||
onMouseup={() => inputNumberRef.value!.focus()}
|
||||
>
|
||||
<span class={`${preCls}-prefix`}>{prefix}</span>
|
||||
{hasPrefix && <span class={`${preCls}-prefix`}>{prefix}</span>}
|
||||
{element}
|
||||
{hasFeedback && <span class={`${preCls}-suffix`}>{feedbackIcon}</span>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -172,14 +194,15 @@ const InputNumber = defineComponent({
|
|||
[`${preCls}-group-wrapper-lg`]: mergeSize === 'large',
|
||||
[`${preCls}-group-wrapper-rtl`]: direction.value === 'rtl',
|
||||
},
|
||||
getStatusClassNames(`${prefixCls}-group-wrapper`, mergedStatus.value, hasFeedback),
|
||||
className,
|
||||
);
|
||||
element = (
|
||||
<div class={mergedGroupClassName} style={style}>
|
||||
<div class={mergedWrapperClassName}>
|
||||
{addonBeforeNode}
|
||||
{addonBeforeNode && <NoFormStatus>{addonBeforeNode}</NoFormStatus>}
|
||||
{element}
|
||||
{addonAfterNode}
|
||||
{addonAfterNode && <NoFormStatus>{addonAfterNode}</NoFormStatus>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -34,8 +34,11 @@ cover: https://gw.alipayobjects.com/zos/alicdn/XOS8qZ0kU/InputNumber.svg
|
|||
| precision | 数值精度 | number | - | |
|
||||
| prefix | 带有前缀图标的 input | slot | - | 3.0 |
|
||||
| size | 输入框大小 | string | 无 | |
|
||||
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
|
||||
| step | 每次改变步数,可以为小数 | number\|string | 1 | |
|
||||
| stringMode | 字符值模式,开启后支持高精度小数。同时 `change` 事件将返回 string 类型 | boolean | false | 3.0 |
|
||||
| upIcon | 自定义上箭头图标 | slot | `<UpOutlined />` | 3.3.0 |
|
||||
| downIcon | 自定义下箭头图标 | slot | `<DownOutlined />` | 3.3.0 |
|
||||
| value(v-model) | 当前值 | number | | |
|
||||
|
||||
### 事件
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
&-affix-wrapper {
|
||||
.input();
|
||||
// or number handler will cover form status
|
||||
position: static;
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
width: 90px;
|
||||
padding: 0;
|
||||
|
@ -49,14 +49,33 @@
|
|||
visibility: hidden;
|
||||
content: '\a0';
|
||||
}
|
||||
|
||||
.@{ant-prefix}-input-number-handler-wrap {
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
&-prefix {
|
||||
&-prefix,
|
||||
&-suffix {
|
||||
display: flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&-prefix {
|
||||
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 {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
@import '../../style/mixins/index';
|
||||
@import '../../input/style/mixin';
|
||||
@import './affix';
|
||||
@import './status';
|
||||
|
||||
@input-number-prefix-cls: ~'@{ant-prefix}-input-number';
|
||||
@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