react-color#ChromePicker TypeScript Examples

The following examples show how to use react-color#ChromePicker. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ColorPicker.tsx    From dnde with GNU General Public License v3.0 6 votes vote down vote up
ColorPicker = ({ handleChange, mouseDown }: ColorPickerProps) => {
  const [color, setColor] = useState(() => '#ccc');

  const handleColorChange = (color: any) => {
    const hexCode = `${color.hex}${decimalToHex(color.rgb.a)}`;
    setColor(hexCode);
    handleChange(`rgba(${color.rgb.r},${color.rgb.g},${color.rgb.b},${color.rgb.a})`);
  };

  return (
    <ColorPickerContainer
      onMouseDown={(e) => {
        if (!mouseDown) {
          e.preventDefault();
          e.stopPropagation();
        }
      }}
      color={color}
    >
      <div className="popover">
        <ChromePicker disableAlpha={false} color={color} onChange={(color: any) => handleColorChange(color)} />
      </div>
    </ColorPickerContainer>
  );
}
Example #2
Source File: BorderCollection.tsx    From dnde with GNU General Public License v3.0 6 votes vote down vote up
ColorPickerComponent = ({
  color,
  setColor,
  showColor,
  setShowColor,
  borderDirection,
}: ColorPickerComponentProps) => {
  let left = '0px';
  if (borderDirection === BorderDirection.Top || borderDirection === BorderDirection.Left) left = '-40px';
  else left = '-200px';

  return (
    <ColorPicker left={left} color={color}>
      <div className="swatch" onClick={() => setShowColor(true)}>
        <div className="color"></div>
      </div>
      {showColor ? (
        <div className="popover">
          <div className="cover" onClick={() => setShowColor(false)}></div>
          <ChromePicker disableAlpha={false} color={color} onChange={(x) => setColor(x.hex)} />
        </div>
      ) : null}
    </ColorPicker>
  );
}
Example #3
Source File: ColorPicker.tsx    From react-resume-site with GNU General Public License v3.0 6 votes vote down vote up
PickerColor = () => {
  const { templateStore } = useStores();
  const [displayPick, setDisplayPicker] = useState(false);

  const collapse =(e:any) => {
    const colorWrapper = document.querySelector('.rs-color-wrapper')
    if(!colorWrapper?.contains(e.target) && displayPick) {
      setDisplayPicker(false);
    }
  }

  document.addEventListener('click', collapse, false);

  return useObserver(() => (
    <div className="rs-color-wrapper">
      <div className="rs-color-btn" style={{ background: templateStore.color }} onClick={() => { setDisplayPicker(!displayPick) }}></div>
      { displayPick && <ChromePicker color={templateStore.color} onChangeComplete={(color) => {
        templateStore.setColor(color.hex);
        localStorage.setItem(LOCAL_STORE.MD_COLOR, color.hex);
        document.body.style.setProperty('--bg', color.hex);
        // setDisplayPicker(false);
      }}></ChromePicker>}
    </div>
  ));
}
Example #4
Source File: popupContainer.tsx    From gchat-themes with MIT License 6 votes vote down vote up
render() {
        return (
            <Fragment>
                <div className={styles.colorPicker} ref={this.colorPickerRef}>
                    <ChromePicker color={this.props.color} onChange={this.props.onChange}/>
                </div>
                <div className={styles.cover} onClick={this.handleCoverClick}/>
            </Fragment>
        );
    }
Example #5
Source File: PopoverCell.tsx    From firetable with Apache License 2.0 5 votes vote down vote up
export default function Color({ value, onSubmit }: IPopoverCellProps) {
  const handleChangeComplete = (color) => onSubmit(color);

  return (
    <ChromePicker color={value?.rgb} onChangeComplete={handleChangeComplete} />
  );
}
Example #6
Source File: SideDrawerField.tsx    From firetable with Apache License 2.0 5 votes vote down vote up
export default function Color({
  column,
  control,
  disabled,
}: ISideDrawerFieldProps) {
  const classes = useStyles();
  const fieldClasses = useFieldStyles();

  const [showPicker, setShowPicker] = useState(false);
  const toggleOpen = () => setShowPicker((s) => !s);

  return (
    <Controller
      control={control}
      name={column.key}
      render={({ onChange, onBlur, value }) => (
        <>
          <Grid
            container
            alignItems="center"
            spacing={1}
            className={classes.root}
            onClick={() => {
              toggleOpen();
              onBlur();
            }}
            component={ButtonBase}
            focusRipple
            disabled={disabled}
          >
            <Grid item>
              <div
                className={classes.colorIndicator}
                style={{ backgroundColor: value?.hex }}
              />
            </Grid>

            <Grid item xs>
              <Typography
                variant="body1"
                color={value?.hex ? "textPrimary" : "textSecondary"}
              >
                {value?.hex ?? "Choose a color…"}
              </Typography>
            </Grid>
          </Grid>

          <Collapse in={showPicker}>
            <ChromePicker color={value?.rgb} onChangeComplete={onChange} />
          </Collapse>
        </>
      )}
    />
  );
}
Example #7
Source File: Background.tsx    From dnde with GNU General Public License v3.0 5 votes vote down vote up
Background = ({ activePath, label, overrideAttribute }: BackgroundProps) => {
  const attribute = overrideAttribute || ATTRIBUTE;
  const { mjmlJson, setMjmlJson } = useEditor();
  const [active, setActive] = useState(() => false);
  const [color, setColor] = useState(() => '#ccc');
  const [visible, path] = useVisibility({ attribute, customPath: activePath });

  useEffect(() => {
    if (visible && path) {
      const item = _.get(mjmlJson, path);
      if (item && item.attributes && item.attributes[attribute]) {
        setColor(item.attributes[attribute]);
      }
    }
    logger.log('background reloading,', path, visible);
  }, [path, visible]);

  const handleColorChange = (color: any) => {
    const hexCode = `${color.hex}${decimalToHex(color.rgb.a)}`;
    setColor(hexCode);
    if (path && visible) {
      let element = _.get(mjmlJson, path);
      element.attributes[attribute] = hexCode;
      let json = _.set(mjmlJson, path, element);

      setMjmlJson({ ...json });
    }
  };

  return visible ? (
    <>
      <Row>
        <Col flex="auto">
          <Form.Item label={label ? label : 'Background'}></Form.Item>
        </Col>

        <ColorPicker color={color} flex="none">
          <div className="swatch" onClick={() => setActive(true)}>
            <div className="color"></div>
          </div>
          {active ? (
            <div className="popover">
              <div className="cover" onClick={() => setActive(false)}></div>
              <ChromePicker disableAlpha={false} color={color} onChange={(color: any) => handleColorChange(color)} />
            </div>
          ) : null}
        </ColorPicker>
      </Row>
    </>
  ) : null;
}
Example #8
Source File: ContainerBackground.tsx    From dnde with GNU General Public License v3.0 5 votes vote down vote up
ContainerBackground = () => {
  const { mjmlJson, setMjmlJson } = useEditor();
  const [active, setActive] = useState(() => false);
  const [color, setColor] = useState(() => '#ccc');
  const { active: clicked } = useHtmlWrapper();
  const [visible, path] = useVisibility({ attribute: ATTRIBUTE });

  useEffect(() => {
    if (clicked && visible) {
      try {
        if (path) {
          let item = _.get(mjmlJson, path);
          if (item.mutableProperties.includes(ATTRIBUTE)) {
            setColor(item.attributes[ATTRIBUTE]);
          }
        }
      } catch (e) {
        logger.info('got exception, hiding background mod', e);
      }
    }
  }, [clicked]);

  const handleColorChange = (color: any) => {
    const hexCode = `${color.hex}${decimalToHex(color.rgb.a)}`;
    setColor(hexCode);
    if (path && visible) {
      let element = _.get(mjmlJson, path);
      element.attributes['container-background-color'] = hexCode;
      let json = _.set(mjmlJson, path, element);

      setMjmlJson({ ...json });
    }
  };

  return visible ? (
    <>
      <Row>
        <Col flex="auto">
          <Form.Item label="Container Background"></Form.Item>
        </Col>

        <ColorPicker color={color} flex="none">
          <div className="swatch" onClick={() => setActive(true)}>
            <div className="color"></div>
          </div>
          {active ? (
            <div className="popover">
              <div className="cover" onClick={() => setActive(false)}></div>
              <ChromePicker disableAlpha={false} color={color} onChange={(color: any) => handleColorChange(color)} />
            </div>
          ) : null}
        </ColorPicker>
      </Row>
    </>
  ) : null;
}
Example #9
Source File: custom-generate-palette.tsx    From S2 with MIT License 5 votes vote down vote up
fetch(
  'https://gw.alipayobjects.com/os/bmw-prod/2a5dbbc8-d0a7-4d02-b7c9-34f6ca63cff6.json',
)
  .then((res) => res.json())
  .then((dataCfg) => {
    const s2Options = {
      width: 600,
      height: 480,
    };

    function App() {
      const [themeColor, setThemeColor] = useState('#EA1720');
      const [themeCfg, setThemeCfg] = useState<ThemeCfg>({
        name: 'colorful',
      });

      const updatePalette = (newThemeColor) => {
        // 使用内置的 colorful 色板作为参考色板
        const palette = getPalette(themeCfg.name);
        // 使用参考色板 & 主题色值生成新色板
        const newPalette = generatePalette({
          ...palette,
          brandColor: newThemeColor,
        });

        // 使用新色板设置主题
        setThemeCfg({
          name: themeCfg.name,
          palette: newPalette,
        });
      };

      useEffect(() => {
        updatePalette(themeColor);
      }, []);

      return (
        <Space direction="vertical">
          <Space>
            <span>当前主题色: {themeColor}</span>
            <Popover
              placement="bottomRight"
              content={
                <ChromePicker
                  disableAlpha
                  color={themeColor}
                  onChangeComplete={(color) => {
                    setThemeColor(color.hex);
                    updatePalette(color.hex);
                  }}
                />
              }
            >
              <Button size="small" style={{ marginLeft: 20 }}>
                主题色调整
              </Button>
            </Popover>
          </Space>
          <SheetComponent
            dataCfg={dataCfg}
            options={s2Options}
            themeCfg={themeCfg}
          />
        </Space>
      );
    }

    ReactDOM.render(<App />, document.getElementById('container'));
  });
Example #10
Source File: ColorPreview.tsx    From convoychat with GNU General Public License v3.0 5 votes vote down vote up
ColorPreview: React.FC<IColorPreview> = ({
  color,
  preview,
  handleColorChange,
}) => {
  return (
    <StyledColorPreview className="color-preview__grid">
      <Flex
        gap="xlarge"
        align="center"
        justify="space-between"
        nowrap
        style={{ flex: 1 }}
      >
        <Dropdown>
          <Dropdown.Toggle>
            <div
              className="color-picker__block"
              style={{ backgroundColor: color }}
            >
              <FaPalette />
            </div>
          </Dropdown.Toggle>
          <Dropdown.Content>
            <ChromePicker color={color} onChange={handleColorChange} />
          </Dropdown.Content>
        </Dropdown>
        <CirclePicker
          width={"150px"}
          circleSize={20}
          circleSpacing={10}
          color={color}
          colors={colors}
          onChange={handleColorChange}
        />
      </Flex>
      <div>{preview}</div>
    </StyledColorPreview>
  );
}
Example #11
Source File: StringComponent.tsx    From brick-design with MIT License 5 votes vote down vote up
function StringComponent(props: StringComponentPropsType, ref: any) {
  const {
    value,
    isShowInput = true,
    isShowColor = false,
    colorType = 'hex',
    onChange,
    children,
    isFont,
    style,
    rowProps = { gutter: 5 },
    inputColProps = { span: 18 },
    colorColProps = { span: 6 },
    inputProps = {},
  } = props;
  const [color, setColor] = useState(value);
  useEffect(() => {
    setColor(value);
  }, [value]);

  useEffect(() => {
    const timer = setTimeout(() => onChange && onChange(color), 100);
    return () => clearTimeout(timer);
  }, [color]);

  function handleChangeColor(value: any) {
    let color;
    if (value.target) {
      color = value.target.value;
    } else {
      const {
        rgb: { r, g, b, a },
        hex,
      } = value;
      color = colorType === 'hex' ? hex : `rgba(${r},${g},${b},${a})`;
    }
    setColor(color);
  }

  const childNode = children || (isFont && <Icon type={'font-colors'} />);
  const colorStyle = childNode
    ? { color, fontSize: 16 }
    : { backgroundColor: color };
  return (
    <Row {...rowProps}>
      {isShowInput && (
        <Col {...inputColProps}>
          <Input
            allowClear
            size={'small'}
            value={color}
            onChange={handleChangeColor}
            {...inputProps}
          />
        </Col>
      )}
      {isShowColor && (
        <Col {...colorColProps}>
          <Dropdown
            trigger={['click']}
            overlay={
              <ChromePicker color={color} onChange={handleChangeColor} />
            }
          >
            <Button
              size={'small'}
              style={{ width: '100%', ...style, ...colorStyle }}
            >
              {childNode}
            </Button>
          </Dropdown>
        </Col>
      )}
    </Row>
  );
}
Example #12
Source File: ChromeColorPicker.tsx    From datart with Apache License 2.0 5 votes vote down vote up
/**
 * 单色选择组件
 * @param onChange
 * @param color
 * @returns 返回一个新的颜色值
 */
function ChromeColorPicker({ color, onChange }: colorSelectionPropTypes) {
  const [selectColor, setSelectColor] = useState<any>(color);
  const t = useI18NPrefix('components.colorPicker');

  return (
    <ChromeColorWrap>
      <ChromePicker
        color={selectColor}
        onChangeComplete={color => {
          let colorRgb = toChangeValue(color);
          setSelectColor(colorRgb);
        }}
      />
      <BtnWrap>
        <Button
          size="middle"
          onClick={() => {
            onChange?.(false);
          }}
        >
          {t('cancel')}
        </Button>
        <Button
          type="primary"
          size="middle"
          onClick={() => {
            onChange?.(selectColor);
          }}
        >
          {t('ok')}
        </Button>
      </BtnWrap>
    </ChromeColorWrap>
  );
}
Example #13
Source File: ColorPicker.tsx    From slippi-stats with MIT License 5 votes vote down vote up
ColorPicker: React.FC<{
  value: string;
  defaultColor?: string;
  onChange: (val: string) => void;
}> = ({ value, onChange, defaultColor }) => {
  const [show, setShow] = React.useState(false);
  const wrapperRef = useRef(null);
  const showReset = defaultColor && value !== defaultColor;

  useOnClickOutside(wrapperRef, () => {
    if (show) {
      setShow(false);
    }
  });

  const onClick = () => {
    if (!show) {
      setShow(true);
    }
  };

  const resetClick = () => {
    if (defaultColor) {
      onChange(defaultColor);
    }
  };

  return (
    <div style={{ position: "relative" }}>
      <ColorSquare color={value} size="5rem" ref={wrapperRef} onClick={onClick}>
        {show && (
          <div
            css={css`
              position: absolute;
              z-index: 9999;
              bottom: 0;
            `}
          >
            <ChromePicker color={value} onChange={(color) => onChange(color.hex)} />
          </div>
        )}
      </ColorSquare>
      {showReset && <ResetButton onClick={resetClick}>RESET</ResetButton>}
    </div>
  );
}
Example #14
Source File: index.tsx    From S2 with MIT License 4 votes vote down vote up
function MainLayout() {
  const [render, setRender] = React.useState(true);
  const [sheetType, setSheetType] = React.useState<SheetType>('pivot');
  const [showPagination, setShowPagination] = React.useState(false);
  const [showTotals, setShowTotals] = React.useState(false);
  const [themeCfg, setThemeCfg] = React.useState<ThemeCfg>({
    name: 'default',
  });
  const [themeColor, setThemeColor] = React.useState<string>('#FFF');
  const [showCustomTooltip, setShowCustomTooltip] = React.useState(false);
  const [adaptive, setAdaptive] = React.useState<Adaptive>(false);
  const [options, setOptions] =
    React.useState<Partial<S2Options<React.ReactNode>>>(defaultOptions);
  const [dataCfg, setDataCfg] =
    React.useState<Partial<S2DataConfig>>(pivotSheetDataCfg);
  const [strategyDataCfg, setStrategyDataCfg] =
    React.useState<S2DataConfig>(customTree);
  const [strategyOptions, setStrategyOptions] =
    React.useState<S2Options>(mockStrategyOptions);
  const s2Ref = React.useRef<SpreadSheet>();
  const [columnOptions, setColumnOptions] = React.useState([]);
  const scrollTimer = React.useRef<NodeJS.Timer>();

  //  ================== Callback ========================
  const updateOptions = (newOptions: Partial<S2Options<React.ReactNode>>) => {
    setOptions(customMerge({}, options, newOptions));
  };

  const updateDataCfg = (newDataCfg: Partial<S2DataConfig>) => {
    const currentDataCfg =
      sheetType === 'pivot' ? pivotSheetDataCfg : tableSheetDataCfg;

    setDataCfg(customMerge({}, currentDataCfg, newDataCfg));
  };

  const onAutoAdjustBoundary = (value: TooltipAutoAdjustBoundary) => {
    updateOptions({
      tooltip: {
        autoAdjustBoundary: value || null,
      },
    });
  };

  const onLayoutWidthTypeChange = (e: RadioChangeEvent) => {
    updateOptions({
      style: {
        layoutWidthType: e.target.value,
      },
    });
  };

  const onSizeChange = (type: 'width' | 'height') =>
    debounce((e) => {
      updateOptions({
        [type]: Number(e.target.value),
      });
    }, 300);

  const onScrollSpeedRatioChange =
    (type: 'horizontal' | 'vertical') => (value: number) => {
      updateOptions({
        interaction: {
          scrollSpeedRatio: {
            [type]: value,
          },
        },
      });
    };

  const onToggleRender = () => {
    setRender(!render);
  };

  const onThemeChange = (e: RadioChangeEvent) => {
    setThemeCfg({
      name: e.target.value,
    });
  };

  const onSheetTypeChange = (e: RadioChangeEvent) => {
    setSheetType(e.target.value);
  };

  const logHandler =
    (name: string) =>
    (...args: unknown[]) => {
      console.log(name, ...args);
    };

  const onColCellClick = (cellInfo: TargetCellInfo) => {
    logHandler('onColCellClick')(cellInfo);
    if (!options.showDefaultHeaderActionIcon) {
      const { event } = cellInfo;
      s2Ref.current.showTooltip({
        position: { x: event.clientX, y: event.clientY },
        content: <CustomColTooltip />,
      });
    }
  };

  const getColumnOptions = (sheetType: SheetType) => {
    if (sheetType === 'table') {
      return dataCfg.fields.columns;
    }
    return s2Ref.current?.getInitColumnLeafNodes().map(({ id }) => id) || [];
  };

  //  ================== Hooks ========================

  React.useEffect(() => {
    s2Ref.current?.on(S2Event.DATA_CELL_TREND_ICON_CLICK, (meta) => {
      console.log('趋势图icon点击', meta);
    });
  }, [sheetType]);

  useUpdateEffect(() => {
    switch (sheetType) {
      case 'table':
        setDataCfg(tableSheetDataCfg);
        updateOptions(defaultOptions);
        break;
      default:
        setDataCfg(pivotSheetDataCfg);
        updateOptions(defaultOptions);
        break;
    }
    setColumnOptions(getColumnOptions(sheetType));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sheetType]);

  //  ================== Config ========================

  const mergedOptions: Partial<S2Options<React.ReactNode>> = customMerge(
    {},
    {
      pagination: showPagination && {
        pageSize: 10,
        current: 1,
      },
      tooltip: {
        content: showCustomTooltip ? <CustomTooltip /> : null,
      },
      totals: showTotals && {
        row: {
          showGrandTotals: true,
          showSubTotals: true,
          subTotalsDimensions: ['province'],
        },
        col: {
          showGrandTotals: true,
          showSubTotals: true,
          subTotalsDimensions: ['type'],
        },
      },
      customSVGIcons: !options.showDefaultHeaderActionIcon && [
        {
          name: 'Filter',
          svg: 'https://gw.alipayobjects.com/zos/antfincdn/gu1Fsz3fw0/filter%26sort_filter.svg',
        },
        {
          name: 'FilterAsc',
          svg: 'https://gw.alipayobjects.com/zos/antfincdn/UxDm6TCYP3/filter%26sort_asc%2Bfilter.svg',
        },
      ],
      headerActionIcons: !options.showDefaultHeaderActionIcon && [
        {
          iconNames: ['Filter'],
          belongsCell: 'colCell',
          displayCondition: (node: Node) =>
            node.id !== 'root[&]家具[&]桌子[&]number',
          action: ({ event }: HeaderActionIconProps) => {
            s2Ref.current?.showTooltip({
              position: { x: event.clientX, y: event.clientY },
              content: <ActionIconTooltip name="Filter colCell" />,
            });
          },
        },
        {
          iconNames: ['SortDown'],
          belongsCell: 'colCell',
          displayCondition: (node: Node) =>
            node.id === 'root[&]家具[&]桌子[&]number',
          action: ({ event }: HeaderActionIconProps) => {
            s2Ref.current?.showTooltip({
              position: { x: event.clientX, y: event.clientY },
              content: <ActionIconTooltip name="SortDown colCell" />,
            });
          },
        },
        {
          iconNames: ['FilterAsc'],
          belongsCell: 'cornerCell',
          action: ({ event }: HeaderActionIconProps) => {
            s2Ref.current?.showTooltip({
              position: { x: event.clientX, y: event.clientY },
              content: <ActionIconTooltip name="FilterAsc cornerCell" />,
            });
          },
        },
        {
          iconNames: ['SortDown', 'Filter'],
          belongsCell: 'rowCell',
          action: ({ event }: HeaderActionIconProps) => {
            s2Ref.current?.showTooltip({
              position: { x: event.clientX, y: event.clientY },
              content: <ActionIconTooltip name="SortDown & Filter rowCell" />,
            });
          },
        },
      ],
    },
    options,
  );

  return (
    <div className="playground">
      <Tabs defaultActiveKey="basic" type="card" destroyInactiveTabPane>
        <TabPane tab="基础表" key="basic">
          <Collapse defaultActiveKey={['filter', 'interaction']}>
            <Collapse.Panel header="筛选器" key="filter">
              <Space>
                <Tooltip title="表格类型">
                  <Radio.Group
                    onChange={onSheetTypeChange}
                    defaultValue={sheetType}
                  >
                    <Radio.Button value="pivot">透视表</Radio.Button>
                    <Radio.Button value="table">明细表</Radio.Button>
                  </Radio.Group>
                </Tooltip>
                <Tooltip title="布局类型">
                  <Radio.Group
                    onChange={onLayoutWidthTypeChange}
                    defaultValue="adaptive"
                  >
                    <Radio.Button value="adaptive">行列等宽</Radio.Button>
                    <Radio.Button value="colAdaptive">列等宽</Radio.Button>
                    <Radio.Button value="compact">紧凑</Radio.Button>
                  </Radio.Group>
                </Tooltip>
                <Tooltip title="主题">
                  <Radio.Group onChange={onThemeChange} defaultValue="default">
                    <Radio.Button value="default">默认</Radio.Button>
                    <Radio.Button value="gray">简约灰</Radio.Button>
                    <Radio.Button value="colorful">多彩蓝</Radio.Button>
                  </Radio.Group>
                </Tooltip>
              </Space>
              <Space>
                <Popover
                  placement="bottomRight"
                  content={
                    <>
                      <ChromePicker
                        color={themeColor}
                        onChangeComplete={(color) => {
                          setThemeColor(color.hex);
                          const palette = getPalette(themeCfg.name);
                          const newPalette = generatePalette({
                            ...palette,
                            brandColor: color.hex,
                          });
                          setThemeCfg({
                            name: themeCfg.name,
                            palette: newPalette,
                          });
                        }}
                      />
                    </>
                  }
                >
                  <Button size="small" style={{ marginLeft: 20 }}>
                    主题色调整
                  </Button>
                </Popover>
                <Button
                  danger
                  size="small"
                  onClick={() => {
                    s2Ref.current?.destroy();
                    s2Ref.current?.render();
                  }}
                >
                  卸载组件 (s2.destroy)
                </Button>
              </Space>
              <Space style={{ margin: '20px 0', display: 'flex' }}>
                <Tooltip title="tooltip 自动调整: 显示的tooltip超过指定区域时自动调整, 使其不遮挡">
                  <Select
                    defaultValue={mergedOptions.tooltip.autoAdjustBoundary}
                    onChange={onAutoAdjustBoundary}
                    style={{ width: 230 }}
                    size="small"
                  >
                    <Select.Option value="container">
                      container (表格区域)
                    </Select.Option>
                    <Select.Option value="body">
                      body (浏览器可视区域)
                    </Select.Option>
                    <Select.Option value="">关闭</Select.Option>
                  </Select>
                </Tooltip>
                <Input
                  style={{ width: 150 }}
                  onChange={onSizeChange('width')}
                  defaultValue={mergedOptions.width}
                  suffix="px"
                  prefix="宽度"
                  size="small"
                />
                <Input
                  style={{ width: 150 }}
                  onChange={onSizeChange('height')}
                  defaultValue={mergedOptions.height}
                  suffix="px"
                  prefix="高度"
                  size="small"
                />
                <Button
                  size="small"
                  onClick={() => {
                    s2Ref.current?.changeSheetSize(400, 400);
                    s2Ref.current?.render(false);
                  }}
                >
                  改变表格大小 (s2.changeSheetSize)
                </Button>
                <Popover
                  placement="bottomRight"
                  content={
                    <>
                      <div style={{ width: '600px' }}>
                        水平滚动速率 :
                        <Slider
                          {...sliderOptions}
                          defaultValue={
                            mergedOptions.interaction.scrollSpeedRatio
                              .horizontal
                          }
                          onChange={onScrollSpeedRatioChange('horizontal')}
                        />
                        垂直滚动速率 :
                        <Slider
                          {...sliderOptions}
                          defaultValue={
                            mergedOptions.interaction.scrollSpeedRatio.vertical
                          }
                          onChange={onScrollSpeedRatioChange('vertical')}
                        />
                      </div>
                    </>
                  }
                >
                  <Button size="small">滚动速率调整</Button>
                </Popover>
                <Button
                  size="small"
                  onClick={() => {
                    const rowNode = s2Ref.current
                      ?.getRowNodes()
                      .find(({ id }) => id === 'root[&]四川省[&]成都市');

                    clearInterval(scrollTimer.current);
                    s2Ref.current.updateScrollOffset({
                      offsetY: {
                        value: rowNode?.y,
                        animate: true,
                      },
                    });
                  }}
                >
                  滚动至 [成都市]
                </Button>
                <Button
                  size="small"
                  onClick={() => {
                    clearInterval(scrollTimer.current);
                    s2Ref.current.updateScrollOffset({
                      offsetY: {
                        value: 0,
                        animate: true,
                      },
                    });
                  }}
                >
                  滚动到顶部
                </Button>
                <Button
                  size="small"
                  danger
                  onClick={() => {
                    if (
                      scrollTimer.current ||
                      !s2Ref.current.facet.vScrollBar
                    ) {
                      clearInterval(scrollTimer.current);
                      return;
                    }
                    scrollTimer.current = setInterval(() => {
                      const { scrollY } = s2Ref.current.facet.getScrollOffset();
                      if (s2Ref.current.facet.isScrollToBottom(scrollY)) {
                        console.log('滚动到底部');
                        s2Ref.current.updateScrollOffset({
                          offsetY: {
                            value: 0,
                            animate: false,
                          },
                        });
                        return;
                      }
                      s2Ref.current.updateScrollOffset({
                        offsetY: {
                          value: scrollY + 50,
                          animate: true,
                        },
                      });
                    }, 500);
                  }}
                >
                  {scrollTimer.current ? '停止滚动' : '循环滚动'}
                </Button>
              </Space>
              <Space
                style={{ marginTop: 20, display: 'flex', flexWrap: 'wrap' }}
              >
                <Switch
                  checkedChildren="渲染组件"
                  unCheckedChildren="卸载组件"
                  defaultChecked={render}
                  onChange={onToggleRender}
                />
                <Switch
                  checkedChildren="调试模式开"
                  unCheckedChildren="调试模式关"
                  defaultChecked={mergedOptions.debug}
                  onChange={(checked) => {
                    updateOptions({ debug: checked });
                  }}
                />
                <Switch
                  checkedChildren="树形"
                  unCheckedChildren="平铺"
                  checked={mergedOptions.hierarchyType === 'tree'}
                  onChange={(checked) => {
                    updateOptions({
                      hierarchyType: checked ? 'tree' : 'grid',
                    });
                  }}
                  disabled={sheetType === 'table'}
                />
                <Tooltip title="树状模式生效">
                  <Switch
                    checkedChildren="收起子节点"
                    unCheckedChildren="展开子节点"
                    disabled={mergedOptions.hierarchyType !== 'tree'}
                    checked={mergedOptions.hierarchyCollapse}
                    onChange={(checked) => {
                      updateOptions({
                        hierarchyCollapse: checked,
                      });
                    }}
                  />
                </Tooltip>
                <Switch
                  checkedChildren="数值挂列头"
                  unCheckedChildren="数值挂行头"
                  defaultChecked={dataCfg.fields?.valueInCols}
                  onChange={(checked) => {
                    updateDataCfg({
                      fields: {
                        valueInCols: checked,
                      },
                    });
                  }}
                  disabled={sheetType === 'table'}
                />
                <Switch
                  checkedChildren="隐藏数值"
                  unCheckedChildren="显示数值"
                  defaultChecked={mergedOptions.style.colCfg.hideMeasureColumn}
                  onChange={(checked) => {
                    updateOptions({
                      style: {
                        colCfg: {
                          hideMeasureColumn: checked,
                        },
                      },
                    });
                  }}
                  disabled={sheetType === 'table'}
                />
                <Switch
                  checkedChildren="显示行小计/总计"
                  unCheckedChildren="隐藏行小计/总计"
                  defaultChecked={
                    mergedOptions.totals?.row?.showSubTotals as boolean
                  }
                  onChange={(checked) => {
                    updateOptions({
                      totals: {
                        row: {
                          showGrandTotals: checked,
                          showSubTotals: checked,
                          reverseLayout: true,
                          reverseSubLayout: true,
                          subTotalsDimensions: ['province'],
                        },
                      },
                    });
                  }}
                  disabled={sheetType === 'table'}
                />
                <Switch
                  checkedChildren="显示列小计/总计"
                  unCheckedChildren="隐藏列小计/总计"
                  defaultChecked={
                    mergedOptions.totals?.col?.showSubTotals as boolean
                  }
                  onChange={(checked) => {
                    updateOptions({
                      totals: {
                        col: {
                          showGrandTotals: checked,
                          showSubTotals: checked,
                          reverseLayout: true,
                          reverseSubLayout: true,
                          subTotalsDimensions: ['type'],
                        },
                      },
                    });
                  }}
                  disabled={sheetType === 'table'}
                />
                <Switch
                  checkedChildren="冻结行头开"
                  unCheckedChildren="冻结行头关"
                  defaultChecked={mergedOptions.frozenRowHeader}
                  onChange={(checked) => {
                    updateOptions({
                      frozenRowHeader: checked,
                    });
                  }}
                  disabled={sheetType === 'table'}
                />
                <Switch
                  checkedChildren="容器宽高自适应开"
                  unCheckedChildren="容器宽高自适应关"
                  defaultChecked={Boolean(adaptive)}
                  onChange={setAdaptive}
                />
                <Switch
                  checkedChildren="显示序号"
                  unCheckedChildren="不显示序号"
                  checked={mergedOptions.showSeriesNumber}
                  onChange={(checked) => {
                    updateOptions({
                      showSeriesNumber: checked,
                    });
                  }}
                />
                <Switch
                  checkedChildren="分页"
                  unCheckedChildren="不分页"
                  checked={showPagination}
                  onChange={setShowPagination}
                />
                <Switch
                  checkedChildren="汇总"
                  unCheckedChildren="无汇总"
                  checked={showTotals}
                  onChange={setShowTotals}
                />
                <Switch
                  checkedChildren="默认actionIcons"
                  unCheckedChildren="自定义actionIcons"
                  checked={mergedOptions.showDefaultHeaderActionIcon}
                  onChange={(checked) => {
                    updateOptions({
                      showDefaultHeaderActionIcon: checked,
                    });
                  }}
                />
                <Switch
                  checkedChildren="开启Tooltip"
                  unCheckedChildren="关闭Tooltip"
                  checked={mergedOptions.tooltip.showTooltip}
                  onChange={(checked) => {
                    updateOptions({
                      tooltip: {
                        showTooltip: checked,
                      },
                    });
                  }}
                />
                <Switch
                  checkedChildren="自定义Tooltip"
                  unCheckedChildren="默认Tooltip"
                  checked={showCustomTooltip}
                  onChange={setShowCustomTooltip}
                />
              </Space>
            </Collapse.Panel>
            <Collapse.Panel header="交互配置" key="interaction">
              <Space>
                <Tooltip title="高亮选中单元格">
                  <Switch
                    checkedChildren="选中聚光灯开"
                    unCheckedChildren="选中聚光灯关"
                    checked={mergedOptions.interaction.selectedCellsSpotlight}
                    onChange={(checked) => {
                      updateOptions({
                        interaction: {
                          selectedCellsSpotlight: checked,
                        },
                      });
                    }}
                  />
                </Tooltip>
                <Tooltip title="高亮当前行列单元格">
                  <Switch
                    checkedChildren="hover十字器开"
                    unCheckedChildren="hover十字器关"
                    checked={mergedOptions.interaction.hoverHighlight}
                    onChange={(checked) => {
                      updateOptions({
                        interaction: {
                          hoverHighlight: checked,
                        },
                      });
                    }}
                  />
                </Tooltip>
                <Tooltip title="在数值单元格悬停800ms,显示tooltip">
                  <Switch
                    checkedChildren="hover聚焦开"
                    unCheckedChildren="hover聚焦关"
                    checked={mergedOptions.interaction.hoverFocus as boolean}
                    onChange={(checked) => {
                      updateOptions({
                        interaction: {
                          hoverFocus: checked,
                        },
                      });
                    }}
                  />
                </Tooltip>
                <Tooltip title="开启后,点击空白处,按下ESC键, 取消高亮, 清空选中单元格, 等交互样式">
                  <Switch
                    checkedChildren="自动重置交互样式开"
                    unCheckedChildren="自动重置交互样式关"
                    defaultChecked={
                      mergedOptions?.interaction?.autoResetSheetStyle
                    }
                    onChange={(checked) => {
                      updateOptions({
                        interaction: {
                          autoResetSheetStyle: checked,
                        },
                      });
                    }}
                  />
                </Tooltip>
                <Tooltip
                  title={
                    <>
                      <p>默认隐藏列 </p>
                      <p>明细表: 列头指定 field: number</p>
                      <p>透视表: 列头指定id: root[&]家具[&]沙发[&]number</p>
                    </>
                  }
                >
                  <Select
                    style={{ width: 300 }}
                    defaultValue={mergedOptions.interaction.hiddenColumnFields}
                    mode="multiple"
                    placeholder="默认隐藏列"
                    onChange={(fields) => {
                      updateOptions({
                        interaction: {
                          hiddenColumnFields: fields,
                        },
                      });
                    }}
                  >
                    {columnOptions.map((column) => {
                      return (
                        <Select.Option value={column} key={column}>
                          {column}
                        </Select.Option>
                      );
                    })}
                  </Select>
                </Tooltip>
              </Space>
            </Collapse.Panel>
            <Collapse.Panel header="宽高调整热区配置" key="resize">
              <ResizeConfig setOptions={setOptions} setThemeCfg={setThemeCfg} />
            </Collapse.Panel>
          </Collapse>
          {render && (
            <SheetComponent
              dataCfg={dataCfg as S2DataConfig}
              options={mergedOptions as S2Options}
              sheetType={sheetType}
              adaptive={adaptive}
              ref={s2Ref}
              themeCfg={themeCfg}
              partDrillDown={partDrillDown}
              header={{
                title: (
                  <a href="https://github.com/antvis/S2">
                    {reactPkg.name} playground
                  </a>
                ),
                description: (
                  <Space>
                    <span>
                      {reactPkg.name}: <Tag>{reactPkg.version}</Tag>
                    </span>
                    <span>
                      {corePkg.name}: <Tag>{corePkg.version}</Tag>
                    </span>
                    <span>
                      lang: <Tag>{getLang()}</Tag>
                    </span>
                  </Space>
                ),
                switcherCfg: { open: true },
                exportCfg: { open: true },
                advancedSortCfg: { open: true },
              }}
              onDataCellTrendIconClick={logHandler('onDataCellTrendIconClick')}
              onAfterRender={logHandler('onAfterRender')}
              onDestroy={logHandler('onDestroy')}
              onColCellClick={onColCellClick}
              onRowCellClick={logHandler('onRowCellClick')}
              onCornerCellClick={(cellInfo) => {
                s2Ref.current.showTooltip({
                  position: {
                    x: cellInfo.event.clientX,
                    y: cellInfo.event.clientY,
                  },
                  content: 'click',
                });
              }}
              onCornerCellHover={(cellInfo) => {
                s2Ref.current.showTooltip({
                  position: {
                    x: cellInfo.event.clientX,
                    y: cellInfo.event.clientY,
                  },
                  content: 'hover',
                });
              }}
              onDataCellClick={logHandler('onDataCellClick')}
              onLayoutResizeMouseDown={logHandler('onLayoutResizeMouseDown')}
              onLayoutResizeMouseUp={logHandler('onLayoutResizeMouseUp')}
              onCopied={logHandler('onCopied')}
              onLayoutColsHidden={logHandler('onLayoutColsHidden')}
              onLayoutColsExpanded={logHandler('onLayoutColsExpanded')}
              onSelected={logHandler('onSelected')}
            />
          )}
        </TabPane>
        <TabPane tab="自定义目录树" key="customTree">
          <SheetComponent
            dataCfg={{ data: dataCustomTrees, fields: customTreeFields }}
            options={{ width: 600, height: 480, hierarchyType: 'customTree' }}
          />
        </TabPane>
        <TabPane tab="趋势分析表" key="strategy">
          <Switch
            checkedChildren="单列头"
            unCheckedChildren="多列头"
            checked={strategyDataCfg.fields.columns.length === 1}
            onChange={(checked) => {
              setStrategyDataCfg(
                customMerge(customTree, {
                  fields: {
                    columns: customTree.fields.columns.slice(
                      0,
                      checked ? 1 : 2,
                    ),
                  },
                }),
              );
            }}
          />
          <SheetComponent
            sheetType="strategy"
            dataCfg={strategyDataCfg}
            options={strategyOptions}
            onRowCellClick={logHandler('onRowCellClick')}
            header={{ exportCfg: { open: true } }}
            themeCfg={{
              theme: strategyTheme,
              name: 'gray',
            }}
          />
        </TabPane>
        <TabPane tab="网格分析表" key="gridAnalysis">
          <SheetComponent
            sheetType="gridAnalysis"
            dataCfg={mockGridAnalysisDataCfg}
            options={mockGridAnalysisOptions}
          />
        </TabPane>
      </Tabs>
    </div>
  );
}