1
0

TimeInput.tsx 6.1 KB

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