feat: add calidation (#37009)

* feat: add calidation

* fix: update tslint rule, define typescript version

* fix: remove lint rule, use ts@3.5 omit
This commit is contained in:
Ray Knight 2019-07-19 13:44:08 -07:00 committed by Andrew Branch
parent a1f6013ddd
commit d30cbbd8cd
4 changed files with 240 additions and 0 deletions

View File

@ -0,0 +1,78 @@
import * as React from 'react';
import {
Dictionary,
FieldsConfig,
Form,
FormContext,
FormValidation,
Transforms,
Validation,
ValidationContext,
ValidatorContext,
} from 'calidation';
const config: FieldsConfig = {
foo: {
isRequired: 'This field is required',
isNumber: 'This field must be a number',
isGreaterThan: {
message: 'This field must be greater than 7',
value: 7,
validateIf: ({ isDirty }: ValidatorContext) => isDirty,
},
},
};
const initialValues: Dictionary = { foo: 0 };
const transforms: Transforms = { foo: parseInt };
function onChange(event: React.ChangeEvent<HTMLFormElement>): void {
console.log(event);
}
function onReset(): void {
console.log('form has been reset');
}
function onSubmit(context: FormContext): void {
console.log(context);
}
function onUpdate(context: FormContext): void {
console.log(context);
}
const FormTest = () => (
<Form onChange={onChange} onReset={onReset} onSubmit={onSubmit} onUpdate={onUpdate}>
<Validation config={config} initialValues={initialValues} transforms={transforms}>
{({ dirty, errors, fields }: ValidationContext) => (
<div>
<label>Input</label>
<input name="foo" value={`${fields.foo}`} />
{dirty.foo && errors.foo && <p>{errors.foo}</p>}
</div>
)}
</Validation>
</Form>
);
const FormValidationTest = () => (
<FormValidation
onChange={onChange}
onReset={onReset}
onSubmit={onSubmit}
onUpdate={onUpdate}
config={config}
initialValues={initialValues}
transforms={transforms}
>
{({ dirty, errors, fields }: ValidationContext) => (
<div>
<label>Input</label>
<input name="foo" value={`${fields.foo}`} />
{dirty.foo && errors.foo && <p>{errors.foo}</p>}
</div>
)}
</FormValidation>
);

134
types/calidation/index.d.ts vendored Normal file
View File

@ -0,0 +1,134 @@
// Type definitions for calidation 1.16
// Project: https://github.com/selbekk/calidation#readme
// Definitions by: Ray Knight <https://github.com/ArrayKnight>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 3.5
import * as React from 'react';
export interface Dictionary<T = any> {
[key: string]: T;
}
export type Dirty = Dictionary<boolean>;
export type Errors = Dictionary<string | null>;
export type Fields = Dictionary;
export type Transforms = Dictionary<(value: any) => any>;
export interface ValidatorContext {
errors: Errors;
fields: Fields;
isDirty: boolean;
}
export interface SimpleValidatorConfig {
message: string;
validateIf?: ((context: ValidatorContext) => boolean) | boolean;
}
export type SimpleValidator = string | SimpleValidatorConfig | ((context: ValidatorContext) => SimpleValidatorConfig);
export interface BlacklistValidatorConfig extends SimpleValidatorConfig {
blacklist: string[];
}
export type BlacklistValidator = BlacklistValidatorConfig | ((context: ValidatorContext) => BlacklistValidatorConfig);
export interface ValueValidatorConfig<T> extends SimpleValidatorConfig {
value: T;
}
export type ValueValidator<T> = ValueValidatorConfig<T> | ((context: ValidatorContext) => ValueValidatorConfig<T>);
export interface RegexValidatorConfig extends SimpleValidatorConfig {
regex: RegExp;
}
export type RegexValidator = RegexValidatorConfig | ((context: ValidatorContext) => RegexValidatorConfig);
export interface WhitelistValidatorConfig extends SimpleValidatorConfig {
whitelist: string[];
}
export type WhitelistValidator = WhitelistValidatorConfig | ((context: ValidatorContext) => RegexValidatorConfig);
export interface LengthValidatorConfig extends SimpleValidatorConfig {
length: number;
}
export type LengthValidator = LengthValidatorConfig | ((context: ValidatorContext) => LengthValidatorConfig);
export type Validator =
| SimpleValidator
| BlacklistValidator
| ValueValidator<any>
| RegexValidator
| WhitelistValidator
| LengthValidator;
export interface FieldConfig {
isBlacklisted?: BlacklistValidator;
isEmail?: SimpleValidator;
isEqual?: ValueValidator<any>;
isGreaterThan?: ValueValidator<number>;
isLessThan?: ValueValidator<number>;
isRequired?: SimpleValidator;
isNumber?: SimpleValidator;
isRegexMatch?: RegexValidator;
isWhitelisted?: WhitelistValidator;
isMinLength?: LengthValidator;
isMaxLength?: LengthValidator;
isExactLength?: LengthValidator;
}
export type FieldsConfig = Dictionary<FieldConfig>;
export interface FormContext {
dirty: Dirty;
errors: Errors;
fields: Fields;
isValid: boolean;
resetAll: () => void;
register: (config: FieldsConfig, transforms: Transforms, initialValues: Dictionary) => void;
unregister: (config: FieldsConfig) => void;
setError: (delta: Errors) => void;
setField: (delta: Fields) => void;
submit: () => void;
submitted: boolean;
}
export interface FormProps
extends Omit<React.DetailedHTMLProps<React.FormHTMLAttributes<HTMLFormElement>, HTMLFormElement>, 'onSubmit'> {
onChange?: (event: React.ChangeEvent<HTMLFormElement>) => void;
onReset?: () => void;
onSubmit?: (context: FormContext) => void;
onUpdate?: (context: FormContext) => void;
}
export class Form extends React.Component<FormProps> {}
export type ValidationContext = Omit<FormContext, 'register' | 'unregister'>;
export interface ValidationProps {
children: (context: ValidationContext) => React.ReactNode;
config: FieldsConfig;
initialValues?: Dictionary;
transforms?: Transforms;
}
export class Validation extends React.Component<ValidationProps> {}
export interface FormValidationProps extends FormProps, ValidationProps {
children: (context: ValidationContext) => React.ReactNode;
}
export class FormValidation extends React.Component<FormValidationProps> {}
export interface ValidatorsProviderProps {
validators: Dictionary<(config: SimpleValidatorConfig) => (value: any) => string | null>;
}
export class ValidatorsProvider extends React.Component<ValidatorsProviderProps> {}

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"jsx": "react",
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"calidation-tests.tsx"
]
}

View File

@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}