group.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /* eslint-disable react/destructuring-assignment */
  2. import React, { Component } from 'react';
  3. import classNames from 'classnames';
  4. import { isString } from 'lodash';
  5. import { isValid } from '@douyinfe/semi-foundation/form/utils';
  6. import { cssClasses } from '@douyinfe/semi-foundation/form/constants';
  7. import * as ObjectUtil from '@douyinfe/semi-foundation/utils/object';
  8. import ErrorMessage, { ReactFieldError } from './errorMessage';
  9. import Label, { LabelProps } from './label';
  10. import { FormUpdaterContext } from './context';
  11. import { useFormState } from './hooks/index';
  12. import InputGroup, { InputGroupProps as BacisInputGroupProps } from '../input/inputGroup';
  13. import { BaseFormProps, FormState } from './interface';
  14. import { FormUpdaterContextType } from '@douyinfe/semi-foundation/form/interface';
  15. interface GroupErrorProps {
  16. showValidateIcon?: boolean;
  17. isInInputGroup?: boolean;
  18. error?: ReactFieldError;
  19. fieldSet?: string[];
  20. }
  21. export interface InputGroupProps extends BacisInputGroupProps {
  22. label?: LabelProps;
  23. labelPosition?: 'left' | 'top';
  24. }
  25. const prefix = cssClasses.PREFIX;
  26. // Group component to remove Labels and ErrorMessages from its child fields
  27. // Unified insertion of Labels and ErrorMessages from the group level
  28. // Get Errors of all field in this group
  29. const GroupError = (props: GroupErrorProps) => {
  30. const { fieldSet } = props;
  31. const formState: FormState = useFormState();
  32. const error = fieldSet.map((field: string) => ObjectUtil.get(formState.errors, field));
  33. if (isValid(error)) {
  34. return null;
  35. }
  36. return (
  37. <ErrorMessage error={error} showValidateIcon={props.showValidateIcon} isInInputGroup={props.isInInputGroup} />
  38. );
  39. };
  40. class FormInputGroup extends Component<InputGroupProps> {
  41. static contextType = FormUpdaterContext;
  42. context: FormUpdaterContextType;
  43. renderLabel(label: LabelProps, formProps: BaseFormProps) {
  44. if (label) {
  45. if (isString(label)) {
  46. return (<Label width={formProps.labelWidth} text={label} />);
  47. } else {
  48. return (<Label width={formProps.labelWidth} {...label} />);
  49. }
  50. }
  51. return null;
  52. }
  53. render() {
  54. const { children, label, ...rest } = this.props;
  55. const updater = this.context;
  56. const formProps = updater.getFormProps(['labelPosition', 'labelWidth', 'labelAlign', 'showValidateIcon']);
  57. const labelPosition = this.props.labelPosition || formProps.labelPosition;
  58. const groupFieldSet: Array<string> = [];
  59. const inner = React.Children.map(children, (child: any) => {
  60. if (child && child.props && child.props.field) {
  61. groupFieldSet.push(child.props.field);
  62. return React.cloneElement(child, {
  63. isInInputGroup: true,
  64. // noErrorMessage: true,
  65. // noLabel: true
  66. });
  67. }
  68. return null;
  69. });
  70. const groupCls = classNames({
  71. [`${prefix}-field-group`]: true
  72. });
  73. return (
  74. <div x-label-pos={labelPosition} className={groupCls}>
  75. {this.renderLabel(label, formProps)}
  76. <div>
  77. <InputGroup {...rest}>
  78. {inner}
  79. </InputGroup>
  80. <GroupError fieldSet={groupFieldSet} showValidateIcon={formProps.showValidateIcon} isInInputGroup />
  81. </div>
  82. </div>
  83. );
  84. }
  85. }
  86. export default FormInputGroup;