All files / src/checkbox CheckboxGroup.tsx

47.62% Statements 10/21
45% Branches 9/20
66.67% Functions 2/3
47.62% Lines 10/21

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112                                                                                          8x                 8x   8x   8x     25x       25x       25x 25x               25x                                               8x                  
import React from "react";
import invariant from "invariant";
import classNames from "classnames";
import { ControlledProps, useDefaultValue } from "../form/controlled";
import { CheckContext, CheckContextValue } from "../check";
import { CheckChangeContext } from "../check/Check";
import { Combine, StyledProps } from "../_type";
import { useConfig } from "../_util/config-context";
 
/**
 * CheckboxGroup 组件所接收的参数
 */
export interface CheckboxGroupProps
  extends Combine<StyledProps, ControlledProps<string[]>> {
  /**
   * 已选中的值集合,由 `value = true` 的 `<Checkbox />` 的 `name` 属性组成
   */
  value?: string[];
 
  /**
   * 值变更时回调
   */
  onChange?: (value: string[], context: CheckChangeContext) => void;
 
  /**
   * 禁用组件
   * */
  disabled?: boolean;
 
  /**
   * 使用水平布局(`inline`)还是纵向排列布局(`column`)
   * @default "inline"
   */
  layout?: "inline" | "column";
 
  /**
   * 复选框内容
   */
  children?: React.ReactNode;
}
 
/**
 * 单选选项组,里面可以嵌套 <Radio />
 */
export function CheckboxGroup(props: CheckboxGroupProps) {
  const { classPrefix } = useConfig();
  const {
    value,
    onChange,
    disabled,
    layout,
    className,
    style,
    children,
  } = useDefaultValue(props, []);
 
  const checkedSet = new Set(value || []);
 
  const context: CheckContextValue = {
    inject: checkProps => {
      // 只为 checkbox 提供
      Iif (checkProps.type !== "checkbox") {
        return checkProps;
      }
      // 如果已经受控,则不注入
      Iif (typeof checkProps.value === "boolean") {
        return checkProps;
      }
 
      const checkName = checkProps.name;
      Iif (typeof checkName === "undefined") {
        invariant(
          false,
          '<Checkbox> managed by <CheckboxGroup> must include the "name" prop'
        );
        return checkProps;
      }
 
      return {
        ...checkProps,
        value: checkedSet.has(checkName),
        disabled: checkProps.disabled || disabled,
        display: layout === "column" ? "block" : "inline",
        onChange(checked, context) {
          // 支持 checkbox 上的 onChange 处理时阻止默认的处理行为
          if (typeof checkProps.onChange === "function") {
            checkProps.onChange(checked, context);
            if (context.event.defaultPrevented) {
              return;
            }
          }
          if (typeof onChange === "function") {
            const newValue = checked
              ? [...value, checkName]
              : (checkedSet.delete(checkName), Array.from(checkedSet));
            onChange(newValue, context);
          }
        },
      };
    },
  };
 
  return (
    <div
      className={classNames(`${classPrefix}-form-check-group`, className)}
      style={style}
    >
      <CheckContext.Provider value={context}>{children}</CheckContext.Provider>
    </div>
  );
}