All files / src/segment Segment.tsx

93.33% Statements 14/15
100% Branches 8/8
83.33% Functions 5/6
92.86% Lines 13/14

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 113 114 115 116 117 118 119 120 121 122 123 124                                                                                                  9x 9x 1x     21x 3x                           8x                     11x 11x                 37x                                     37x 2x           35x           7x  
import React from "react";
import classNames from "classnames";
import { ControlledProps, useDefaultValue } from "../form/controlled";
import { Combine, StyledProps } from "../_type";
import { Button } from "../button";
import { SegmentOption } from "./SegmentOption";
import { Bubble } from "../bubble";
import { useConfig } from "../_util/config-context";
import { SegmentGroup, SegmentGroupItem } from "./SegmentGroup";
 
export interface SegmentProps
  extends Combine<StyledProps, ControlledProps<string>> {
  /**
   * Segment 中选项
   */
  options: SegmentOption[];
 
  /**
   * 分组
   */
  groups?: {
    [groupKey: string]: React.ReactNode;
  };
 
  /**
   * 是否为无边框样式
   * @default false
   */
  rimless?: boolean;
 
  /**
   * 包含分组时,外层分组容器自定义类名
   */
  groupClassName?: string;
 
  /**
   * 包含分组时,外层分组容器自定义样式
   */
  groupStyle?: React.CSSProperties;
}
 
export function Segment(props: SegmentProps) {
  const {
    value,
    onChange,
    options,
    groups,
    groupClassName,
    groupStyle,
  } = useDefaultValue(props, "");
  if (groups) {
    return (
      <SegmentGroup className={groupClassName} style={groupStyle}>
        {Object.entries(groups).map(([key, name]) => {
          const subOptions = options.filter(i => i.groupKey === key);
          return (
            <SegmentGroupItem name={name} key={key}>
              <SegmentMain
                {...props}
                options={subOptions}
                value={value}
                onChange={onChange}
              />
            </SegmentGroupItem>
          );
        })}
      </SegmentGroup>
    );
  }
  return <SegmentMain {...props} value={value} onChange={onChange} />;
}
 
function SegmentMain({
  className,
  style,
  value,
  onChange,
  options,
  rimless,
}: SegmentProps) {
  const { classPrefix } = useConfig();
  return (
    <div
      className={classNames(`${classPrefix}-segment`, className, {
        [`${classPrefix}-segment--rimless`]: rimless,
      })}
      style={style}
    >
      {options.map(option => {
        const button = (
          <Button
            key={option.value}
            disabled={option.disabled}
            tooltip={option.tooltip}
            htmlType="button"
            className={classNames({
              "is-selected": option.value === value,
            })}
            onClick={
              option.disabled
                ? null
                : event => {
                    onChange(option.value, { event });
                  }
            }
          >
            {option.text || option.value}
          </Button>
        );
        if (option.bubble) {
          return (
            <Bubble key={option.value} content={option.bubble}>
              {button}
            </Bubble>
          );
        }
        return button;
      })}
    </div>
  );
}
 
Segment.defaultLabelAlign = "middle";