UNPKG

@carbon/react

Version:

React components for the Carbon Design System

287 lines (282 loc) 9.54 kB
/** * 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 { WarningFilled, WarningAltFilled, Calendar } from '@carbon/icons-react'; import { warning } from '../../internal/warning.js'; import cx from 'classnames'; import PropTypes from 'prop-types'; import React, { useContext, cloneElement } from 'react'; import { usePrefix } from '../../internal/usePrefix.js'; import '../FluidForm/FluidForm.js'; import { FormContext } from '../FluidForm/FormContext.js'; import { useId } from '../../internal/useId.js'; import '../Text/index.js'; import { deprecate } from '../../prop-types/deprecate.js'; import { AILabel } from '../AILabel/index.js'; import { isComponentElement } from '../../internal/utils.js'; import { Text } from '../Text/Text.js'; let didWarnAboutDatePickerInputValue = false; const DatePickerInput = /*#__PURE__*/React.forwardRef(function DatePickerInput(props, ref) { const { datePickerType, decorator, disabled = false, helperText, hideLabel, id, invalid = false, invalidText, labelText, onClick = () => {}, onChange = () => {}, pattern = '\\d{1,2}\\/\\d{1,2}\\/\\d{4}', placeholder, size = 'md', slug, type = 'text', warn, warnText, ...rest } = props; const prefix = usePrefix(); const { isFluid } = useContext(FormContext); const datePickerInputInstanceId = useId(); const datePickerInputProps = { id, onChange: event => { if (!disabled) { onChange(event); } }, onClick: event => { if (!disabled) { onClick(event); } }, pattern, placeholder, type }; if (process.env.NODE_ENV !== 'production' && 'value' in rest && !didWarnAboutDatePickerInputValue) { process.env.NODE_ENV !== "production" ? warning(false, `The 'value' prop is not supported on the DatePickerInput component. ` + `For DatePicker components with 'datePickerType="range"', please ` + `pass the 'value' prop (as an array of dates) to the parent ` + `DatePicker component instead.`) : void 0; didWarnAboutDatePickerInputValue = true; } const wrapperClasses = cx(`${prefix}--date-picker-input__wrapper`, { [`${prefix}--date-picker-input__wrapper--invalid`]: invalid, [`${prefix}--date-picker-input__wrapper--warn`]: warn, [`${prefix}--date-picker-input__wrapper--slug`]: slug, [`${prefix}--date-picker-input__wrapper--decorator`]: decorator }); const labelClasses = cx(`${prefix}--label`, { [`${prefix}--visually-hidden`]: hideLabel, [`${prefix}--label--disabled`]: disabled, [`${prefix}--label--readonly`]: rest.readOnly }); const helperTextClasses = cx(`${prefix}--form__helper-text`, { [`${prefix}--form__helper-text--disabled`]: disabled }); const inputClasses = cx(`${prefix}--date-picker__input`, { [`${prefix}--date-picker__input--${size}`]: size, [`${prefix}--date-picker__input--invalid`]: invalid, [`${prefix}--date-picker__input--warn`]: warn }); const containerClasses = cx(`${prefix}--date-picker-container`, { [`${prefix}--date-picker--nolabel`]: !labelText, [`${prefix}--date-picker--fluid--invalid`]: isFluid && invalid, [`${prefix}--date-picker--fluid--warn`]: isFluid && warn }); const datePickerInputHelperId = !helperText ? undefined : `datepicker-input-helper-text-${datePickerInputInstanceId}`; const inputProps = { ...rest, ...datePickerInputProps, className: inputClasses, disabled, ref, ['aria-describedby']: helperText ? datePickerInputHelperId : undefined }; if (invalid) { inputProps['data-invalid'] = true; } const input = /*#__PURE__*/React.createElement("input", inputProps); // AILabel always size `mini` const candidate = slug ?? decorator; const candidateIsAILabel = isComponentElement(candidate, AILabel); const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, { size: 'mini' }) : null; return /*#__PURE__*/React.createElement("div", { className: containerClasses }, labelText && /*#__PURE__*/React.createElement(Text, { as: "label", htmlFor: id, className: labelClasses }, labelText), /*#__PURE__*/React.createElement("div", { className: wrapperClasses }, /*#__PURE__*/React.createElement("span", null, input, slug ? normalizedDecorator : decorator ? /*#__PURE__*/React.createElement("div", { className: `${prefix}--date-picker-input-inner-wrapper--decorator` }, normalizedDecorator) : '', isFluid && /*#__PURE__*/React.createElement(DatePickerIcon, { datePickerType: datePickerType }), /*#__PURE__*/React.createElement(DatePickerIcon, { datePickerType: datePickerType, invalid: invalid, warn: warn }))), invalid && /*#__PURE__*/React.createElement(React.Fragment, null, isFluid && /*#__PURE__*/React.createElement("hr", { className: `${prefix}--date-picker__divider` }), /*#__PURE__*/React.createElement(Text, { as: "div", className: `${prefix}--form-requirement` }, invalidText)), warn && /*#__PURE__*/React.createElement(React.Fragment, null, isFluid && /*#__PURE__*/React.createElement("hr", { className: `${prefix}--date-picker__divider` }), /*#__PURE__*/React.createElement(Text, { as: "div", className: `${prefix}--form-requirement` }, warnText)), helperText && !invalid && /*#__PURE__*/React.createElement(Text, { as: "div", id: datePickerInputHelperId, className: helperTextClasses }, helperText)); }); DatePickerInput.propTypes = { /** * The type of the date picker: * * * `simple` - Without calendar dropdown. * * `single` - With calendar dropdown and single date. * * `range` - With calendar dropdown and a date range. */ datePickerType: PropTypes.oneOf(['simple', 'single', 'range']), /** * **Experimental**: Provide a decorator component to be rendered inside the `RadioButton` component */ decorator: PropTypes.node, /** * Specify whether or not the input should be disabled */ disabled: PropTypes.bool, /** * Provide text that is used alongside the control label for additional help */ helperText: PropTypes.node, /** * Specify if the label should be hidden */ hideLabel: PropTypes.bool, /** * Specify an id that uniquely identifies the `<input>` */ id: PropTypes.string.isRequired, /** * Specify whether or not the input should be invalid */ invalid: PropTypes.bool, /** * Specify the text to be rendered when the input is invalid */ invalidText: PropTypes.node, /** * Provide the text that will be read by a screen reader when visiting this * control */ labelText: PropTypes.node.isRequired, /** * Specify an `onChange` handler that is called whenever a change in the * input field has occurred */ onChange: PropTypes.func, /** * Provide a function to be called when the input field is clicked */ onClick: PropTypes.func, /** * Provide a regular expression that the input value must match */ pattern: (props, propName, componentName) => { if (props[propName] === undefined) { return; } try { new RegExp(props[propName]); } catch (e) { return new Error(`Invalid value of prop '${propName}' supplied to '${componentName}', it should be a valid regular expression`); } }, /** * Specify the placeholder text */ placeholder: PropTypes.string, /** * whether the DatePicker is to be readOnly */ readOnly: PropTypes.bool, /** * Specify the size of the Date Picker Input. Currently supports either `sm`, `md`, or `lg` as an option. */ size: PropTypes.oneOf(['sm', 'md', 'lg']), slug: deprecate(PropTypes.node, 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'), /** * Specify the type of the `<input>` */ type: PropTypes.string, /** * Specify whether the control is currently in warning state */ warn: PropTypes.bool, /** * Provide the text that is displayed when the control is in warning state */ warnText: PropTypes.node }; function DatePickerIcon({ datePickerType, invalid, warn }) { const prefix = usePrefix(); const { isFluid } = useContext(FormContext); if (datePickerType === 'simple' && !invalid && !warn) { if (!isFluid) { return null; } } if (invalid) { return /*#__PURE__*/React.createElement(WarningFilled, { className: `${prefix}--date-picker__icon ${prefix}--date-picker__icon--invalid` }); } if (!invalid && warn) { return /*#__PURE__*/React.createElement(WarningAltFilled, { className: `${prefix}--date-picker__icon ${prefix}--date-picker__icon--warn` }); } return /*#__PURE__*/React.createElement(Calendar, { className: `${prefix}--date-picker__icon`, role: "img", "aria-hidden": "true" }); } DatePickerIcon.propTypes = { /** * The type of the date picker: * * * `simple` - Without calendar dropdown. * * `single` - With calendar dropdown and single date. * * `range` - With calendar dropdown and a date range. */ datePickerType: PropTypes.oneOf(['simple', 'single', 'range']), /** * Specify whether or not the input should be invalid */ invalid: PropTypes.bool, /** * Specify whether the control is currently in warning state */ warn: PropTypes.bool }; export { DatePickerInput as default };