mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 02:58:05 +08:00
feat: input-date 支持手动输入 (#3677)
* feat: input-date 支持手动输入 * update snapshots
This commit is contained in:
parent
ce7ae06c67
commit
a840b910e7
@ -56,11 +56,12 @@ exports[`Renderer:date 1`] = `
|
||||
class="cxd-DatePicker"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="cxd-DatePicker-value"
|
||||
>
|
||||
2019-06-06 21:11:00
|
||||
</span>
|
||||
<input
|
||||
autocomplete="off"
|
||||
placeholder="请选择日期以及时间"
|
||||
type="text"
|
||||
value="2019-06-06 21:11:00"
|
||||
/>
|
||||
<a
|
||||
class="cxd-DatePicker-clear"
|
||||
>
|
||||
|
@ -56,11 +56,12 @@ exports[`Renderer:inputDate 1`] = `
|
||||
class="cxd-DatePicker"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="cxd-DatePicker-value"
|
||||
>
|
||||
2019-06-07
|
||||
</span>
|
||||
<input
|
||||
autocomplete="off"
|
||||
placeholder="请选择日期"
|
||||
type="text"
|
||||
value="2019-06-07"
|
||||
/>
|
||||
<a
|
||||
class="cxd-DatePicker-clear"
|
||||
>
|
||||
|
@ -31,8 +31,11 @@ test('Renderer:date', async () => {
|
||||
)
|
||||
);
|
||||
|
||||
const input = container.querySelector('.cxd-DatePicker-value');
|
||||
expect(input?.innerHTML).toEqual(
|
||||
const input = container.querySelector(
|
||||
'.cxd-DatePicker input'
|
||||
)! as HTMLInputElement;
|
||||
|
||||
expect(input.value).toEqual(
|
||||
moment(1559826660, 'X').format('YYYY-MM-DD HH:mm:ss')
|
||||
);
|
||||
|
||||
|
@ -31,10 +31,10 @@ test('Renderer:inputDate', async () => {
|
||||
)
|
||||
);
|
||||
|
||||
const input = container.querySelector('.cxd-DatePicker-value');
|
||||
expect(input?.innerHTML).toEqual(
|
||||
moment(1559836800, 'X').format('YYYY-MM-DD')
|
||||
);
|
||||
const input = container.querySelector(
|
||||
'.cxd-DatePicker input'
|
||||
)! as HTMLInputElement;
|
||||
expect(input.value).toEqual(moment(1559836800, 'X').format('YYYY-MM-DD'));
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
@ -8,7 +8,8 @@ import {makeEnv} from '../../helper';
|
||||
import moment from 'moment';
|
||||
|
||||
test('Renderer:inputMonth click', async () => {
|
||||
const {container, findByText} = render(
|
||||
const {container, findByText, findByPlaceholderText, findByDisplayValue} =
|
||||
render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'form',
|
||||
@ -28,7 +29,7 @@ test('Renderer:inputMonth click', async () => {
|
||||
)
|
||||
);
|
||||
|
||||
const inputDate = await findByText('请选择月份');
|
||||
const inputDate = await findByPlaceholderText('请选择月份');
|
||||
|
||||
fireEvent.click(inputDate);
|
||||
|
||||
@ -43,11 +44,11 @@ test('Renderer:inputMonth click', async () => {
|
||||
|
||||
const lastYearMonth = moment().subtract(1, 'year').format('YYYY') + '-01';
|
||||
|
||||
await findByText(lastYearMonth);
|
||||
await findByDisplayValue(lastYearMonth);
|
||||
|
||||
const value = document.querySelector(
|
||||
'.cxd-DatePicker-value'
|
||||
) as HTMLSpanElement;
|
||||
'.cxd-DatePicker input'
|
||||
) as HTMLInputElement;
|
||||
|
||||
expect(value.innerHTML).toEqual(lastYearMonth);
|
||||
expect(value.value).toEqual(lastYearMonth);
|
||||
});
|
||||
|
@ -8,7 +8,7 @@ import {makeEnv} from '../../helper';
|
||||
import moment from 'moment';
|
||||
|
||||
test('Renderer:inputYear click', async () => {
|
||||
const {container, findByText} = render(
|
||||
const {container, findByPlaceholderText, findByText} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'form',
|
||||
@ -28,7 +28,7 @@ test('Renderer:inputYear click', async () => {
|
||||
)
|
||||
);
|
||||
|
||||
const inputDate = await findByText('请选择年');
|
||||
const inputDate = await findByPlaceholderText('请选择年');
|
||||
|
||||
fireEvent.click(inputDate);
|
||||
|
||||
@ -39,8 +39,8 @@ test('Renderer:inputYear click', async () => {
|
||||
fireEvent.click(thisYear);
|
||||
|
||||
const value = document.querySelector(
|
||||
'.cxd-DatePicker-value'
|
||||
) as HTMLSpanElement;
|
||||
'.cxd-DatePicker input'
|
||||
) as HTMLInputElement;
|
||||
|
||||
expect(value.innerHTML).toEqual(thisYearText);
|
||||
expect(value.value).toEqual(thisYearText);
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ afterAll(() => {
|
||||
});
|
||||
|
||||
test('Renderer:mobile Input Date', async () => {
|
||||
const {container, findByText, getByText} = render(
|
||||
const {container, findByPlaceholderText, getByText} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'form',
|
||||
@ -35,7 +35,7 @@ test('Renderer:mobile Input Date', async () => {
|
||||
)
|
||||
);
|
||||
|
||||
const inputDate = await findByText('请选择日期');
|
||||
const inputDate = await findByPlaceholderText('请选择日期');
|
||||
fireEvent.click(inputDate);
|
||||
|
||||
const confirmButton = document.querySelector(
|
||||
@ -44,9 +44,9 @@ test('Renderer:mobile Input Date', async () => {
|
||||
|
||||
fireEvent.click(confirmButton);
|
||||
|
||||
const value = document.querySelector(
|
||||
'.cxd-DatePicker-value'
|
||||
) as HTMLSpanElement;
|
||||
// const value = document.querySelector(
|
||||
// '.cxd-DatePicker-value'
|
||||
// ) as HTMLSpanElement;
|
||||
|
||||
// TODO: 这里原组件的日错了,等修复
|
||||
// expect(value.innerHTML).toEqual(moment().format('YYYY-MM-DD'));
|
||||
|
@ -84,12 +84,31 @@ order: 51
|
||||
}
|
||||
```
|
||||
|
||||
## 默认值
|
||||
|
||||
和其它表单项一样,如果要设置默认值,可以使用 value 属性
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "form",
|
||||
"debug": true,
|
||||
"body": [
|
||||
{
|
||||
"name": "switch",
|
||||
"type": "switch",
|
||||
"label": "开关",
|
||||
"value": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 属性表
|
||||
|
||||
除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ---------- | -------- | --------- | ------------ |
|
||||
| ---------- | --------------------------- | ------- | -------------------- |
|
||||
| option | `string` | | 选项说明 |
|
||||
| onText | `string / IconSchema` | | 开启时开关显示的内容 |
|
||||
| offText | `string / IconSchema` | | 关闭时开关显示的内容 |
|
||||
@ -100,4 +119,4 @@ IconSchema 配置
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ---------- | -------- | --------- | ------------ |
|
||||
| type | `string` | | `icon` |
|
||||
| icon | `string` | | icon的类型 |
|
||||
| icon | `string` | | icon 的类型 |
|
||||
|
@ -12,6 +12,19 @@
|
||||
background: var(--DatePicker-bg);
|
||||
border-radius: var(--DatePicker-borderRadius);
|
||||
|
||||
input {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
background: none;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
&:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
box-sizing: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include input-border();
|
||||
|
||||
&:not(.is-disabled) {
|
||||
|
@ -17,6 +17,7 @@ import Calendar from './calendar/Calendar';
|
||||
import {localeable, LocaleProps, TranslateFn} from '../locale';
|
||||
import {isMobile, ucFirst} from '../utils/helper';
|
||||
import CalendarMobile from './CalendarMobile';
|
||||
import Input from './Input';
|
||||
|
||||
const availableShortcuts: {[propName: string]: any} = {
|
||||
now: {
|
||||
@ -302,6 +303,7 @@ export interface DatePickerState {
|
||||
isOpened: boolean;
|
||||
isFocused: boolean;
|
||||
value: moment.Moment | undefined;
|
||||
inputValue: string | undefined; // 手动输入的值
|
||||
}
|
||||
|
||||
function normalizeValue(value: any, format?: string) {
|
||||
@ -329,11 +331,15 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
state: DatePickerState = {
|
||||
isOpened: false,
|
||||
isFocused: false,
|
||||
value: normalizeValue(this.props.value, this.props.format)
|
||||
value: normalizeValue(this.props.value, this.props.format),
|
||||
inputValue:
|
||||
normalizeValue(this.props.value, this.props.format)?.format(
|
||||
this.props.inputFormat
|
||||
) || ''
|
||||
};
|
||||
constructor(props: DateProps) {
|
||||
super(props);
|
||||
|
||||
this.inputRef = React.createRef();
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.selectRannge = this.selectRannge.bind(this);
|
||||
this.checkIsValidDate = this.checkIsValidDate.bind(this);
|
||||
@ -348,10 +354,13 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
this.getTarget = this.getTarget.bind(this);
|
||||
this.handlePopOverClick = this.handlePopOverClick.bind(this);
|
||||
this.renderShortCuts = this.renderShortCuts.bind(this);
|
||||
this.inputChange = this.inputChange.bind(this);
|
||||
}
|
||||
|
||||
dom: HTMLDivElement;
|
||||
|
||||
inputRef: React.RefObject<HTMLInputElement>;
|
||||
|
||||
componentDidUpdate(prevProps: DateProps) {
|
||||
const props = this.props;
|
||||
|
||||
@ -403,13 +412,17 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
}
|
||||
|
||||
open(fn?: () => void) {
|
||||
this.props.disabled ||
|
||||
if (this.props.disabled) {
|
||||
return;
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
isOpened: true
|
||||
},
|
||||
fn
|
||||
);
|
||||
const input = this.inputRef.current;
|
||||
input && input.focus();
|
||||
}
|
||||
|
||||
close() {
|
||||
@ -423,6 +436,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
e.stopPropagation();
|
||||
const onChange = this.props.onChange;
|
||||
onChange('');
|
||||
this.setState({inputValue: ''});
|
||||
}
|
||||
|
||||
handleChange(value: moment.Moment) {
|
||||
@ -432,6 +446,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
minDate,
|
||||
maxDate,
|
||||
dateFormat,
|
||||
inputFormat,
|
||||
timeFormat,
|
||||
closeOnSelect,
|
||||
utc,
|
||||
@ -453,6 +468,31 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
if (closeOnSelect && dateFormat && !timeFormat) {
|
||||
this.close();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
inputValue: utc
|
||||
? moment.utc(value).format(inputFormat)
|
||||
: value.format(inputFormat)
|
||||
});
|
||||
}
|
||||
|
||||
// 手动输入日期
|
||||
inputChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const {onChange, inputFormat, format, utc} = this.props;
|
||||
const value = e.currentTarget.value;
|
||||
this.setState({inputValue: value});
|
||||
if (value === '') {
|
||||
onChange('');
|
||||
} else {
|
||||
const newDate = moment(value, inputFormat);
|
||||
const dateValue = utc
|
||||
? moment.utc(newDate).format(format)
|
||||
: newDate.format(format);
|
||||
// 小于 0 的日期丢弃
|
||||
if (!dateValue.startsWith('-')) {
|
||||
onChange(dateValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectRannge(item: any) {
|
||||
@ -693,15 +733,13 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
ref={this.domRef}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{date ? (
|
||||
<span className={cx(`DatePicker-value`)}>
|
||||
{date.format(inputFormat)}
|
||||
</span>
|
||||
) : (
|
||||
<span className={cx(`DatePicker-placeholder`)}>
|
||||
{__(placeholder)}
|
||||
</span>
|
||||
)}
|
||||
<Input
|
||||
onChange={this.inputChange}
|
||||
ref={this.inputRef}
|
||||
placeholder={__(placeholder)}
|
||||
autoComplete="off"
|
||||
value={this.state.inputValue}
|
||||
/>
|
||||
|
||||
{clearable && !disabled && normalizeValue(value, format) ? (
|
||||
<a className={cx(`DatePicker-clear`)} onClick={this.clearValue}>
|
||||
|
@ -161,18 +161,19 @@ class BaseDatePicker extends React.Component<
|
||||
updatedState = this.getStateFromProps(props);
|
||||
}
|
||||
|
||||
if (updatedState.open === undefined) {
|
||||
if (typeof props.open !== 'undefined') {
|
||||
updatedState.open = props.open;
|
||||
} else if (
|
||||
prevProps.closeOnSelect &&
|
||||
this.state.currentView !== viewModes.TIME
|
||||
) {
|
||||
updatedState.open = false;
|
||||
} else {
|
||||
updatedState.open = this.state.open;
|
||||
}
|
||||
}
|
||||
// open 是外部控制了
|
||||
// if (updatedState.open === undefined) {
|
||||
// if (typeof props.open !== 'undefined') {
|
||||
// updatedState.open = props.open;
|
||||
// } else if (
|
||||
// prevProps.closeOnSelect &&
|
||||
// this.state.currentView !== viewModes.TIME
|
||||
// ) {
|
||||
// updatedState.open = false;
|
||||
// } else {
|
||||
// updatedState.open = this.state.open;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (props.viewMode !== prevProps.viewMode) {
|
||||
updatedState.currentView = props.viewMode;
|
||||
@ -236,6 +237,10 @@ class BaseDatePicker extends React.Component<
|
||||
updatedState.viewDate = moment(props.viewDate);
|
||||
}
|
||||
|
||||
if (Object.keys(updatedState).length) {
|
||||
this.setState(updatedState);
|
||||
}
|
||||
|
||||
this.checkTZ(props);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user