UNPKG

@douyinfe/semi-ui

Version:

A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.

438 lines 15.1 kB
import _get from "lodash/get"; import _noop from "lodash/noop"; var __rest = this && this.__rest || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import ConfigContext from '../configProvider/context'; import BaseComponent from '../_base/baseComponent'; import { strings, cssClasses } from '@douyinfe/semi-foundation/lib/es/timePicker/constants'; import Popover from '../popover'; import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/lib/es/popover/constants'; import TimePickerFoundation from '@douyinfe/semi-foundation/lib/es/timePicker/foundation'; import isNullOrUndefined from '@douyinfe/semi-foundation/lib/es/utils/isNullOrUndefined'; import Combobox from './Combobox'; import TimeInput from './TimeInput'; import { PanelShape, PanelShapeDefaults } from './PanelShape'; import { TimeShape } from './TimeShape'; import '@douyinfe/semi-foundation/lib/es/timePicker/timePicker.css'; import Trigger from '../trigger'; export default class TimePicker extends BaseComponent { constructor(props) { var _this; super(props); _this = this; this.onCurrentSelectPanelChange = currentSelectPanel => { this.setState({ currentSelectPanel }); }; this.handlePanelChange = (value, index) => this.foundation.handlePanelChange(value, index); this.handleInput = value => this.foundation.handleInputChange(value); this.createPanelProps = function () { let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; const { panels, panelFooter, panelHeader, locale } = _this.props; const panelProps = { panelHeader, panelFooter }; if (_this.adapter.isRangePicker()) { const defaultHeaderMap = { 0: locale.begin, 1: locale.end }; panelProps.panelHeader = _get(panels, index, isNullOrUndefined(panelHeader) ? _get(defaultHeaderMap, index, null) : Array.isArray(panelHeader) ? panelHeader[index] : panelHeader); panelProps.panelFooter = _get(panels, index, Array.isArray(panelFooter) ? panelFooter[index] : panelFooter); } return panelProps; }; /* istanbul ignore next */ this.handlePanelVisibleChange = visible => this.foundation.handleVisibleChange(visible); this.openPanel = () => { this.foundation.handlePanelOpen(); }; this.handleFocus = e => { this.foundation.handleFocus(e); }; this.handleBlur = e => this.foundation.handleInputBlur(e); this.setTimePickerRef = node => this.timePickerRef.current = node; const { format = strings.DEFAULT_FORMAT } = props; this.state = { open: props.open || props.defaultOpen || false, value: [], inputValue: '', currentSelectPanel: 0, isAM: [true, false], showHour: Boolean(format.match(/HH|hh|H|h/g)), showMinute: Boolean(format.match(/mm/g)), showSecond: Boolean(format.match(/ss/g)), invalid: undefined }; this.foundation = new TimePickerFoundation(this.adapter); this.timePickerRef = /*#__PURE__*/React.createRef(); this.savePanelRef = /*#__PURE__*/React.createRef(); this.useCustomTrigger = typeof this.props.triggerRender === 'function'; } get adapter() { var _this2 = this; return Object.assign(Object.assign({}, super.adapter), { togglePanel: show => { this.setState({ open: show }); }, registerClickOutSide: () => { if (this.clickOutSideHandler) { this.adapter.unregisterClickOutSide(); } this.clickOutSideHandler = e => { const panel = this.savePanelRef && this.savePanelRef.current; const trigger = this.timePickerRef && this.timePickerRef.current; const target = e.target; const path = e.composedPath && e.composedPath() || [target]; if (!(panel && panel.contains(target)) && !(trigger && trigger.contains(target)) && !(path.includes(trigger) || path.includes(panel))) { this.foundation.handlePanelClose(true, e); } }; document.addEventListener('mousedown', this.clickOutSideHandler); }, setInputValue: (inputValue, cb) => this.setState({ inputValue }, cb), unregisterClickOutSide: () => { if (this.clickOutSideHandler) { document.removeEventListener('mousedown', this.clickOutSideHandler); this.clickOutSideHandler = null; } }, notifyOpenChange: function () { return _this2.props.onOpenChange(...arguments); }, notifyChange: (agr1, arg2) => this.props.onChange && this.props.onChange(agr1, arg2), notifyFocus: function () { return _this2.props.onFocus && _this2.props.onFocus(...arguments); }, notifyBlur: function () { return _this2.props.onBlur && _this2.props.onBlur(...arguments); }, isRangePicker: () => this.props.type === strings.TYPE_TIME_RANGE_PICKER }); } static getDerivedStateFromProps(nextProps, prevState) { if ('open' in nextProps && nextProps.open !== prevState.open) { return { open: nextProps.open }; } return null; } componentDidUpdate(prevProps) { // if (this.isControlled('open') && this.props.open != null && this.props.open !== prevProps.open) { // this.foundation.setPanel(this.props.open); // } if (this.isControlled('value') && this.props.value !== prevProps.value) { this.foundation.refreshProps(Object.assign({}, this.props)); } else if (this.props.timeZone !== prevProps.timeZone) { this.foundation.refreshProps({ timeZone: this.props.timeZone, __prevTimeZone: prevProps.timeZone, value: this.state.value }); } } getPanelElement() { const { prefixCls, type } = this.props; const { isAM, value } = this.state; const format = this.foundation.getDefaultFormatIfNeed(); const timePanels = [/*#__PURE__*/React.createElement(Combobox, Object.assign({}, this.props, { key: 0, format: format, isAM: isAM[0], timeStampValue: value[0], prefixCls: `${prefixCls}-panel`, onChange: v => this.handlePanelChange(v, 0), onCurrentSelectPanelChange: this.onCurrentSelectPanelChange }, this.createPanelProps(0)))]; if (type === strings.TYPE_TIME_RANGE_PICKER) { timePanels.push(/*#__PURE__*/React.createElement(Combobox, Object.assign({}, this.props, { key: 1, format: format, isAM: isAM[1], timeStampValue: value[1], prefixCls: `${prefixCls}-panel`, onChange: v => this.handlePanelChange(v, 1), onCurrentSelectPanelChange: this.onCurrentSelectPanelChange }, this.createPanelProps(1)))); } const wrapCls = classNames({ [cssClasses.RANGE_PANEL_LISTS]: this.adapter.isRangePicker() }); return /*#__PURE__*/React.createElement("div", { ref: this.savePanelRef, className: wrapCls }, timePanels.map(panel => panel)); } getPopupClassName() { const { use12Hours, prefixCls, popupClassName } = this.props; const { showHour, showMinute, showSecond } = this.state; let selectColumnCount = 0; if (showHour) { selectColumnCount += 1; } if (showMinute) { selectColumnCount += 1; } if (showSecond) { selectColumnCount += 1; } if (use12Hours) { selectColumnCount += 1; } return classNames(`${prefixCls}-panel`, popupClassName, { [`${prefixCls}-panel-narrow`]: (!showHour || !showMinute || !showSecond) && !use12Hours, [cssClasses.RANGE_PICKER]: this.adapter.isRangePicker() }, `${prefixCls}-panel-column-${selectColumnCount}`); } focus() { // TODO this.picker is undefined, confirm keep this func or not // this.picker.focus(); } blur() { // TODO this.picker is undefined, confirm keep this func or not // this.picker.blur(); } render() { const _a = this.props, { prefixCls, placeholder, disabled, defaultValue, dropdownMargin, className, popupStyle, size, style, locale, localeCode, zIndex, getPopupContainer, insetLabel, insetLabelId, inputStyle, showClear, panelHeader, panelFooter, rangeSeparator, onOpenChange, onChangeWithDateFirst, popupClassName: propPopupClassName, hideDisabledOptions, use12Hours, minuteStep, hourStep, secondStep, scrollItemProps, triggerRender, motion, autoAdjustOverflow, stopPropagation } = _a, rest = __rest(_a, ["prefixCls", "placeholder", "disabled", "defaultValue", "dropdownMargin", "className", "popupStyle", "size", "style", "locale", "localeCode", "zIndex", "getPopupContainer", "insetLabel", "insetLabelId", "inputStyle", "showClear", "panelHeader", "panelFooter", "rangeSeparator", "onOpenChange", "onChangeWithDateFirst", "popupClassName", "hideDisabledOptions", "use12Hours", "minuteStep", "hourStep", "secondStep", "scrollItemProps", "triggerRender", "motion", "autoAdjustOverflow", "stopPropagation"]); const format = this.foundation.getDefaultFormatIfNeed(); const position = this.foundation.getPosition(); const { open, inputValue, invalid, value } = this.state; const popupClassName = this.getPopupClassName(); const headerPrefix = classNames({ [`${prefixCls}-header`]: true }); const panelPrefix = classNames({ [`${prefixCls}-panel`]: true, [`${prefixCls}-panel-${size}`]: size }); const inputProps = Object.assign(Object.assign({}, rest), { disabled, prefixCls, size, showClear: disabled ? false : showClear, style: inputStyle, value: inputValue, onFocus: this.handleFocus, insetLabel, insetLabelId, format, locale, localeCode, invalid, placeholder, onChange: this.handleInput, onBlur: this.handleBlur }); const outerProps = {}; if (this.useCustomTrigger) { outerProps.onClick = this.openPanel; } return /*#__PURE__*/React.createElement("div", Object.assign({ ref: this.setTimePickerRef, className: classNames({ [prefixCls]: true }, className), style: style }, outerProps), /*#__PURE__*/React.createElement(Popover, { getPopupContainer: getPopupContainer, zIndex: zIndex, prefixCls: panelPrefix, contentClassName: popupClassName, style: popupStyle, content: this.getPanelElement(), trigger: 'custom', position: position, visible: disabled ? false : Boolean(open), motion: motion, margin: dropdownMargin, autoAdjustOverflow: autoAdjustOverflow, stopPropagation: stopPropagation }, this.useCustomTrigger ? (/*#__PURE__*/React.createElement(Trigger, { triggerRender: triggerRender, disabled: disabled, value: value, inputValue: inputValue, onChange: this.handleInput, placeholder: placeholder, componentName: 'TimePicker', componentProps: Object.assign({}, this.props) })) : (/*#__PURE__*/React.createElement("span", { className: headerPrefix }, /*#__PURE__*/React.createElement(TimeInput, Object.assign({}, inputProps)))))); } } TimePicker.contextType = ConfigContext; TimePicker.propTypes = Object.assign(Object.assign({ 'aria-labelledby': PropTypes.string, 'aria-invalid': PropTypes.bool, 'aria-errormessage': PropTypes.string, 'aria-describedby': PropTypes.string, 'aria-required': PropTypes.bool, prefixCls: PropTypes.string, borderless: PropTypes.bool, clearText: PropTypes.string, clearIcon: PropTypes.node, value: TimeShape, inputReadOnly: PropTypes.bool, disabled: PropTypes.bool, showClear: PropTypes.bool, defaultValue: TimeShape, open: PropTypes.bool, defaultOpen: PropTypes.bool, onOpenChange: PropTypes.func, position: PropTypes.any, getPopupContainer: PropTypes.func, placeholder: PropTypes.string, format: PropTypes.string, style: PropTypes.object, className: PropTypes.string, popupClassName: PropTypes.string, popupStyle: PropTypes.object, disabledHours: PropTypes.func, disabledMinutes: PropTypes.func, disabledSeconds: PropTypes.func, dropdownMargin: PropTypes.oneOfType([PropTypes.number, PropTypes.object]), hideDisabledOptions: PropTypes.bool, onChange: PropTypes.func, use12Hours: PropTypes.bool, hourStep: PropTypes.number, minuteStep: PropTypes.number, secondStep: PropTypes.number, focusOnOpen: PropTypes.bool, autoFocus: PropTypes.bool, size: PropTypes.oneOf(strings.SIZE), stopPropagation: PropTypes.bool, panels: PropTypes.arrayOf(PropTypes.shape(PanelShape)), onFocus: PropTypes.func, onBlur: PropTypes.func, locale: PropTypes.object, localeCode: PropTypes.string, dateFnsLocale: PropTypes.object, zIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), insetLabel: PropTypes.node, insetLabelId: PropTypes.string, validateStatus: PropTypes.oneOf(strings.STATUS), type: PropTypes.oneOf(strings.TYPES), rangeSeparator: PropTypes.string, triggerRender: PropTypes.func, timeZone: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), scrollItemProps: PropTypes.object, motion: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.object]), autoAdjustOverflow: PropTypes.bool }, PanelShape), { inputStyle: PropTypes.object, preventScroll: PropTypes.bool }); TimePicker.defaultProps = Object.assign({ autoAdjustOverflow: true, borderless: false, getPopupContainer: () => document.body, showClear: true, zIndex: popoverNumbers.DEFAULT_Z_INDEX, rangeSeparator: strings.DEFAULT_RANGE_SEPARATOR, onOpenChange: _noop, clearText: 'clear', prefixCls: cssClasses.PREFIX, inputReadOnly: false, style: {}, stopPropagation: true, className: '', popupClassName: '', popupStyle: { left: '0px', top: '0px' }, disabledHours: () => [], disabledMinutes: () => [], disabledSeconds: () => [], hideDisabledOptions: false, // position: 'bottomLeft', onFocus: _noop, onBlur: _noop, onChange: _noop, onChangeWithDateFirst: true, use12Hours: false, focusOnOpen: false, onKeyDown: _noop, size: 'default', type: strings.DEFAULT_TYPE, motion: true }, PanelShapeDefaults);