@qundus/qform
Version:
The only form library you'll ever need :)
487 lines (475 loc) • 20.8 kB
TypeScript
import { _QSTATE } from '@qundus/qstate';
import { deriveAddon, updateAddon } from '@qundus/qstate/addons';
import { OptionHooksIn } from '@qundus/qstate/hooks';
declare function createProcessors<F extends Field, O extends Options<any>>(props: ProcessorProps<F, O>): {
readonly checkbox: (checked: any, value: any) => any;
readonly file: (value: any) => any;
readonly select: (value: any) => any;
readonly number: (value: any) => number | null;
};
type FieldStoreObject<F extends Field> = {
value: F["value"] | undefined;
condition: FieldCondition;
errors?: string[];
extras?: FieldExtras<F["type"]>;
};
type FieldStore<F extends Field, O extends Options<any>> = _QSTATE.StoreDerived<FieldStoreObject<F>, {
hooks: O["hooks"];
}>;
type FormState<F extends Fields> = _QSTATE.NanoMap<FormObject<F>>;
type FormStore<F extends Fields, O extends Options<any>> = _QSTATE.Store<FormState<F>, {
hooks: O["hooks"];
addons: {
derive: typeof deriveAddon;
update: typeof updateAddon;
};
}>;
type FormButtonObject = {
status: FormStatus;
disabled: boolean;
canSubmit: boolean;
submitting: boolean;
};
type FormButtonStore<F extends Fields, O extends Options<F>> = _QSTATE.StoreDerived<FormButtonObject, {
hooks: O["hooks"];
}>;
type FormButton<F extends Fields, O extends Options<F>, S extends FormButtonStore<F, O> = FormButtonStore<F, O>> = {
$store: S;
};
declare const PLACEHOLDERS: {
readonly select: {
value: string;
disabled: boolean;
selected: boolean;
};
readonly selectButton: {
value: string;
};
};
type ElementCustomProps<D extends ElementDomType, K extends ElementKeysType> = {
dType?: D;
kType?: K;
};
interface Props<F extends Field, O extends Options<any>> {
derived: FieldStore<F, O>;
}
type FieldElement<F extends Field, O extends Options<any>> = ReturnType<typeof prepareFieldElement<F, O>>;
declare function prepareFieldElement<F extends Field, O extends Options<any>>(props: Props<F, O> & ElementProps<F, O>): {
readonly dom: <D extends ElementDomType, K extends ElementKeysType>(props?: ElementCustomProps<D, K>) => {
name: string;
value: any;
} & {
required: boolean;
disabled: boolean;
} & {
onfocus: (event: FocusEvent) => void;
onblur: (event: FocusEvent) => void;
autocomplete?: "on" | "off";
} & {
oninput: (event: Event) => void;
};
readonly preact: <D extends ElementDomType, K extends ElementKeysType>(props?: ElementCustomProps<D, K>) => {
name: string;
value: any;
} & {
required: boolean;
disabled: boolean;
} & {
onfocus: (event: FocusEvent) => void;
onblur: (event: FocusEvent) => void;
autocomplete?: "on" | "off";
} & {
oninput: (event: Event) => void;
};
readonly react: <D extends ElementDomType, K extends ElementKeysType>(props?: ElementCustomProps<D, K>) => {
name: string;
value: any;
} & {
required: boolean;
disabled: boolean;
} & {
onfocus: (event: FocusEvent) => void;
onblur: (event: FocusEvent) => void;
autocomplete?: "on" | "off";
} & {
oninput: (event: Event) => void;
};
readonly solid: <D extends ElementDomType, K extends ElementKeysType>(props?: ElementCustomProps<D, K>) => {
name: string;
value: any;
} & {
required: boolean;
disabled: boolean;
} & {
onfocus: (event: FocusEvent) => void;
onblur: (event: FocusEvent) => void;
autocomplete?: "on" | "off";
} & {
oninput: (event: Event) => void;
};
readonly svelte: {
name: string;
value: any;
} & {
required: boolean;
disabled: boolean;
} & {
onfocus: (event: FocusEvent) => void;
onblur: (event: FocusEvent) => void;
autocomplete?: "on" | "off";
} & {
oninput: (event: Event) => void;
};
ref: <K extends ElementKeysType>(ref: any, props?: ElementCustomProps<"dom", K>) => void;
};
type FieldAtom<F extends Field, O extends Options<any>> = F extends Field<infer type, infer value> ? {
$store: FieldStore<F, O>;
key: string;
type: type;
label: string;
getOptions?: F["options"];
get element(): FieldElement<F, O>;
placeholders: typeof PLACEHOLDERS;
get addValidation(): (func: FieldValidate) => (() => void) | null;
updateValue: (value: value | ((prev: value) => void), configs?: {
preprocessValue?: boolean;
}) => void;
clearValue: () => void;
updateCondition: (value: Partial<FieldCondition> | ((prev: Partial<FieldCondition>) => Partial<FieldCondition>)) => void;
} : unknown;
type Atoms<S extends Fields, O extends Options<S>> = {
[K in keyof S]: FieldAtom<S[K], O>;
};
type AtomsPrepared<S extends Fields, O extends Options<S>> = ReturnType<typeof prepareFormAtoms<S, O>>;
declare function prepareFormAtoms<F extends Fields, O extends Options<F>>(props: {
fields: F;
options: O;
$store: FormStore<F, O>;
}): {
readonly atoms: <G extends keyof F>(key: G) => Atoms<F, O>[G];
readonly elements: <G extends keyof F>(key: G) => FieldElement<Field<FieldType, string>, O>;
};
type _Processors<F extends Field, O extends Options<any>> = ReturnType<typeof createProcessors<F, O>>;
type IsUnknown<T> = unknown extends T ? true : false;
type IsUndefined<T> = unknown extends T ? never : undefined extends T ? true : false;
type IsNull<T> = unknown extends T ? never : null extends T ? true : false;
type IsEmpty<T> = unknown extends T ? never : {} extends T ? true : false;
type ElementDomType = "dom" | "vdom";
/**
* when element props is accessed, usually the returned keys are
* all that support for html element, this gives user the option
* to choose which ones are wanted.
* @default "all";
*/
type ElementKeysType = "base" | "special" | "all";
type ElementReturns<T extends ElementDomType, Base, Dom, VDom> = Base & ("dom" extends T ? Dom : VDom) extends infer G ? G : never;
type FieldType = "checkbox" | "color" | "date" | "datetime-local" | "email" | "file" | "image" | "month" | "number" | "password" | "radio" | "range" | "reset" | "search" | "tel" | "text" | "time" | "url" | "week" | "select";
type FieldValue<T extends FieldType, D> = true extends IsUnknown<D> | IsUndefined<D> | IsNull<D> ? T extends "select" ? string[] : T extends "file" ? FileList : T extends "checkbox" ? boolean : T extends "radio" ? string : T extends "tel" ? number | string : string : D;
/**
* sometimes some field types require additional information beyond the
* the standard field "value", this offers that through value processing
* and places it under FieldState or State
*/
type FieldExtras<T extends FieldType> = T extends "file" ? {
buffer: string | ArrayBuffer | null | undefined;
file: File;
placeholder: string;
name: string;
}[] : never;
type FieldCondition = {
valid: boolean;
hidden: boolean;
value: {
updated: boolean;
lastUpdate: false | "user" | "manual";
error: false | "validation" | "incomplete" | "optional";
};
element: {
state: false | "focus" | "blur";
visited: boolean;
disabled: boolean;
required: boolean;
};
};
type FieldErrors = string[] | null | undefined;
type FieldValidate = (value: any, helpers: {
$values: FormObject<any>["values"];
}) => string | string[] | undefined | null;
/**
* processor used in case of complex data values
* need to be extracted from field element and the basic
* element.value processor isn't accurate enough.
* some processors run when events like onfocus and onblur fire,
* this gives the chance to modify field state like required,
* disabled..etc, according to specific needs or logic.
*/
type FieldProcess<F extends Field, Returns> = (props: Omit<ProcessorProps<F>, "$form"> & {
value: any;
getValueOf: (key: string) => any;
getConditionOf: (key: string) => any;
$condition: FieldCondition;
processors: _Processors<F, Options<any>>;
}) => Returns;
type FieldProcessElement<D extends ElementDomType = ElementDomType> = (props: {
key: string;
element: Record<string, any>;
value: FieldStoreObject<any>;
isVdom: D extends "vdom" ? true : false;
kType: ElementKeysType;
}) => void;
/**
* Value Manual Change Mechanism (VMCM), happens when values are updated from api
* fetch data or just manual programmatic interferrence.
* this affects whether the updated values go through the proper
* channels of validation, proccessing and affects on form status or just
* updates values without affecting anything else.
* @option normal: value updates go through the proper channeels of validation, proccessing, error handling and condition report.
* @option bypass: value updates are not validated so no proccessing or error handling, condition is changed though.
* @option force-valid: value updates defaults fields value condition to valid.
* @default "normal"
*/
type FieldVMCM = "normal" | "bypass" | "force-valid";
type FieldValidateOn = "input" | "change";
type FieldOptions = (<G>(props?: G) => {
label: string;
value: string;
}[]) | null | undefined;
type Field<T extends FieldType = FieldType, V = any> = {
type: T;
/** initial value */
value?: V;
hidden?: boolean;
label?: string;
processValue?: FieldProcess<Field<any>, any> | FieldProcess<Field<any>, any>[];
/** validate value */
validate?: FieldValidate | FieldValidate[] | null;
validateOn?: FieldValidateOn;
processCondition?: FieldProcess<Field<any>, void>;
onChange?: (props: {
$value: FieldStoreObject<Field<any>>;
form: FormObject<Fields>;
}) => void;
required?: boolean;
disabled?: boolean;
/** supercedes global options */
vmcm?: FieldVMCM;
/**
* html bare element props passed, this is so preliminary right
* now and requires extra work for vdom, expect breaking changes here.
*/
processElement?: FieldProcessElement;
/**
* all values go through preprocessing phase, use this to prevent that
* @default true
*/
preprocessValue?: boolean;
/**
* checks for missing/required value and mark condition.value.error as
* incomplete.
* @default true
*/
incompleteStatus?: boolean;
/**
* allowing the field value to be null
*/
valueNullable?: boolean;
options?: T extends "select" | "radio" ? FieldOptions : null;
multiple?: T extends "select" ? boolean : false;
/**
* for when a checkbox is mandatory daah
*/
mandatory?: T extends "checkbox" ? boolean : false;
};
type Basic = null | undefined | Field | FieldType;
type Basics = Record<string, Basic>;
type BasicToField<T extends Basic> = true extends IsUnknown<T> | IsUndefined<T> | IsNull<T> | IsEmpty<T> ? Field<FieldType, string> : T extends FieldType ? Field<T, FieldValue<T, undefined>> : T extends Field ? Field<T["type"], FieldValue<T["type"], T["value"]>> : never;
type Fields<B extends Basics = Basics> = {
[K in keyof B]: BasicToField<B[K]>;
} extends infer G ? {
[K in keyof G]: G[K];
} : never;
type FormStatus = "idle" | "incomplete" | "error" | "valid" | "submit";
type FormValues<T extends Fields> = {
[K in keyof T]: T[K]["value"];
};
type FormErrors<T extends Fields> = undefined | null | {
[K in keyof T]?: string[];
};
type FormConditions<T extends Fields> = {
[K in keyof T]: FieldCondition;
};
type FormExtras<T extends Fields> = {
[K in keyof T as FieldExtras<T[K]["type"]> extends never ? never : K]: FieldExtras<T[K]["type"]>;
};
type FormObject<F extends Fields> = {
values: FormValues<F>;
conditions: FormConditions<F>;
errors: FormErrors<F>;
extras: FormExtras<F>;
incomplete: string[];
status: FormStatus;
} extends infer G ? {
[K in keyof G]: G[K];
} : never;
type Options<F extends Fields> = {
hooks?: OptionHooksIn;
onMount?: (props: {
init: FormObject<F>;
update: (values: any) => void | Promise<void>;
}) => Promise<void> | void;
onChange?: (props: {
newValue: FormObject<F>;
abort: () => void;
}) => void;
vmcm?: FieldVMCM;
/**
* usually all values are immediatly updated in the state,
* by setting this to true, only valid values will be commited.
* @default false
*/
preventErroredValues?: boolean;
/**
* normal behavior of form is to consider all fields required
* and mark optional ones through "require" setting,
* this alters that behavior and forces all fields to be optional.
* the user then has the ability to make required fields through
* setting "required" to true
* @default true
*/
allFieldsRequired?: boolean;
allFieldsDisabled?: boolean;
/**
* global options to optin or out of values preprocessing based on field type.
* this option precedes individual ones
*/
preprocessValues?: boolean;
/**
* how should the form react to updating values using form.actions.update
* @default "silent"
*/
onUpdateKeyNotFound?: "silent" | "warn";
/**
* the last step of checking for form validity is to check for
* required fields' values and add them to the incompleteList,
* this option allows for choosing how big or small this list goes.
* @option true collect all incomplete fields
* @option false don't collect any incomplete fields
* @option number collect this many of incomplete fields
* @default false
*/
incompleteListCount?: boolean | number;
/**
* wheather the preferred method of checking values
* is ran oninput or onchange, oninput checks for validation
* for every change happens, onchange checks once there's a
* state change like blur or focus.
* field specific validateOn takes precedence here.
* @default input
*/
validateOn?: FieldValidateOn;
/**
* global element processor, gets called before or after field's specific processElement
* based on processElementOrder option.
*/
processElement?: FieldProcessElement;
/**
* determines wheather global processElement is going to take place before or after
* field's specific processElement
* @default "after"
*/
processElementOrder?: "before" | "after";
/**
* if the desired data extracted from the form is in the
* shape of a nested object, then this splitter is used
* to determine which keys are nested, for now only
* the dot is supported.
* @default '.'
*/
flatObjectKeysChar?: ".";
/**
* when no label is provided, the key is used as fallback but sometimes
* the key is meant to be unflattened later on when fetching the form data,
* so this offers a way to replace the key flatObjectKeysChar with any
* character.
* @default ' ' or empty spcace
*/
flatLabelJoinChar?: string;
};
type OptionsMerged<G extends Options<any>, D extends Options<any>> = D & G;
type InteractionProps<F extends Field, O extends Options<any>> = {
key: string;
field: F;
options: O;
event: Event | undefined | null;
value: any;
preprocessValue?: boolean;
$form: FormObject<any>;
};
type ProcessorProps<F extends Field, O extends Options<any> = Options<any>> = {
key: string;
field: F;
event: Event | undefined | null;
manualUpdate: boolean;
$form: FormObject<any>;
};
type PluginProps<F extends Fields, O extends Options<F>> = {
fields: F;
options: O;
$store: FormStore<F, O>;
};
type ElementProps<F extends Field, O extends Options<any>> = {
key: string;
field: F;
options: O;
$store: FormStore<any, O>;
};
type _model_Atoms<S extends Fields, O extends Options<S>> = Atoms<S, O>;
type _model_AtomsPrepared<S extends Fields, O extends Options<S>> = AtomsPrepared<S, O>;
type _model_Basic = Basic;
type _model_BasicToField<T extends Basic> = BasicToField<T>;
type _model_Basics = Basics;
type _model_ElementDomType = ElementDomType;
type _model_ElementKeysType = ElementKeysType;
type _model_ElementProps<F extends Field, O extends Options<any>> = ElementProps<F, O>;
type _model_ElementReturns<T extends ElementDomType, Base, Dom, VDom> = ElementReturns<T, Base, Dom, VDom>;
type _model_Field<T extends FieldType = FieldType, V = any> = Field<T, V>;
type _model_FieldAtom<F extends Field, O extends Options<any>> = FieldAtom<F, O>;
type _model_FieldCondition = FieldCondition;
type _model_FieldErrors = FieldErrors;
type _model_FieldExtras<T extends FieldType> = FieldExtras<T>;
type _model_FieldOptions = FieldOptions;
type _model_FieldProcess<F extends Field, Returns> = FieldProcess<F, Returns>;
type _model_FieldProcessElement<D extends ElementDomType = ElementDomType> = FieldProcessElement<D>;
type _model_FieldStore<F extends Field, O extends Options<any>> = FieldStore<F, O>;
type _model_FieldStoreObject<F extends Field> = FieldStoreObject<F>;
type _model_FieldType = FieldType;
type _model_FieldVMCM = FieldVMCM;
type _model_FieldValidate = FieldValidate;
type _model_FieldValidateOn = FieldValidateOn;
type _model_FieldValue<T extends FieldType, D> = FieldValue<T, D>;
type _model_Fields<B extends Basics = Basics> = Fields<B>;
type _model_FormButton<F extends Fields, O extends Options<F>, S extends FormButtonStore<F, O> = FormButtonStore<F, O>> = FormButton<F, O, S>;
type _model_FormButtonObject = FormButtonObject;
type _model_FormButtonStore<F extends Fields, O extends Options<F>> = FormButtonStore<F, O>;
type _model_FormConditions<T extends Fields> = FormConditions<T>;
type _model_FormErrors<T extends Fields> = FormErrors<T>;
type _model_FormExtras<T extends Fields> = FormExtras<T>;
type _model_FormObject<F extends Fields> = FormObject<F>;
type _model_FormState<F extends Fields> = FormState<F>;
type _model_FormStatus = FormStatus;
type _model_FormStore<F extends Fields, O extends Options<any>> = FormStore<F, O>;
type _model_FormValues<T extends Fields> = FormValues<T>;
type _model_InteractionProps<F extends Field, O extends Options<any>> = InteractionProps<F, O>;
type _model_IsEmpty<T> = IsEmpty<T>;
type _model_IsNull<T> = IsNull<T>;
type _model_IsUndefined<T> = IsUndefined<T>;
type _model_IsUnknown<T> = IsUnknown<T>;
type _model_Options<F extends Fields> = Options<F>;
type _model_OptionsMerged<G extends Options<any>, D extends Options<any>> = OptionsMerged<G, D>;
type _model_PluginProps<F extends Fields, O extends Options<F>> = PluginProps<F, O>;
type _model_ProcessorProps<F extends Field, O extends Options<any> = Options<any>> = ProcessorProps<F, O>;
type _model__Processors<F extends Field, O extends Options<any>> = _Processors<F, O>;
declare namespace _model {
export type { _model_Atoms as Atoms, _model_AtomsPrepared as AtomsPrepared, _model_Basic as Basic, _model_BasicToField as BasicToField, _model_Basics as Basics, _model_ElementDomType as ElementDomType, _model_ElementKeysType as ElementKeysType, _model_ElementProps as ElementProps, _model_ElementReturns as ElementReturns, _model_Field as Field, _model_FieldAtom as FieldAtom, _model_FieldCondition as FieldCondition, _model_FieldErrors as FieldErrors, _model_FieldExtras as FieldExtras, _model_FieldOptions as FieldOptions, _model_FieldProcess as FieldProcess, _model_FieldProcessElement as FieldProcessElement, _model_FieldStore as FieldStore, _model_FieldStoreObject as FieldStoreObject, _model_FieldType as FieldType, _model_FieldVMCM as FieldVMCM, _model_FieldValidate as FieldValidate, _model_FieldValidateOn as FieldValidateOn, _model_FieldValue as FieldValue, _model_Fields as Fields, _model_FormButton as FormButton, _model_FormButtonObject as FormButtonObject, _model_FormButtonStore as FormButtonStore, _model_FormConditions as FormConditions, _model_FormErrors as FormErrors, _model_FormExtras as FormExtras, _model_FormObject as FormObject, _model_FormState as FormState, _model_FormStatus as FormStatus, _model_FormStore as FormStore, _model_FormValues as FormValues, _model_InteractionProps as InteractionProps, _model_IsEmpty as IsEmpty, _model_IsNull as IsNull, _model_IsUndefined as IsUndefined, _model_IsUnknown as IsUnknown, _model_Options as Options, _model_OptionsMerged as OptionsMerged, _model_PluginProps as PluginProps, _model_ProcessorProps as ProcessorProps, _model__Processors as _Processors };
}
export { type AtomsPrepared as A, type Basics as B, type Fields as F, type Options as O, type PluginProps as P, _model as _, type FieldCondition as a, type FormButton as b, PLACEHOLDERS as c, type FormObject as d, type OptionsMerged as e, type FieldType as f, type Field as g };