@carbon/react
Version:
React components for the Carbon Design System
320 lines (310 loc) • 10.7 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.
*/
;
Object.defineProperty(exports, '__esModule', { value: true });
var iconsReact = require('@carbon/icons-react');
var warning = require('../../internal/warning.js');
var cx = require('classnames');
var PropTypes = require('prop-types');
var React = require('react');
var usePrefix = require('../../internal/usePrefix.js');
require('../FluidForm/FluidForm.js');
var FormContext = require('../FluidForm/FormContext.js');
var useId = require('../../internal/useId.js');
var Text = require('../Text/Text.js');
require('../Text/TextDirection.js');
var deprecate = require('../../prop-types/deprecate.js');
var index = require('../AILabel/index.js');
var utils = require('../../internal/utils.js');
var useNormalizedInputProps = require('../../internal/useNormalizedInputProps.js');
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- https://github.com/carbon-design-system/carbon/issues/20452
let didWarnAboutDatePickerInputValue = false;
const frFn = React.forwardRef;
const DatePickerInput = frFn((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 = false,
warnText,
readOnly,
...rest
} = props;
const prefix = usePrefix.usePrefix();
const {
isFluid
} = React.useContext(FormContext.FormContext);
const datePickerInputInstanceId = useId.useId();
const normalizedProps = useNormalizedInputProps.useNormalizedInputProps({
id,
readOnly,
disabled,
invalid,
invalidText,
warn,
warnText
});
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.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`]: normalizedProps.invalid,
[`${prefix}--date-picker-input__wrapper--warn`]: normalizedProps.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`]: normalizedProps.disabled,
[`${prefix}--label--readonly`]: readOnly
});
const helperTextClasses = cx(`${prefix}--form__helper-text`, {
[`${prefix}--form__helper-text--disabled`]: normalizedProps.disabled
});
const inputClasses = cx(`${prefix}--date-picker__input`, {
[`${prefix}--date-picker__input--${size}`]: size,
[`${prefix}--date-picker__input--invalid`]: normalizedProps.invalid,
[`${prefix}--date-picker__input--warn`]: normalizedProps.warn
});
const containerClasses = cx(`${prefix}--date-picker-container`, {
[`${prefix}--date-picker--nolabel`]: !labelText,
[`${prefix}--date-picker--fluid--invalid`]: isFluid && normalizedProps.invalid,
[`${prefix}--date-picker--fluid--warn`]: isFluid && normalizedProps.warn
});
const datePickerInputHelperId = !helperText ? undefined : `datepicker-input-helper-text-${datePickerInputInstanceId}`;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- https://github.com/carbon-design-system/carbon/issues/20452
const inputProps = {
...rest,
...datePickerInputProps,
className: inputClasses,
disabled: normalizedProps.disabled,
ref,
['aria-describedby']: helperText ? datePickerInputHelperId : undefined
};
if (normalizedProps.invalid) {
inputProps['data-invalid'] = true;
}
const input = /*#__PURE__*/React.createElement("input", inputProps);
// AILabel always size `mini`
const candidate = slug ?? decorator;
const candidateIsAILabel = utils.isComponentElement(candidate, index.AILabel);
const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/React.cloneElement(candidate, {
size: 'mini'
}) : candidate;
return /*#__PURE__*/React.createElement("div", {
className: containerClasses
}, labelText && /*#__PURE__*/React.createElement(Text.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: normalizedProps.invalid,
warn: normalizedProps.warn,
disabled: normalizedProps.disabled,
readOnly: readOnly
}))), normalizedProps.validation, helperText && !normalizedProps.invalid && !normalizedProps.warn && /*#__PURE__*/React.createElement(Text.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
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- https://github.com/carbon-design-system/carbon/issues/20452
pattern: (props, propName, componentName) => {
if (props[propName] === undefined) {
return;
}
try {
new RegExp(props[propName]);
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- https://github.com/carbon-design-system/carbon/issues/20452
} 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.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,
disabled,
readOnly
}) {
const prefix = usePrefix.usePrefix();
const {
isFluid
} = React.useContext(FormContext.FormContext);
if (datePickerType === 'simple' && !invalid && !warn) {
if (!isFluid) {
return null;
}
}
// Don't show invalid/warn icons when disabled or readonly
if (disabled || readOnly) {
return /*#__PURE__*/React.createElement(iconsReact.Calendar, {
className: `${prefix}--date-picker__icon`,
role: "img",
"aria-hidden": "true"
});
}
if (invalid) {
return /*#__PURE__*/React.createElement(iconsReact.WarningFilled, {
className: `${prefix}--date-picker__icon ${prefix}--date-picker__icon--invalid`
});
}
if (!invalid && warn) {
return /*#__PURE__*/React.createElement(iconsReact.WarningAltFilled, {
className: `${prefix}--date-picker__icon ${prefix}--date-picker__icon--warn`
});
}
return /*#__PURE__*/React.createElement(iconsReact.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,
/**
* Specify whether or not the input should be disabled
*/
disabled: PropTypes.bool,
/**
* Specify whether the input is readonly
*/
readOnly: PropTypes.bool
};
exports.default = DatePickerInput;