TimeInput.tsx 6.0 KB

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