@carbon/react
Version:
React components for the Carbon Design System
254 lines (250 loc) • 7.58 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2023
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
import cx from 'classnames';
import PropTypes from 'prop-types';
import React, { forwardRef } from 'react';
import { usePrefix } from '../../internal/usePrefix.js';
import { deprecate } from '../../prop-types/deprecate.js';
import { WarningFilled, WarningAltFilled } from '@carbon/icons-react';
const frFn = forwardRef;
const TimePicker = frFn((props, ref) => {
const {
children,
className,
inputClassName,
pickerClassName,
disabled = false,
hideLabel,
id,
invalidText = 'Invalid time format.',
invalid = false,
warningText = 'Warning message.',
warning = false,
labelText,
light = false,
maxLength = 5,
onChange = () => {},
onClick = () => {},
onBlur = () => {},
pattern = '(1[012]|[1-9]):[0-5][0-9](\\s)?',
placeholder = 'hh:mm',
readOnly,
size = 'md',
type = 'text',
value,
...rest
} = props;
const prefix = usePrefix();
const [isValue, setValue] = React.useState(value);
const [prevValue, setPrevValue] = React.useState(value);
if (value !== prevValue) {
setValue(value);
setPrevValue(value);
}
function handleOnClick(evt) {
if (!disabled) {
if (!readOnly) {
setValue(isValue);
}
onClick(evt);
}
}
function handleOnChange(evt) {
if (!disabled && !readOnly) {
setValue(isValue);
onChange(evt);
}
}
function handleOnBlur(evt) {
if (!disabled) {
if (!readOnly) {
setValue(isValue);
}
onBlur(evt);
}
}
const timePickerInputClasses = cx(`${prefix}--time-picker__input-field`, `${prefix}--text-input`, [inputClassName], {
[`${prefix}--text-input--light`]: light,
[`${prefix}--time-picker__input-field-error`]: invalid || warning
});
const timePickerClasses = cx({
[`${prefix}--time-picker`]: true,
[`${prefix}--time-picker--light`]: light,
[`${prefix}--time-picker--invalid`]: invalid,
[`${prefix}--time-picker--warning`]: warning,
[`${prefix}--time-picker--readonly`]: readOnly,
[`${prefix}--time-picker--${size}`]: size,
...(pickerClassName && {
[pickerClassName]: true
})
});
const labelClasses = cx(`${prefix}--label`, {
[`${prefix}--visually-hidden`]: hideLabel,
[`${prefix}--label--disabled`]: disabled
});
const label = labelText ? /*#__PURE__*/React.createElement("label", {
htmlFor: id,
className: labelClasses
}, labelText) : null;
function getInternalPickerSelects() {
const readOnlyEventHandlers = {
onMouseDown: evt => {
// NOTE: does not prevent click
if (readOnly) {
evt.preventDefault();
// focus on the element as per readonly input behavior
evt.target.focus();
}
},
onKeyDown: evt => {
const selectAccessKeys = ['ArrowDown', 'ArrowUp', ' '];
// This prevents the select from opening for the above keys
if (readOnly && selectAccessKeys.includes(evt.key)) {
evt.preventDefault();
}
}
};
const mappedChildren = React.Children.map(children, pickerSelect => {
const item = pickerSelect;
if (item) {
return /*#__PURE__*/React.cloneElement(item, {
...item.props,
disabled: item.props.disabled ?? disabled,
readOnly: readOnly,
...readOnlyEventHandlers
});
}
});
return mappedChildren;
}
const readOnlyProps = {
readOnly: readOnly
};
return /*#__PURE__*/React.createElement("div", {
className: cx(`${prefix}--form-item`, className)
}, label, /*#__PURE__*/React.createElement("div", {
className: timePickerClasses
}, /*#__PURE__*/React.createElement("div", {
className: `${prefix}--time-picker__input`
}, /*#__PURE__*/React.createElement("input", _extends({
className: timePickerInputClasses,
"data-invalid": invalid ? invalid : undefined,
disabled: disabled,
id: id,
maxLength: maxLength,
onClick: handleOnClick,
onChange: handleOnChange,
onBlur: handleOnBlur,
placeholder: placeholder,
pattern: pattern,
ref: ref,
type: type,
value: value
}, rest, readOnlyProps)), (invalid || warning) && /*#__PURE__*/React.createElement("div", {
className: `${prefix}--time-picker__error__icon`
}, invalid ? /*#__PURE__*/React.createElement(WarningFilled, {
className: `${prefix}--checkbox__invalid-icon`,
size: 16
}) : /*#__PURE__*/React.createElement(WarningAltFilled, {
className: `${prefix}--text-input__invalid-icon--warning`,
size: 16
}))), getInternalPickerSelects()), (invalid || warning) && /*#__PURE__*/React.createElement("div", {
className: `${prefix}--form-requirement`
}, invalid ? invalidText : warningText));
});
TimePicker.propTypes = {
/**
* Pass in the children that will be rendered next to the form control
*/
children: PropTypes.node,
/**
* Specify an optional className to be applied to the container node
*/
className: PropTypes.string,
/**
* Specify whether the `<input>` should be disabled
*/
disabled: PropTypes.bool,
/**
* Specify whether you want the underlying label to be visually hidden
*/
hideLabel: PropTypes.bool,
/**
* Specify a custom `id` for the `<input>`
*/
id: PropTypes.string.isRequired,
/**
* Specify whether the control is currently invalid
*/
invalid: PropTypes.bool,
/**
* Provide the text that is displayed when the control is in an invalid state
*/
invalidText: PropTypes.node,
/**
* Provide the text that will be read by a screen reader when visiting this
* control
*/
labelText: PropTypes.node,
/**
* The `light` prop for `TimePicker` has been deprecated. It will be removed in v12. Use the `Layer` component instead.
*/
light: deprecate(PropTypes.bool, 'The `light` prop for `TimePicker` is no longer needed and has been deprecated. It will be removed in the next major release. Use the `Layer` component instead.'),
/**
* Specify the maximum length of the time string in `<input>`
*/
maxLength: PropTypes.number,
/**
* Optionally provide an `onBlur` handler that is called whenever the
* `<input>` loses focus
*/
onBlur: PropTypes.func,
/**
* Optionally provide an `onChange` handler that is called whenever `<input>`
* is updated
*/
onChange: PropTypes.func,
/**
* Optionally provide an `onClick` handler that is called whenever the
* `<input>` is clicked
*/
onClick: PropTypes.func,
/**
* Specify the regular expression working as the pattern of the time string in `<input>`
*/
pattern: PropTypes.string,
/**
* Specify the placeholder attribute for the `<input>`
*/
placeholder: PropTypes.string,
/**
* Specify whether the TimePicker should be read-only
*/
readOnly: PropTypes.bool,
/**
* Specify the size of the Time Picker.
*/
size: PropTypes.oneOf(['sm', 'md', 'lg']),
/**
* Specify the type of the `<input>`
*/
type: PropTypes.string,
/**
* Specify the value of the `<input>`
*/
value: PropTypes.string,
/**
* Specify a warning message
*/
warning: PropTypes.bool,
/**
* Provide the text that is displayed when the control is in an warning state
*/
warningText: PropTypes.node
};
export { TimePicker as default };