errorMessage.tsx 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /* eslint-disable prefer-template */
  2. import React, { PureComponent } from 'react';
  3. import classNames from 'classnames';
  4. import PropTypes from 'prop-types';
  5. import { cssClasses } from '@douyinfe/semi-foundation/form/constants';
  6. import { IconAlertTriangle, IconAlertCircle } from '@douyinfe/semi-icons';
  7. import type { BasicFieldError } from '@douyinfe/semi-foundation/form/interface';
  8. const prefix = cssClasses.PREFIX;
  9. export type ReactFieldError = BasicFieldError | React.ReactNode;
  10. export interface ErrorMessageProps {
  11. error?: ReactFieldError;
  12. className?: string;
  13. style?: React.CSSProperties;
  14. showValidateIcon?: boolean;
  15. validateStatus?: string;
  16. helpText?: React.ReactNode;
  17. isInInputGroup?: boolean;
  18. errorMessageId?: string;
  19. helpTextId?: string
  20. }
  21. export default class ErrorMessage extends PureComponent<ErrorMessageProps> {
  22. static propTypes = {
  23. error: PropTypes.oneOfType([PropTypes.bool, PropTypes.string, PropTypes.array, PropTypes.node]),
  24. className: PropTypes.string,
  25. style: PropTypes.object,
  26. validateStatus: PropTypes.string,
  27. showValidateIcon: PropTypes.bool,
  28. helpText: PropTypes.node,
  29. isInInputGroup: PropTypes.bool,
  30. // internal props
  31. errorMessageId: PropTypes.string,
  32. helpTextId: PropTypes.string,
  33. };
  34. generatorText(error: ReactFieldError) {
  35. const { helpTextId, errorMessageId } = this.props;
  36. const propsError = this.props.error;
  37. let id = errorMessageId;
  38. if (!propsError) {
  39. id = helpTextId;
  40. }
  41. if (typeof error === 'string') {
  42. return <span id={id}>{error}</span>;
  43. } else if (Array.isArray(error)) {
  44. const err = error.filter(e => e);
  45. return err.length ? <span id={id}>{err.join(', ')}</span> : null;
  46. } else if (React.isValidElement(error)) {
  47. return error;
  48. }
  49. return null;
  50. }
  51. render() {
  52. const { error, className, style, validateStatus, helpText, showValidateIcon, isInInputGroup } = this.props;
  53. const cls = classNames(
  54. {
  55. [prefix + '-field-error-message']: Boolean(error),
  56. [prefix + '-field-help-text']: Boolean(helpText),
  57. },
  58. className
  59. );
  60. if (!error && !helpText) {
  61. return null;
  62. }
  63. const iconMap = {
  64. warning: <IconAlertTriangle />,
  65. error: <IconAlertCircle />,
  66. };
  67. const text = error ? this.generatorText(error) : this.generatorText(helpText);
  68. const iconCls = `${prefix }-field-validate-status-icon`;
  69. let icon = null;
  70. if (isInInputGroup) {
  71. icon = <IconAlertCircle className={iconCls} />;
  72. } else {
  73. if (iconMap[validateStatus]) {
  74. icon = React.cloneElement(iconMap[validateStatus], { className: iconCls });
  75. }
  76. }
  77. return (
  78. <div className={cls} style={style}>
  79. {showValidateIcon && text ? icon : null}
  80. {text}
  81. </div>
  82. );
  83. }
  84. }