Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Precise UI Changelog

## 2.1.14

- Improve validation of `Form`

## 2.1.13

- Fix WCAG error: Empty table header in case of JSX element
Expand Down
8 changes: 7 additions & 1 deletion mlc_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
"ignorePatterns": [
{
"pattern": "^https://stackoverflow.com/tags/"
},
{
"pattern": "^https://guides.github.com/"
}
],
"aliveStatusCodes": [429, 200]
"aliveStatusCodes": [
429,
200
]
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "precise-ui",
"version": "2.1.13",
"version": "2.1.14",
"description": "Precise UI React component library powered by Styled Components.",
"keywords": [
"react",
Expand Down
4 changes: 4 additions & 0 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,10 @@ export interface InputProps<T> extends StandardProps {
* Sets maximum lenngth of input field.
*/
maxLength?: number;
/**
* List of fields, that need to be revalidated when the field value is changed
*/
validateWith?: Array<string>;
}

export interface LabeledInputProps<T> extends InputProps<T> {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Autocomplete/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class AutocompleteInt<T> extends React.Component<SupportedAutocompleteProps<T> &
const { onChange, name = '', form } = this.props;

if (!this.state.controlled) {
form ? form.change({ name, value }) : this.setState({ value });
form ? form.change({ name, value, validateWith: this.props.validateWith }) : this.setState({ value });
}

suggestionSelected ? this.hide() : this.show();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export class AutocompleteTagBuilderInt<T> extends React.Component<
form.change({
name,
value: newValue,
validateWith: this.props.validateWith,
});
} else {
this.setState({
Expand Down
1 change: 1 addition & 0 deletions src/components/Checkbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export class CheckboxInt extends React.PureComponent<CheckboxProps, CheckboxStat
form.change({
name,
value: checked,
validateWith: this.props.validateWith,
});
} else {
this.setState({
Expand Down
1 change: 1 addition & 0 deletions src/components/ColorPicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ class ColorPickerInt extends React.PureComponent<ColorPickerProps & FormContextP
form.change({
name,
value: (state as Pick<ColorPickerState, 'value'>).value,
validateWith: this.props.validateWith,
});
} else {
this.setState(state);
Expand Down
1 change: 1 addition & 0 deletions src/components/DateField/DateFieldInt.part.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ class DateFieldInt extends React.Component<DateFieldProps, DateFieldState> {
form.change({
name,
value,
validateWith: this.props.validateWith,
});
this.onOpenChange(true);
});
Expand Down
1 change: 1 addition & 0 deletions src/components/DropdownField/DropdownFieldInt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ export class DropdownFieldInt extends React.Component<DropdownFieldProps & FormC
form.change({
name,
value,
validateWith: this.props.validateWith,
});
} else {
this.setState({
Expand Down
2 changes: 2 additions & 0 deletions src/components/Dropzone/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class DropzoneInt extends React.Component<DropzoneProps & FormContextProps, Drop
form.change({
name,
value: multiple ? [...this.state.value, ...files] : files,
validateWith: this.props.validateWith,
});
} else {
this.setState(
Expand Down Expand Up @@ -250,6 +251,7 @@ class DropzoneInt extends React.Component<DropzoneProps & FormContextProps, Drop
form.change({
name,
value: this.state.value.filter(file => f !== file),
validateWith: this.props.validateWith,
});
} else {
this.setState(
Expand Down
2 changes: 2 additions & 0 deletions src/components/FileSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class FileSelectInt extends React.Component<FileSelectProps & FormContextProps,
form.change({
name,
value: getFiles(multiple ? [...this.state.value] : [], files),
validateWith: this.props.validateWith,
});
} else {
this.setState(
Expand All @@ -130,6 +131,7 @@ class FileSelectInt extends React.Component<FileSelectProps & FormContextProps,
form.change({
name,
value: this.state.value.filter(file => f !== file),
validateWith: this.props.validateWith,
});
} else {
this.setState(
Expand Down
27 changes: 16 additions & 11 deletions src/components/Form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export interface FormProps<FormValues> extends StandardProps {
/**
* Rules for validating fields values.
*/
validationRules?: { [T in keyof FormValues]?: (value: any) => React.ReactChild | true };
validationRules?: { [T in keyof FormValues]?: (value: any, formValues: FormValues) => React.ReactChild | true };
/**
* Event emitted when a field of the form changed.
*/
Expand Down Expand Up @@ -215,9 +215,9 @@ export class Form<Values extends FormValuesData> extends React.Component<FormPro
}
}

private getError(name: string, value: any) {
private getError(name: string, value: any, current: Values) {
const validator = this.props.validationRules && this.props.validationRules[name];
const validationResult = validator ? validator(value) : true;
const validationResult = validator ? validator(value, current) : true;
const error = validationResult === true ? undefined : validationResult;
return error;
}
Expand All @@ -231,8 +231,8 @@ export class Form<Values extends FormValuesData> extends React.Component<FormPro
}
}

private setError({ name, value }: FormValueChange) {
const error = this.getError(name, value);
private setError({ name, value }: FormValueChange, current: Values) {
const error = this.getError(name, value, current);
this.setFieldError(name, error);

this.setState({ errors: { ...this.state.errors, [name]: error } });
Expand All @@ -244,12 +244,13 @@ export class Form<Values extends FormValuesData> extends React.Component<FormPro

for (const key of keys as Array<Extract<keyof Values, string>>) {
const value = current[key];
const error = this.getError(key, value);
const error = this.getError(key, value, current);
errors[key] = error;
this.setFieldError(key, error);
}

this.setState({ errors });
return errors;
}

private createContext(): FormContextType {
Expand All @@ -267,7 +268,11 @@ export class Form<Values extends FormValuesData> extends React.Component<FormPro
this.setValues(proposed, changed);
}

this.setError(field);
this.setError(field, proposed);

(field.validateWith || []).forEach((fieldName: string) => {
return this.setError({ name: fieldName, value: proposed[fieldName] }, proposed);
});

if (typeof onChange === 'function') {
onChange({
Expand All @@ -286,14 +291,14 @@ export class Form<Values extends FormValuesData> extends React.Component<FormPro
let error: React.ReactChild | undefined;
if (name in current) {
const value = current[name];
error = this.getError(name, value);
error = this.getError(name, value, current);
field.setState({
value,
});
} else {
const value = field.state.value;
current[name as Extract<keyof Values, string>] = value;
error = this.getError(name, value);
error = this.getError(name, value, current);
}

if (error) {
Expand All @@ -310,9 +315,9 @@ export class Form<Values extends FormValuesData> extends React.Component<FormPro

private submit = (e: React.FormEvent<HTMLFormElement>) => {
const { onSubmit, disabled } = this.props;
const { current, changed, errors } = this.state;
const { current, changed } = this.state;

this.setErrors(current);
const errors = this.setErrors(current);

if (!disabled && typeof onSubmit === 'function') {
const arrayErrors = this.getErrorsAsArray(errors);
Expand Down
5 changes: 5 additions & 0 deletions src/components/RadioButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export interface RadioButtonProps extends StandardProps {
* Name of the radio button within a radio button group.
*/
name?: string;
/**
* List of fields, that need to be revalidated when the field value is changed
*/
validateWith?: Array<string>;
}

export interface RadioButtonIntProps extends RadioButtonProps {
Expand Down Expand Up @@ -213,6 +217,7 @@ export class RadioButtonInt extends React.PureComponent<RadioButtonIntProps & Fo
form.change({
name,
value,
validateWith: this.props.validateWith,
});
} else {
this.setState({
Expand Down
1 change: 1 addition & 0 deletions src/components/RadioButtonGroup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class RadioButtonGroupInt extends React.PureComponent<RadioButtonGroupProps & Fo
form.change({
name,
value,
validateWith: this.props.validateWith,
});
} else if (value) {
this.setState({
Expand Down
1 change: 1 addition & 0 deletions src/components/Rating/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ class RatingInt extends React.Component<RatingProps & FormContextProps, RatingSt
form.change({
name,
value,
validateWith: this.props.validateWith,
});
} else {
this.setState({
Expand Down
1 change: 1 addition & 0 deletions src/components/Slider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ class SliderInt extends React.PureComponent<SliderProps & FormContextProps, Slid
form.change({
name,
value,
validateWith: this.props.validateWith,
});
} else {
this.setState({
Expand Down
1 change: 1 addition & 0 deletions src/components/TagBuilder/TagBuilderInt.part.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ export class TagBuilderInt extends React.Component<TagBuilderProps & FormContext
form.change({
name,
value,
validateWith: this.props.validateWith,
});
} else {
this.setState({
Expand Down
1 change: 1 addition & 0 deletions src/components/TextField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class TextFieldInt extends React.Component<TextFieldProps & FormContextProps, Te
form.change({
name,
value,
validateWith: this.props.validateWith,
});
} else {
this.setState({
Expand Down
1 change: 1 addition & 0 deletions src/components/Toggle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ class ToggleInt extends React.PureComponent<ToggleProps & FormContextProps, Togg
form.change({
name,
value: status,
validateWith: this.props.validateWith,
});
} else {
this.setState({
Expand Down
1 change: 1 addition & 0 deletions src/contexts/FormContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface FormValueNotifier {
export interface FormValueChange {
name: string;
value: any;
validateWith?: Array<string>;
}

export interface FormContextType {
Expand Down