feat: input-date 支持手动输入 (#3677)

* feat: input-date 支持手动输入

* update snapshots
This commit is contained in:
吴多益 2022-03-03 14:31:35 +08:00 committed by GitHub
parent ce7ae06c67
commit a840b910e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 171 additions and 90 deletions

View File

@ -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"
>

View File

@ -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"
>

View File

@ -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')
);

View File

@ -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();
});

View File

@ -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);
});

View File

@ -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);
});

View File

@ -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'));

View File

@ -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 的类型 |

View File

@ -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) {

View File

@ -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}>

View File

@ -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);
}