Custom terminal fonts support (#5414)

Fixes #5132 #5133 
- bundled 7 new monospaced fonts for terminal
- fix: refresh terminal font after changing in the preferences / keep cluster iframe accessible in DOM while not active/focused
- display terminal's custom font preview with font-name in the select-box + live-preload for current `fontSize`, fix lint

* Fixes for <Input/>:
- remove duplicated error messages for sync validators
- don't propagate invalid values on change (uncontrolled components only)
- more informative error message for numeric input with min/max info
This commit is contained in:
Roman authored and GitHub committed 2022-06-06 18:03:12 +03:00
1 parent fae6bff6fb
commit 55a977554d
38 files changed
+325 -146

No files matched your search

+24 -19
View File
@@ -14,7 +14,6 @@ import { Tooltip } from "../tooltip";
import * as Validators from "./input_validators";
import type { InputValidator } from "./input_validators";
import isFunction from "lodash/isFunction";
import isBoolean from "lodash/isBoolean";
import uniqueId from "lodash/uniqueId";
import { debounce } from "lodash";
@@ -24,7 +23,10 @@ export { InputValidators };
export type { InputValidator };
type InputElement = HTMLInputElement | HTMLTextAreaElement;
type InputElementProps = InputHTMLAttributes<HTMLInputElement> & TextareaHTMLAttributes<HTMLTextAreaElement> & DOMAttributes<InputElement>;
type InputElementProps =
InputHTMLAttributes<HTMLInputElement>
& TextareaHTMLAttributes<HTMLTextAreaElement>
& DOMAttributes<InputElement>;
export interface IconDataFnArg {
isDirty: boolean;
@@ -173,22 +175,18 @@ export class Input extends React.Component<InputProps, State> {
error => this.getValidatorError(value, validator) || error,
),
);
} else {
if (!validator.validate(value, this.props)) {
errors.push(this.getValidatorError(value, validator));
}
}
const result = validator.validate(value, this.props);
const isValid = validator.validate(value, this.props);
if (isBoolean(result) && !result) {
if (isValid === false) {
errors.push(this.getValidatorError(value, validator));
} else if (result instanceof Promise) {
} else if (isValid instanceof Promise) {
if (!validationId) {
this.validationId = validationId = uniqueId("validation_id_");
}
asyncValidators.push(
result.then(
isValid.then(
() => null, // don't consider any valid result from promise since we interested in errors only
error => this.getValidatorError(value, validator) || error,
),
@@ -266,17 +264,25 @@ export class Input extends React.Component<InputProps, State> {
setDirtyOnChange = debounce(() => this.setDirty(), 500);
onChange(evt: React.ChangeEvent<any>) {
this.props.onChange?.(evt.currentTarget.value, evt);
this.validate();
async onChange(evt: React.ChangeEvent<any>) {
const newValue = evt.currentTarget.value;
const eventCopy = { ...evt };
this.autoFitHeight();
this.setDirtyOnChange();
// re-render component when used as uncontrolled input
// when used @defaultValue instead of @value changing real input.value doesn't call render()
if (this.isUncontrolled && this.showMaxLenIndicator) {
this.forceUpdate();
// Handle uncontrolled components (`props.defaultValue` must be used instead `value`)
if (this.isUncontrolled) {
// update DOM since render() is not called on input's changes with uncontrolled inputs
if (this.showMaxLenIndicator) this.forceUpdate();
// don't propagate changes for invalid values
await this.validate();
if (!this.state.valid) return; // skip
}
// emit new value update
this.props.onChange?.(newValue, eventCopy);
}
onKeyDown(evt: React.KeyboardEvent<InputElement>) {
@@ -299,7 +305,7 @@ export class Input extends React.Component<InputProps, State> {
this.setDirty();
}
if(this.props.blurOnEnter){
if (this.props.blurOnEnter) {
//pressing enter indicates that the edit is complete, we can unfocus now
this.blur();
}
@@ -379,7 +385,6 @@ export class Input extends React.Component<InputProps, State> {
multiLine, showValidationLine, validators, theme, maxRows, children, showErrorsAsTooltip,
maxLength, rows, disabled, autoSelectOnFocus, iconLeft, iconRight, contentRight, id,
dirty: _dirty, // excluded from passing to input-element
defaultValue,
trim,
blurOnEnter,
...inputProps
@@ -8,7 +8,8 @@ import type { ReactNode } from "react";
import fse from "fs-extra";
import { TypedRegEx } from "typed-regex";
export class AsyncInputValidationError extends Error {}
export class AsyncInputValidationError extends Error {
}
export type InputValidator<IsAsync extends boolean> = {
/**
@@ -32,7 +33,7 @@ export type InputValidator<IsAsync extends boolean> = {
message?: undefined;
debounce: number;
}
);
);
export function inputValidator<IsAsync extends boolean = false>(validator: InputValidator<IsAsync>): InputValidator<IsAsync> {
return validator;
@@ -52,7 +53,14 @@ export const isEmail = inputValidator({
export const isNumber = inputValidator({
condition: ({ type }) => type === "number",
message: () => `Invalid number`,
message(value, { min, max }) {
const minMax: string = [
typeof min === "number" ? `min: ${min}` : undefined,
typeof max === "number" ? `max: ${max}` : undefined,
].filter(Boolean).join(", ");
return `Invalid number${minMax ? ` (${minMax})` : ""}`;
},
validate: (value, { min, max }) => {
const numVal = +value;