TimeInput.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /* eslint-disable no-unused-vars */
  2. import React from 'react';
  3. import PropTypes from 'prop-types';
  4. import classNames from 'classnames';
  5. import { strings } from '@douyinfe/semi-foundation/timePicker/constants';
  6. import { noop } from 'lodash';
  7. import Input from '../input';
  8. import BaseComponent, { BaseProps } from '../_base/baseComponent';
  9. import InputFoundation, { TimeInputAdapter } from '@douyinfe/semi-foundation/timePicker/inputFoundation';
  10. import { IconClock } from '@douyinfe/semi-icons';
  11. import { TimePickerProps } from './TimePicker';
  12. export type TimeInputProps = Pick<TimePickerProps,
  13. 'value' |
  14. 'format' |
  15. 'prefixCls' |
  16. 'placeholder' |
  17. 'clearText' |
  18. 'inputReadOnly' |
  19. 'disabled' |
  20. 'type' |
  21. 'timeZone' |
  22. 'defaultOpen' |
  23. 'disabledHours' |
  24. 'disabledMinutes' |
  25. 'disabledSeconds' |
  26. 'dateFnsLocale' |
  27. 'onFocus' |
  28. 'onBlur' |
  29. 'focusOnOpen' |
  30. 'locale' |
  31. 'localeCode' |
  32. 'insetLabel' |
  33. 'validateStatus'> & BaseProps & {
  34. onChange?: (value: string) => void;
  35. onEsc?: () => void;
  36. onClick?: React.MouseEventHandler;
  37. defaultOpenValue?: boolean;
  38. currentSelectPanel?: string;
  39. timeStampValue?: any;
  40. invalid?: boolean;
  41. };
  42. class TimeInput extends BaseComponent<TimeInputProps, any> {
  43. static propTypes = {
  44. format: PropTypes.string,
  45. prefixCls: PropTypes.string,
  46. placeholder: PropTypes.string,
  47. clearText: PropTypes.string,
  48. inputReadOnly: PropTypes.bool,
  49. hourOptions: PropTypes.array,
  50. minuteOptions: PropTypes.array,
  51. secondOptions: PropTypes.array,
  52. disabledHours: PropTypes.func,
  53. disabledMinutes: PropTypes.func,
  54. disabledSeconds: PropTypes.func,
  55. onChange: PropTypes.func,
  56. onFocus: PropTypes.func,
  57. onBlur: PropTypes.func,
  58. onEsc: PropTypes.func,
  59. onClick: PropTypes.func,
  60. defaultOpenValue: PropTypes.object,
  61. currentSelectPanel: PropTypes.string,
  62. focusOnOpen: PropTypes.bool,
  63. timeStampValue: PropTypes.any,
  64. locale: PropTypes.object,
  65. localeCode: PropTypes.string,
  66. insetLabel: PropTypes.node,
  67. validateStatus: PropTypes.string,
  68. };
  69. static defaultProps = {
  70. inputReadOnly: false,
  71. onChange: noop,
  72. onBlur: noop,
  73. onFocus: noop,
  74. onClick: noop,
  75. disabledHours: noop,
  76. disabledMinutes: noop,
  77. disabledSeconds: noop,
  78. format: strings.DEFAULT_FORMAT,
  79. };
  80. foundation: InputFoundation;
  81. constructor(props: TimeInputProps) {
  82. super(props);
  83. this.foundation = new InputFoundation(this.adapter);
  84. this.state = {
  85. // focusing: props.focusOnOpen,
  86. };
  87. }
  88. componentDidMount() {
  89. super.componentDidMount();
  90. const { focusOnOpen } = this.props;
  91. if (focusOnOpen) {
  92. const requestAnimationFrame = window.requestAnimationFrame || window.setTimeout;
  93. requestAnimationFrame(() => {
  94. const inputNode = this.adapter.getCache('inputNode');
  95. if (inputNode) {
  96. inputNode.focus();
  97. inputNode.select();
  98. }
  99. });
  100. }
  101. }
  102. componentDidUpdate(prevProps: TimeInputProps) {
  103. const { timeStampValue } = this.props;
  104. if (this.isControlled('timeStampValue') && timeStampValue !== this.state.timeStampValue) {
  105. this.foundation.restoreCursor();
  106. }
  107. if (this.props.value !== prevProps.value) {
  108. this.foundation.restoreCursor();
  109. }
  110. }
  111. get adapter(): TimeInputAdapter {
  112. return {
  113. ...super.adapter,
  114. notifyChange: (...args) => this.props.onChange(...args),
  115. notifyFocus: (...args) => this.props.onFocus(...args),
  116. notifyBlur: (...args) => this.props.onBlur(...args),
  117. };
  118. }
  119. setRef = (node: HTMLElement) => this.adapter.setCache('inputNode', node);
  120. handleClick: React.MouseEventHandler = e => this.props.onClick(e);
  121. handleFocus: React.FocusEventHandler = e => this.foundation.handleFocus(e);
  122. handleBlur: React.FocusEventHandler = e => this.foundation.handleBlur(e);
  123. handleChange = (v: string) => this.foundation.handleChange(v);
  124. getInput() {
  125. const {
  126. prefixCls,
  127. placeholder,
  128. inputReadOnly,
  129. onFocus,
  130. disabled,
  131. type,
  132. locale,
  133. localeCode,
  134. insetLabel,
  135. validateStatus,
  136. value,
  137. onChange,
  138. invalid,
  139. format,
  140. clearText,
  141. disabledHours,
  142. disabledMinutes,
  143. disabledSeconds,
  144. onEsc,
  145. defaultOpenValue,
  146. currentSelectPanel,
  147. focusOnOpen,
  148. timeStampValue,
  149. timeZone,
  150. defaultOpen,
  151. dateFnsLocale,
  152. ...rest
  153. } = this.props;
  154. // const { focusing } = this.state;
  155. const inputCls = classNames(`${prefixCls}-input`, {
  156. [`${prefixCls}-input-invalid`]: invalid,
  157. [`${prefixCls}-input-readonly`]: inputReadOnly,
  158. });
  159. const mergeValidateStatus = invalid ? 'error' : validateStatus;
  160. return (
  161. <Input
  162. {...rest}
  163. hideSuffix
  164. className={inputCls}
  165. ref={this.setRef as any}
  166. value={value as any}
  167. placeholder={placeholder || locale.placeholder[type]}
  168. readonly={Boolean(inputReadOnly)}
  169. onChange={this.handleChange}
  170. onFocus={this.handleFocus}
  171. onBlur={this.handleBlur}
  172. suffix={<IconClock onClick={this.handleClick} />}
  173. validateStatus={mergeValidateStatus}
  174. disabled={disabled}
  175. insetLabel={insetLabel}
  176. />
  177. );
  178. }
  179. render() {
  180. const { prefixCls } = this.props;
  181. return <div className={`${prefixCls}-input-wrap`}>{this.getInput()}</div>;
  182. }
  183. }
  184. export default TimeInput;