@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
JavaScript
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);