lodash#assign TypeScript Examples

The following examples show how to use lodash#assign. 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: tooltip.ts    From S2 with MIT License 6 votes vote down vote up
mergeCellInfo = (cells: S2CellType[]): TooltipData[] => {
  return map(cells, (stateCell) => {
    const stateCellMeta = stateCell.getMeta();
    return assign(
      {},
      stateCellMeta.query || {},
      pick(stateCellMeta, ['colIndex', 'rowIndex']),
    );
  });
}
Example #2
Source File: schema.ts    From am-editor with MIT License 6 votes vote down vote up
/**
	 * 过滤满足node节点规则的属性和样式
	 * @param node 节点,用于获取规则
	 * @param attributes 属性
	 * @param styles 样式
	 * @param apply 是否把过滤的属性和样式应用到节点上
	 * @returns
	 */
	filter(
		node: NodeInterface,
		attributes: { [k: string]: string },
		styles: { [k: string]: string },
		apply: boolean = false,
	) {
		const rule = this.getRule(node);
		if (!rule) return;
		const { globals } = this.data;
		const globalRule = globals[rule.type] ? rule.type : undefined;
		const allRule = Object.assign({}, rule, {
			attributes: merge(
				{},
				rule.attributes,
				globalRule ? globals[globalRule] : {},
			),
		});
		this.filterAttributes(
			attributes,
			allRule,
			apply ? (name) => node.removeAttributes(name) : undefined,
		);
		this.filterStyles(
			styles,
			allRule,
			apply ? (name) => node.css(name, '') : undefined,
		);
	}
Example #3
Source File: dict.monad.ts    From relate with GNU General Public License v3.0 6 votes vote down vote up
/**
     * Shallow merge of two Dicts (equivalent of Object.assign)
     * ```ts
     * const foo = Dict.from({foo: true, baz: {key1: 'foo'}});
     * const bar = Dict.from({bar: 1, baz: {key2: 'bar'}});
     * const fooBar = foo.assign(bar);
     * fooBar.toObject() // {foo: true, bar: 1, baz: {key2: 'bar'}}
     * ```
     */
    assign<O extends Dict>(other: O): Dict<T & O> {
        // @ts-ignore
        return Dict.from(assign({}, this.toObject(), Dict.isDict(other) ? other.toObject() : other));
    }
Example #4
Source File: Router.ts    From mo360-ftk with MIT License 6 votes vote down vote up
public navigate(path: string, query?: RouteQuery): void {
        path = path || '/';
        if (!path.startsWith('/')) {
            path = `/${path}`;
        }
        this.routes.forEach(item => {
            const parser: RouteParser = new RouteParser(item.pattern);
            const match: RouteParameter | boolean = parser.match(path);

            if (match) {
                this.route = assign({}, item, {
                    parameter: match,
                    query,
                    url: path + Url.buildQueryFromParameters(query as IUrlQueryMap),
                });
            }
        });
    }
Example #5
Source File: index.ts    From fe-v5 with Apache License 2.0 6 votes vote down vote up
update(newOptions: Options) {
    /**
     * 更新功能目前还没有想到最优的方案,暂时先根据目前的需求来强定制
     */
    const options = assign({}, this.options, newOptions);

    if (newOptions.series) {
      options.series = newOptions.series;
    }
    this.options = options;
    this.initSeries();
    this.options.chartType === ChartType.Line ? this.initLine() : this.initStackArea();
    this.initTooltip();
    this.initScales();
    // this.initScales(); // TODO: 更新偶尔会出现 colsePath 的情况,但是触发两次 initScales 就不会出现 closePath 情况
    this.legend.updateOptions(options);
    this.draw();
  }
Example #6
Source File: utils.ts    From prism-frontend with MIT License 6 votes vote down vote up
convertToTableData = (result: ExposedPopulationResult) => {
  const {
    key,
    groupBy,
    statistic,
    featureCollection: { features },
  } = result;

  const fields = uniq(features.map(f => f.properties && f.properties[key]));

  const featureProperties = features.map(feature => {
    return {
      [groupBy]: feature.properties?.[groupBy],
      [key]: feature.properties?.[key],
      [statistic]: feature.properties?.[statistic],
    };
  });

  const rowData = mapValues(_groupBy(featureProperties, groupBy), k => {
    return mapValues(_groupBy(k, key), v =>
      parseInt(
        v.map(x => x[statistic]).reduce((acc, value) => acc + value),
        10,
      ),
    );
  });

  const groupedRowData = Object.keys(rowData).map(k => {
    return {
      [groupBy]: k,
      ...rowData[k],
    };
  });

  const groupedRowDataWithAllLabels = groupedRowData.map(row => {
    const labelsWithoutValue = difference(fields, keysIn(row));
    const extras = labelsWithoutValue.map(k => ({ [k]: 0 }));
    return extras.length !== 0 ? assign(row, ...extras) : row;
  });

  const headlessRows = groupedRowDataWithAllLabels.map(row => {
    // TODO - Switch between MAX and SUM depending on the polygon source.
    // Then re-add "Total" to the list of columns
    // const total = fields.map(f => row[f]).reduce((a, b) => a + b);
    // return assign(row, { Total: total });
    return row;
  });

  const columns = [groupBy, ...fields]; // 'Total'
  const headRow = zipObject(columns, columns);
  const rows = [headRow, ...headlessRows];
  return { columns, rows };
}
Example #7
Source File: dbms.model.ts    From relate with GNU General Public License v3.0 5 votes vote down vote up
constructor(props: any) {
        super(props);

        // reassigning default values doesn't work when it's done from the parent class
        assign(this, props);
    }
Example #8
Source File: dict.monad.ts    From relate with GNU General Public License v3.0 5 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/ban-types
    assign<O extends object>(other: O): Dict<T & O>;
Example #9
Source File: project.model.ts    From relate with GNU General Public License v3.0 5 votes vote down vote up
constructor(props: any) {
        super(props);

        // reassigning default values doesn't work when it's done from the parent class
        assign(this, props);
    }
Example #10
Source File: project-install.model.ts    From relate with GNU General Public License v3.0 5 votes vote down vote up
constructor(props: any) {
        super(props);

        // reassigning default values doesn't work when it's done from the parent class
        assign(this, props);
    }
Example #11
Source File: model.abstract.ts    From relate with GNU General Public License v3.0 5 votes vote down vote up
constructor(props: T) {
        assign(this, props);
        this.validate();
    }
Example #12
Source File: manifest.model.ts    From relate with GNU General Public License v3.0 5 votes vote down vote up
constructor(props: any) {
        super(props);

        // reassigning default values doesn't work when it's done from the parent class
        assign(this, props);
    }
Example #13
Source File: dbms-plugin.model.ts    From relate with GNU General Public License v3.0 5 votes vote down vote up
constructor(props: any) {
        super(props);

        // reassigning default values doesn't work when it's done from the parent class
        assign(this, props);
    }
Example #14
Source File: index.ts    From fe-v5 with Apache License 2.0 5 votes vote down vote up
initStackArea() {
    this.chartContent = new StackArea(Object.assign(this.options, { series: this.baseSeries }), this.backContext);
  }
Example #15
Source File: index.ts    From fe-v5 with Apache License 2.0 5 votes vote down vote up
initLine() {
    // TODO: 涉及重复实例导
    this.chartContent = new Line(Object.assign(this.options, { series: this.baseSeries }), this.backContext);
  }
Example #16
Source File: GeneralSignup.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function GeneralSignup(props: GeneralSignupProps): React.ReactElement {
  const [form] = Form.useForm();
  const runtime = getRuntime();
  const brand = runtime.getBrandSettings();
  const enabledFeatures = runtime.getFeatureFlags();
  const { t } = useTranslation(NS_GENERAL_AUTH);
  const [, setForceUpdate] = useState<any>();

  const passwordConfigMap = {
    default: {
      regex: /^.{6,20}$/,
      description: "请输入6至20位密码",
    },
    strong: {
      regex: /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9]).{8,20}$/,
      description: "请输入8至20位密码,且同时包含大小写字母、数字、特殊字符",
    },
    backend: {},
  };
  let passwordLevel: keyof typeof passwordConfigMap = "default"; //特性开关
  useEffect(() => {
    if (enabledFeatures["enable-backend-password-config"]) {
      (async () => {
        passwordLevel = "backend";
        passwordConfigMap[passwordLevel] =
          await UserAdminApi_getPasswordConfig();
      })();
    }
  }, []);

  const MIN_USERNAME_LENGTH = 3; //特性开关
  const MAX_USERNAME_LENGTH = 32; //特性开关
  const usernamePattern = new RegExp(
    `^[A-Za-z0-9][A-Za-z0-9|_\\-\\.]{${MIN_USERNAME_LENGTH - 1},${
      MAX_USERNAME_LENGTH - 1
    }}$`
  );

  const iniviteCodePattern = /^[0-9a-zA-Z]{9}$/;
  const hideInvite = iniviteCodePattern.test(getInviteCode());
  const [isCommonSignup, setIsCommonSignup] = useState(true);

  const [isTermsVisible, setIsTermsVisible] = useState(false);

  function showTerms(): void {
    setIsTermsVisible(true);
  }
  function hideTerms(): void {
    setIsTermsVisible(false);
  }
  function agreeTerms(): void {
    form.setFieldsValue({
      terms: true,
    });
    hideTerms();
  }
  function disagreeTerms(): void {
    form.setFieldsValue({
      terms: false,
    });
    hideTerms();
  }

  const [imageHeight, setImageHeight] = useState(window.innerHeight);
  const onWindowResized = () => {
    if (imageHeight < window.innerHeight) {
      setImageHeight(window.innerHeight);
    }
  };
  useEffect(() => {
    const handleWindowResized = debounce(onWindowResized, 500, {
      leading: false,
    });
    window.addEventListener("resize", handleWindowResized);
    return () => {
      window.removeEventListener("resize", handleWindowResized);
    };
  }, []);

  const timer = useRef<any>();
  const count = useRef<number>(duration);
  const [verifyBtnDisabled, setVerifyBtnDisabled] = useState(true);
  const [content, setContent] = useState(t(K.GET_VERIFY_CODE));
  const [messageId, setMessageId] = useState("");
  const handleVerifyBtnClick = async (
    e: React.MouseEvent<HTMLElement, MouseEvent>
  ) => {
    if (timer.current) return;
    count.current -= 1;
    setContent(t(K.GET_VERIFY_CODE_TIPS, { count: count.current }));
    setVerifyBtnDisabled(true);
    timer.current = setInterval(() => {
      count.current -= 1;
      setContent(t(K.GET_VERIFY_CODE_TIPS, { count: count.current }));
      if (count.current === 0) {
        clearInterval(timer.current);
        timer.current = null;
        count.current = duration;
        setVerifyBtnDisabled(false);
        setContent(t(K.GET_VERIFY_CODE));
      }
    }, 1000);
    const result = await CustomerApi_sendApplicationVerificationCode({
      phone_number: form.getFieldValue("phone"),
    });
    result.message_id && setMessageId(result.message_id);
  };

  const redirect = async (result: Record<string, any>): Promise<void> => {
    runtime.reloadSharedData();
    await runtime.reloadMicroApps();
    resetLegacyIframe();
    authenticate({
      org: result.org,
      username: result.username,
      userInstanceId: result.userInstanceId,
      accessRule: result.accessRule,
    });
    const { state } = getHistory().location;
    const from =
      state && state.from
        ? state.from
        : {
            pathname: "/",
          };
    const redirect = createLocation(from);
    getHistory().push(redirect);
  };

  const onFinish = async (values: Record<string, any>): Promise<void> => {
    values.password = encryptValue(values.password);
    try {
      let result: Record<string, any>;
      if (isCommonSignup && !hideInvite) {
        result = await OrgApi_saaSOrgRegister(
          assign(omit(values, ["terms", "password2"]), {
            message_id: messageId,
          }) as OrgApi_SaaSOrgRegisterRequestBody
        );
      } else {
        result = await AuthApi_register(
          assign(
            omit(values, ["terms", "password2", "username"]),
            hideInvite
              ? { invite: getInviteCode(), name: values["username"] }
              : { name: values["username"] }
          ) as AuthApi_RegisterRequestBody
        );
      }
      if (result.loggedIn) {
        redirect(result);
      }
      message.success(t(K.REGISTER_SUCCESS));
    } catch (error) {
      Modal.error({
        title: t(K.REGISTER_FAILED),
        content:
          isCommonSignup && !hideInvite
            ? t(K.WRONG_VERIFICATION_CODE)
            : t(K.WRONG_INVITE_CODE),
      });
    }
  };

  return (
    <>
      <div className={styles.signupWrapper}>
        <div className={styles.signupHeader}>
          <div className={styles.logoBar}>
            <Link to="/">
              {brand.auth_logo_url ? (
                <img
                  src={brand.auth_logo_url}
                  style={{ height: 32, verticalAlign: "middle" }}
                />
              ) : (
                <Logo height={32} style={{ verticalAlign: "middle" }} />
              )}
            </Link>
          </div>
        </div>
        <div className={styles.signupImg}>
          <img src={loginPng} style={{ height: imageHeight }} />
        </div>
        <div className={styles.signupForm}>
          <Card bordered={false}>
            {!hideInvite &&
              (isCommonSignup ? (
                <a
                  onClick={() => {
                    setIsCommonSignup(false);
                  }}
                  style={{ alignSelf: "flex-end" }}
                  id="JumpToJoinFormLink"
                >
                  {t(K.JOIN_THE_ORGANIZATION)} <RightOutlined />
                </a>
              ) : (
                <a
                  onClick={() => {
                    setIsCommonSignup(true);
                  }}
                  id="JumpToCommonFormLink"
                >
                  <LeftOutlined /> {t(K.REGISTER_COMMONLY)}
                </a>
              ))}
            {!hideInvite && isCommonSignup ? (
              <div className={styles.title}>{t(K.REGISTER_ACCOUNT)}</div>
            ) : (
              <div className={styles.title}>{t(K.REGISTER_AND_JOIN)}</div>
            )}
            <Form name="signupForm" form={form} onFinish={onFinish}>
              <Form.Item
                validateFirst={true}
                name="username"
                rules={[
                  {
                    required: true,
                    message: t(K.USERNAME_TIPS, {
                      minLength: 3,
                      maxLength: 32,
                    }),
                  },
                  {
                    pattern: usernamePattern,
                    message: t(K.USERNAME_TIPS, {
                      minLength: 3,
                      maxLength: 32,
                    }),
                  },
                  {
                    validator: (
                      _: any,
                      value: any,
                      callback: (value?: string) => void
                    ) =>
                      validateMap["airNameValidator"](
                        value,
                        callback,
                        setForceUpdate
                      ),
                  },
                ]}
              >
                <Input
                  prefix={<UserOutlined className={styles.inputPrefixIcon} />}
                  placeholder={t(K.USERNAME)}
                />
              </Form.Item>
              {enabledFeatures["enable-nickname-config"] && hideInvite && (
                <Form.Item validateFirst={false} name="nickname">
                  <Input
                    prefix={
                      <SolutionOutlined className={styles.inputPrefixIcon} />
                    }
                    placeholder={t(K.NICKNAME)}
                  />
                </Form.Item>
              )}
              <Form.Item
                name="email"
                validateFirst={true}
                rules={[
                  { required: true, message: t(K.PLEASE_ENTER_VALID_EMAIL) },
                  { type: "email", message: t(K.PLEASE_ENTER_VALID_EMAIL) },
                  {
                    validator: (
                      _: any,
                      value: any,
                      callback: (value?: string) => void
                    ) =>
                      validateMap["airEmailValidator"](
                        value,
                        callback,
                        setForceUpdate
                      ),
                  },
                ]}
              >
                <Input
                  prefix={<MailOutlined className={styles.inputPrefixIcon} />}
                  type="email"
                  placeholder={t(K.EMAIL)}
                />
              </Form.Item>
              <Form.Item
                validateFirst={true}
                name="password"
                rules={[
                  { required: true, message: t(K.PLEASE_INPUT_PASSWORD) },
                  {
                    pattern: passwordConfigMap[passwordLevel].regex,
                    message: passwordConfigMap[passwordLevel].description,
                  },
                ]}
              >
                <Input
                  prefix={<LockOutlined className={styles.inputPrefixIcon} />}
                  type="password"
                  placeholder={t(K.PASSWORD)}
                />
              </Form.Item>
              <Form.Item
                dependencies={["password"]}
                name="password2"
                rules={[
                  { required: true, message: t(K.PLEASE_INPUT_PASSWORD) },
                  ({ getFieldValue }) => ({
                    validator(_, value) {
                      if (!value || getFieldValue("password") === value) {
                        return Promise.resolve();
                      }
                      return Promise.reject(
                        new Error(t(K.TWO_PASSWORDS_ARE_INCONSISTENT))
                      );
                    },
                  }),
                ]}
              >
                <Input
                  prefix={<LockOutlined className={styles.inputPrefixIcon} />}
                  type="password"
                  placeholder={t(K.PASSWORD_CONFIRM)}
                />
              </Form.Item>
              {!hideInvite &&
                (isCommonSignup ? (
                  <>
                    <Form.Item
                      validateFirst={true}
                      rules={[
                        {
                          required: true,
                          message: t(K.PLEASE_FILL_IN_VALID_PHONE_NUMBER),
                        },
                        {
                          validator: (_, value) => {
                            if (
                              /^(?=\d{11}$)^1(?:3\d|4[57]|5[^4\D]|7[^249\D]|8\d)\d{8}$/.test(
                                value
                              )
                            ) {
                              setVerifyBtnDisabled(false);
                              return Promise.resolve();
                            }
                            setVerifyBtnDisabled(true);
                            return Promise.reject(
                              new Error(t(K.PLEASE_FILL_IN_VALID_PHONE_NUMBER))
                            );
                          },
                        },
                      ]}
                      name="phone"
                    >
                      <Input
                        prefix={
                          <PhoneOutlined
                            className={styles.inputPrefixIcon}
                            rotate={90}
                          />
                        }
                        suffix={
                          <Button
                            disabled={verifyBtnDisabled}
                            type="text"
                            onClick={handleVerifyBtnClick}
                            id="verifyBtn"
                          >
                            {content}
                          </Button>
                        }
                        placeholder={t(K.PHONE)}
                      />
                    </Form.Item>
                    <Form.Item
                      rules={[
                        {
                          required: true,
                          message: t(K.PLEASE_INPUT_PHRASE),
                        },
                        {
                          pattern: /^\d{6}$/,
                          message: t(K.PLEASE_INPUT_VALID_PHRASE),
                        },
                      ]}
                      name="verification_code"
                    >
                      <Input
                        prefix={
                          <SafetyOutlined className={styles.inputPrefixIcon} />
                        }
                        placeholder={t(K.VERIFY_CODE)}
                      ></Input>
                    </Form.Item>
                  </>
                ) : (
                  <Form.Item
                    validateFirst={true}
                    name="invite"
                    rules={[
                      {
                        required: true,
                        message: t([K.PLEASE_FILL_IN_INVITE_CODE]),
                      },
                      {
                        pattern: iniviteCodePattern,
                        message: t([K.PLEASE_FILL_IN_INVITE_CODE]),
                      },
                    ]}
                  >
                    <Input
                      prefix={
                        <GeneralIcon
                          icon={{
                            lib: "easyops",
                            icon: "release-management",
                            category: "menu",
                            color: "rgba(0,0,0,.25)",
                          }}
                        />
                      }
                      type="text"
                      placeholder={t(K.INVITE_CODE)}
                    />
                  </Form.Item>
                ))}
              <Form.Item
                name="terms"
                valuePropName="checked"
                rules={[
                  {
                    validator: (_, value) =>
                      value
                        ? Promise.resolve()
                        : Promise.reject(new Error(t(K.AGREE_TERMS_TIPS))),
                  },
                ]}
              >
                <Checkbox>
                  {t(K.AGREE_TERMS)}
                  <a
                    onClick={() => {
                      showTerms();
                    }}
                    id="TermsLink"
                  >
                    {t(K.UWINTECH_TERMS)}
                  </a>
                </Checkbox>
              </Form.Item>
              <Form.Item>
                <Button
                  type="primary"
                  htmlType="submit"
                  style={{
                    width: "100%",
                    height: 34,
                  }}
                  id="submitBtn"
                >
                  {t(K.REGISTER)}
                </Button>
              </Form.Item>
              <Form.Item>
                <div style={{ textAlign: "center" }}>
                  {t(K.ALREADY_HAVE_AN_ACCOUNT)}
                  <a
                    id="LogInLink"
                    onClick={() => {
                      getHistory().push(
                        createLocation({
                          pathname: props.loginUrl ?? "/auth/login",
                        })
                      );
                    }}
                  >
                    {t(K.LOGIN_IMMEDIATELY)}
                  </a>
                </div>
              </Form.Item>
            </Form>
          </Card>
          <Modal
            visible={isTermsVisible}
            title={t(K.UWINTECH_TERMS)}
            width={598}
            okType="default"
            cancelText={t(K.DISAGREE)}
            okText={t(K.AGREE)}
            closable={false}
            onCancel={() => {
              disagreeTerms();
            }}
            onOk={() => {
              agreeTerms();
            }}
          >
            <Terms />
          </Modal>
        </div>
      </div>
    </>
  );
}
Example #17
Source File: schema.ts    From am-editor with MIT License 4 votes vote down vote up
/**
	 * 增加规则
	 * 只有 type 和 attributes 时,将作为此类型全局属性,与其它所有同类型标签属性将合并
	 * @param rules 规则
	 */
	add(rules: SchemaRule | SchemaGlobal | Array<SchemaRule | SchemaGlobal>) {
		rules = cloneDeep(rules);
		if (!Array.isArray(rules)) {
			rules = [rules];
		}

		rules.forEach((rule) => {
			if (isSchemaRule(rule)) {
				//删除全局属性已有的规则
				if (rule.attributes) {
					Object.keys(rule.attributes).forEach((key) => {
						if (!this.data.globals[rule.type]) return;
						if (key === 'style') {
							Object.keys(rule.attributes!.style).forEach(
								(styleName) => {
									if (
										this.data.globals[rule.type][key] &&
										this.data.globals[rule.type][key][
											styleName
										] === rule.attributes!.style[styleName]
									) {
										delete rule.attributes!.style[
											styleName
										];
									}
								},
							);
						} else if (
							this.data.globals[rule.type][key] ===
							rule.attributes![key]
						) {
							delete rule.attributes![key];
						}
					});
				}
				if (rule.type === 'block') {
					this.data.blocks.push(rule);
				} else if (rule.type === 'inline') {
					this.data.inlines.push(rule);
				} else if (rule.type === 'mark') {
					this.data.marks.push(rule);
				}
			} else if (!!this.data[`${rule.type}s`]) {
				this.data.globals[rule.type] = merge(
					Object.assign({}, this.data.globals[rule.type]),
					rule.attributes,
				);
			}
		});
		this.updateTagMap();
		//按照必要属性个数排序
		const getCount = (rule: SchemaRule) => {
			const aAttributes = rule.attributes || {};
			const aStyles = aAttributes.style || {};
			let aCount = 0;
			let sCount = 0;
			Object.keys(aAttributes).forEach((attributesName) => {
				const attributesValue = aAttributes[attributesName];
				if (
					isSchemaValueObject(attributesValue) &&
					attributesValue.required
				)
					aCount++;
			});
			Object.keys(aStyles).forEach((stylesName) => {
				const stylesValue = aStyles[stylesName];
				if (isSchemaValueObject(stylesValue) && stylesValue.required)
					sCount++;
			});
			return [aCount, sCount];
		};
		const { blocks, marks, inlines } = this.data;
		this._all = [...blocks, ...marks, ...inlines].sort((a, b) => {
			const [aACount, aSCount] = getCount(a);
			const [bACount, bSCount] = getCount(b);

			if (aACount > bACount) return -1;
			if (aACount === bACount)
				return aSCount === bSCount ? 0 : aSCount > bSCount ? -1 : 1;
			return 1;
		});
	}
Example #18
Source File: BrickEditor.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function BrickEditor({
  defaultConf,
  onConfChange,
  aceSetOptions,
  mode,
}: BrickEditorProps): React.ReactElement {
  const aceRef = React.useRef(null);
  const [valid, setValid] = React.useState(true);
  const changed = React.useRef(false);
  const [confString, setConfString] = React.useState("");
  const defaultAceSetOptions = {
    showLineNumbers: true,
    maxLines: Infinity,
    minLines: 5,
    tabSize: 2,
    printMargin: false,
    highlightActiveLine: false,
    highlightGutterLine: false,
  };

  const parse = (value: string, tryMode = mode): BrickConf => {
    let brickConf: BrickConf;
    if (value) {
      try {
        if (tryMode === "json") {
          brickConf = JSON.parse(value);
        } else {
          brickConf = yaml.safeLoad(value, {
            schema: yaml.JSON_SCHEMA,
            json: true,
          }) as BrickConf;
        }
        setValid(true);
      } catch (e) {
        setValid(false);
      }
    } else {
      setValid(true);
    }
    return brickConf;
  };

  const serialize = (brickConf: BrickConf): string => {
    let content = "";
    if (brickConf) {
      if (mode === "json") {
        content = JSON.stringify(brickConf, null, 2);
      } else {
        content = yaml.safeDump(brickConf, {
          schema: yaml.JSON_SCHEMA,
          skipInvalid: true,
          noRefs: true,
          noCompatMode: true,
        });
      }
    }
    return content;
  };

  const onButtonCopy = (text: string, success: boolean): void => {
    if (success) {
      message.success("复制成功");
    } else {
      message.error("复制失败");
    }
  };

  const setOptions = assign({}, defaultAceSetOptions, aceSetOptions);
  const handleStoryChange = (value: string): void => {
    changed.current = true;
    setConfString(value);

    parse(value);
  };

  const handleStoryBlur = (): void => {
    if (!changed.current) {
      return;
    }
    changed.current = false;
    const conf = parse(confString);
    if (conf) onConfChange(conf);
  };

  React.useEffect(() => {
    const content = serialize(defaultConf);
    setConfString(content);
  }, [mode]);

  return (
    <div
      className={cssStyle.editorCard}
      style={{ boxShadow: valid ? "none" : "red 0px 0px 3px 1px" }}
    >
      <AceEditor
        ref={aceRef}
        theme="monokai"
        mode={mode}
        showGutter={true}
        value={confString}
        width="100%"
        editorProps={{ $blockScrolling: Infinity }}
        setOptions={setOptions}
        onChange={handleStoryChange}
        debounceChangePeriod={100}
        onBlur={handleStoryBlur}
      />
      <div className={cssStyle.copyIcon}>
        <Clipboard
          text={confString}
          onCopy={onButtonCopy}
          icon={{ theme: "outlined" }}
        />
      </div>
    </div>
  );
}
Example #19
Source File: Chart.tsx    From majsoul-api with MIT License 4 votes vote down vote up
ChartComponent = React.forwardRef<Chart | undefined, ChartProps>((props, ref) => {
	const {
		id,
		className,
		height = 150,
		width = 300,
		redraw = false,
		type,
		data,
		plugins,
		options = {},
		getDatasetAtEvent,
		getElementAtEvent,
		getElementsAtEvent,
		fallbackContent,
		...rest
	} = props;

	const canvas = React.useRef<HTMLCanvasElement>(null);

	const computedData = React.useMemo<ChartData>(() => {
		if (typeof data === 'function') {
			return canvas.current ? data(canvas.current) : {} as ChartData;
		} else {
			return { ...data };
		}
	}, [data, canvas.current]);

	const [chart, setChart] = React.useState<Chart>();

	React.useImperativeHandle<Chart | undefined, Chart | undefined>(ref, () => chart, [
		chart,
	]);

	const renderChart = () => {
		if (!canvas.current) {
			return;
		}

		setChart(
			new Chart(canvas.current, {
				type,
				data: computedData,
				options,
				plugins,
			})
		);
	};

	const onClick = (event: React.MouseEvent<HTMLCanvasElement>) => {
		if (!chart) {
			return;
		}

		getDatasetAtEvent &&
			getDatasetAtEvent(
				chart.getElementsAtEventForMode(
					event.nativeEvent,
					'dataset',
					{ intersect: true },
					false
				),
				event
			);

		getElementAtEvent &&
			getElementAtEvent(
				chart.getElementsAtEventForMode(
					event.nativeEvent,
					'nearest',
					{ intersect: false },
					false
				)[0],
				event
			);

		getElementsAtEvent &&
			getElementsAtEvent(
				chart.getElementsAtEventForMode(event.nativeEvent, 'index', { intersect: true }, false),
				event
			);
	};

	const updateChart = () => {
		if (!chart) {
			return;
		}

		if (options) {
			chart.options = { ...options };
		}

		if (!chart.config.data) {
			chart.config.data = computedData;
			chart.update();
			return;
		}

		const { datasets: newDataSets = [], ...newChartData } = computedData;
		const { datasets: currentDataSets = [] } = chart.config.data;

		// copy values
		assign(chart.config.data, newChartData);
		chart.config.data.datasets = newDataSets.map((newDataSet: any) => {
			// given the new set, find it's current match
			const currentDataSet = find(
				currentDataSets,
				d => d.label === newDataSet.label && d.type === newDataSet.type
			);

			// There is no original to update, so simply add new one
			if (!currentDataSet || !newDataSet.data) {
				return newDataSet;
			}

			if (!currentDataSet.data) {
				currentDataSet.data = [];
			} else {
				currentDataSet.data.length = newDataSet.data.length;
			}

			// copy in values
			assign(currentDataSet.data, newDataSet.data);

			// apply dataset changes, but keep copied data
			return {
				...currentDataSet,
				...newDataSet,
				data: currentDataSet.data,
			};
		});

		chart.update();
	};

	const destroyChart = () => {
		if (chart) {
			chart.destroy();
		}
	};

	React.useEffect(() => {
		renderChart();
		return () => destroyChart();
	}, []);

	React.useEffect(() => {
		if (redraw) {
			destroyChart();
			setTimeout(() => {
				renderChart();
			}, 0);
		} else {
			updateChart();
		}
	}, [props, computedData]);

	return (
		<canvas
			{...rest}
			height={height}
			width={width}
			ref={canvas}
			id={id}
			className={className}
			onClick={onClick}
			data-testid='canvas'
			role='img'
		>
			{fallbackContent}
		</canvas>
	);
})