mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
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 Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
27c67c3e2e
commit
36710e2b08
@ -8,7 +8,7 @@ import { action } from "mobx";
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import type { UserStore } from "../../../common/user-store";
|
import type { UserStore } from "../../../common/user-store";
|
||||||
import { SubTitle } from "../layout/sub-title";
|
import { SubTitle } from "../layout/sub-title";
|
||||||
import { Input, InputValidators } from "../input";
|
import { Input } from "../input";
|
||||||
import { Switch } from "../switch";
|
import { Switch } from "../switch";
|
||||||
import { Select, type SelectOption } from "../select";
|
import { Select, type SelectOption } from "../select";
|
||||||
import type { ThemeStore } from "../../themes/store";
|
import type { ThemeStore } from "../../themes/store";
|
||||||
@ -104,8 +104,8 @@ const NonInjectedTerminal = observer((
|
|||||||
theme="round-black"
|
theme="round-black"
|
||||||
type="number"
|
type="number"
|
||||||
min={10}
|
min={10}
|
||||||
validators={InputValidators.isNumber}
|
max={50}
|
||||||
value={userStore.terminalConfig.fontSize.toString()}
|
defaultValue={userStore.terminalConfig.fontSize.toString()}
|
||||||
onChange={(value) => userStore.terminalConfig.fontSize = Number(value)}
|
onChange={(value) => userStore.terminalConfig.fontSize = Number(value)}
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import { Tooltip } from "../tooltip";
|
|||||||
import * as Validators from "./input_validators";
|
import * as Validators from "./input_validators";
|
||||||
import type { InputValidator } from "./input_validators";
|
import type { InputValidator } from "./input_validators";
|
||||||
import isFunction from "lodash/isFunction";
|
import isFunction from "lodash/isFunction";
|
||||||
import isBoolean from "lodash/isBoolean";
|
|
||||||
import uniqueId from "lodash/uniqueId";
|
import uniqueId from "lodash/uniqueId";
|
||||||
import { debounce } from "lodash";
|
import { debounce } from "lodash";
|
||||||
|
|
||||||
@ -24,7 +23,10 @@ export { InputValidators };
|
|||||||
export type { InputValidator };
|
export type { InputValidator };
|
||||||
|
|
||||||
type InputElement = HTMLInputElement | HTMLTextAreaElement;
|
type InputElement = HTMLInputElement | HTMLTextAreaElement;
|
||||||
type InputElementProps = InputHTMLAttributes<HTMLInputElement> & TextareaHTMLAttributes<HTMLTextAreaElement> & DOMAttributes<InputElement>;
|
type InputElementProps =
|
||||||
|
InputHTMLAttributes<HTMLInputElement>
|
||||||
|
& TextareaHTMLAttributes<HTMLTextAreaElement>
|
||||||
|
& DOMAttributes<InputElement>;
|
||||||
|
|
||||||
export interface IconDataFnArg {
|
export interface IconDataFnArg {
|
||||||
isDirty: boolean;
|
isDirty: boolean;
|
||||||
@ -173,22 +175,18 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
error => this.getValidatorError(value, validator) || error,
|
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));
|
errors.push(this.getValidatorError(value, validator));
|
||||||
} else if (result instanceof Promise) {
|
} else if (isValid instanceof Promise) {
|
||||||
if (!validationId) {
|
if (!validationId) {
|
||||||
this.validationId = validationId = uniqueId("validation_id_");
|
this.validationId = validationId = uniqueId("validation_id_");
|
||||||
}
|
}
|
||||||
asyncValidators.push(
|
asyncValidators.push(
|
||||||
result.then(
|
isValid.then(
|
||||||
() => null, // don't consider any valid result from promise since we interested in errors only
|
() => null, // don't consider any valid result from promise since we interested in errors only
|
||||||
error => this.getValidatorError(value, validator) || error,
|
error => this.getValidatorError(value, validator) || error,
|
||||||
),
|
),
|
||||||
@ -266,9 +264,7 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
|
|
||||||
setDirtyOnChange = debounce(() => this.setDirty(), 500);
|
setDirtyOnChange = debounce(() => this.setDirty(), 500);
|
||||||
|
|
||||||
onChange(evt: React.ChangeEvent<any>) {
|
async onChange(evt: React.ChangeEvent<any>) {
|
||||||
this.props.onChange?.(evt.currentTarget.value, evt);
|
|
||||||
this.validate();
|
|
||||||
this.autoFitHeight();
|
this.autoFitHeight();
|
||||||
this.setDirtyOnChange();
|
this.setDirtyOnChange();
|
||||||
|
|
||||||
@ -277,6 +273,17 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
if (this.isUncontrolled && this.showMaxLenIndicator) {
|
if (this.isUncontrolled && this.showMaxLenIndicator) {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const newValue = evt.currentTarget.value;
|
||||||
|
const eventCopy = { ...evt };
|
||||||
|
|
||||||
|
await this.validate(); // validate first
|
||||||
|
|
||||||
|
// don't propagate changes for invalid values
|
||||||
|
// possible only with uncontrolled components (defaultValue={} must be used instead value={})
|
||||||
|
if (!this.isUncontrolled || (this.isUncontrolled && this.state.valid)) {
|
||||||
|
this.props.onChange?.(newValue, eventCopy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown(evt: React.KeyboardEvent<InputElement>) {
|
onKeyDown(evt: React.KeyboardEvent<InputElement>) {
|
||||||
@ -299,7 +306,7 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
this.setDirty();
|
this.setDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.props.blurOnEnter){
|
if (this.props.blurOnEnter) {
|
||||||
//pressing enter indicates that the edit is complete, we can unfocus now
|
//pressing enter indicates that the edit is complete, we can unfocus now
|
||||||
this.blur();
|
this.blur();
|
||||||
}
|
}
|
||||||
@ -379,7 +386,6 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
multiLine, showValidationLine, validators, theme, maxRows, children, showErrorsAsTooltip,
|
multiLine, showValidationLine, validators, theme, maxRows, children, showErrorsAsTooltip,
|
||||||
maxLength, rows, disabled, autoSelectOnFocus, iconLeft, iconRight, contentRight, id,
|
maxLength, rows, disabled, autoSelectOnFocus, iconLeft, iconRight, contentRight, id,
|
||||||
dirty: _dirty, // excluded from passing to input-element
|
dirty: _dirty, // excluded from passing to input-element
|
||||||
defaultValue,
|
|
||||||
trim,
|
trim,
|
||||||
blurOnEnter,
|
blurOnEnter,
|
||||||
...inputProps
|
...inputProps
|
||||||
|
|||||||
@ -8,7 +8,8 @@ import type { ReactNode } from "react";
|
|||||||
import fse from "fs-extra";
|
import fse from "fs-extra";
|
||||||
import { TypedRegEx } from "typed-regex";
|
import { TypedRegEx } from "typed-regex";
|
||||||
|
|
||||||
export class AsyncInputValidationError extends Error {}
|
export class AsyncInputValidationError extends Error {
|
||||||
|
}
|
||||||
|
|
||||||
export type InputValidator<IsAsync extends boolean> = {
|
export type InputValidator<IsAsync extends boolean> = {
|
||||||
/**
|
/**
|
||||||
@ -32,7 +33,7 @@ export type InputValidator<IsAsync extends boolean> = {
|
|||||||
message?: undefined;
|
message?: undefined;
|
||||||
debounce: number;
|
debounce: number;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export function inputValidator<IsAsync extends boolean = false>(validator: InputValidator<IsAsync>): InputValidator<IsAsync> {
|
export function inputValidator<IsAsync extends boolean = false>(validator: InputValidator<IsAsync>): InputValidator<IsAsync> {
|
||||||
return validator;
|
return validator;
|
||||||
@ -52,7 +53,14 @@ export const isEmail = inputValidator({
|
|||||||
|
|
||||||
export const isNumber = inputValidator({
|
export const isNumber = inputValidator({
|
||||||
condition: ({ type }) => type === "number",
|
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 }) => {
|
validate: (value, { min, max }) => {
|
||||||
const numVal = +value;
|
const numVal = +value;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user