TimeInput.tsx 6.1 KB

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