import { HTMLTemplateResult, LitElement, TemplateResult } from "lit";
import { Ref } from "lit-html/directives/ref.js";
import {
FButtonState,
FDividerState,
FEmojiPickerCustomEmojiData,
FEmojiPickerExcludesCategories,
FEmojiPickerIncludesCategories,
FFileUploadFileType,
FFileUploadSizeProp,
FIconButtonSize,
FIconButtonState,
FIconButtonType,
FIconButtonVariant,
FSelectOptions,
FSuggestSuggestions,
FSelectOptionTemplate,
FDateTimePickerState,
FDateOption,
DateDisableType,
FRootTooltip,
FColorPickerState,
FSelectMaxOptionsWidth,
FSuggestWhen
} from "@nonfx/flow-core";
import { BetweenParams } from "./modules/validation/rules/between";
import { SimpleSubject } from "@nonfx/flow-core-config";
import { MaxParams } from "./modules/validation/rules/max";
import { MinParams } from "./modules/validation/rules/min";
import { MaxValueParams } from "./modules/validation/rules/max-value";
import { MinValueParams } from "./modules/validation/rules/min-value";
import { RegexParams } from "./modules/validation/rules/regex";
export type FormBuilderFieldEvents = {
onClick?: (event: PointerEvent) => void;
onInput?: (event: Event) => void;
onFocus?: (event: FocusEvent) => void;
onKeyPress?: (event: KeyboardEvent) => void;
onKeyDown?: (event: KeyboardEvent) => void;
onKeyUp?: (event: KeyboardEvent) => void;
onMouseOver?: (event: MouseEvent) => void;
};
export type FormBuilderBaseField = {
id?: string; // id to uniquely identify in DOM
state?: "default" | "success" | "danger" | "warning" | "primary";
className?: string; // any additional css class name
qaId?: string; // data dq attribute for qa automation
label?: FormBuilderLabel; // label of field
ariaLabel?: string;
layout?: "label-left";
validationRules?: FormBuilderValidationRules; // validation rules to validate field
disabled?: boolean;
helperText?: string | HTMLTemplateResult;
showWhen?: FormBuilderShowCondition;
} & FormBuilderFieldEvents;
export type FormBuilderArrayField = FormBuilderBaseField & {
type: "array";
field: FormBuilderField;
label: FormBuilderLabel;
allowEmpty?: boolean;
};
export type FormBuilderColorPickerField = FormBuilderBaseField & {
type: "color";
state?: FColorPickerState;
readOnly?: boolean;
};
export type FormBuilderSeparatorField = FormBuilderFieldEvents & {
id?: string; // id to uniquely identify in DOM
state?: FDividerState;
className?: string; // any additional css class name
type: "separator";
title?: string;
showWhen?: FormBuilderShowCondition;
qaId?: string;
direction?: "vertical" | "horizontal";
};
export type FormBuilderHiddenField = {
id?: string; // id to uniquely identify in DOM
className?: string; // any additional css class name
type: "hidden";
qaId?: string;
showWhen?: undefined;
};
export type CanValidateFields = Exclude<
FormBuilderField,
FormBuilderSeparatorField | FormBuilderHiddenField
>;
export type FormBuilderObjectField = FormBuilderBaseField & {
type: "object";
direction?: "vertical" | "horizontal";
gap?: "small" | "medium" | "large" | "x-small";
variant?: "normal" | "compact";
isCollapsible?: boolean;
isCollapsed?: boolean;
fields: Record;
fieldSeparator?: boolean;
};
// text input type field
export type FormBuilderTextInputField = FormBuilderBaseField & {
type: "text" | "email" | "password" | "url" | "tel" | "number";
placeholder?: string;
iconLeft?: string;
iconRight?: string;
prefix?: string;
suffix?: string;
maxLength?: number;
loading?: boolean;
readonly?: boolean;
clear?: boolean;
autofocus?: boolean;
autocomplete?: string;
suffixWhen?: FormBuilderSuffixCondition;
};
export type FormBuilderEmojiField = FormBuilderBaseField & {
type: "emoji";
placeholder?: string;
recent?: string[];
include?: FEmojiPickerIncludesCategories;
exclude?: FEmojiPickerExcludesCategories;
excludeEmojis?: string[];
custom?: FEmojiPickerCustomEmojiData;
closeOnSelect?: boolean;
clear?: boolean;
disabled?: boolean;
};
export type FormBuilderDatetimeField = FormBuilderBaseField & {
type: "datetime";
mode?: "date-time" | "date-only" | "time-only";
placeholder?: string;
state?: FDateTimePickerState;
minDate?: FDateOption;
maxDate?: FDateOption;
disableDate?: DateDisableType;
clear?: boolean;
isRange?: boolean;
inline?: boolean;
weekNumber?: boolean;
disabled?: boolean;
loading?: boolean;
};
export type FormBuilderSuggestField = FormBuilderBaseField & {
type: "suggest";
placeholder?: string;
iconLeft?: string;
iconRight?: string;
prefix?: string;
suffix?: string;
maxLength?: number;
loading?: boolean;
readonly?: boolean;
clear?: boolean;
optionsMaxHeight?: string;
suggestions?: FSuggestSuggestions;
suffixWhen?: FormBuilderSuffixCondition;
suggestWhen?: FSuggestWhen;
};
export type FormBuilderFileField = FormBuilderBaseField & {
type: "file";
multiple?: boolean;
placeholder?: string;
fileType?: FFileUploadFileType;
maxSize?: FFileUploadSizeProp;
disabled?: boolean;
loading?: boolean;
};
// checkbox type field
export type FormBuilderCheckboxField = FormBuilderBaseField & {
type: "checkbox";
options: CheckboxOptions;
direction?: "vertical" | "horizontal";
gap?: "large" | "medium" | "small" | "x-small";
};
// radio type field
export type FormBuilderRadioField = FormBuilderBaseField & {
type: "radio";
options: RadioOptions;
direction?: "vertical" | "horizontal";
gap?: "large" | "medium" | "small" | "x-small";
};
// switch type field
export type FormBuilderSwitchField = FormBuilderBaseField & {
type: "switchButton";
};
//select type field
export type FormBuilderSelectField = FormBuilderBaseField & {
type: "select";
selection?: "single" | "multiple";
placeholder?: string;
options: FSelectOptions;
optionTemplate?: FSelectOptionTemplate;
iconLeft?: string;
height?: number;
width?: string | number;
maxOptionsWidth?: FSelectMaxOptionsWidth;
searchable?: boolean;
clear?: boolean;
checkbox?: boolean;
selectionLimit?: number;
createOption?: boolean;
loading?: boolean;
useVirtualizer?: boolean;
};
// text-area type field
export type FormBuilderTextAreaField = FormBuilderBaseField & {
type: "textarea";
placeholder?: string;
maxLength?: number;
readonly?: boolean;
clear?: boolean;
rows?: string;
resizable?: boolean;
maskValue?: boolean;
};
// button type field
export type FormBuilderButtonField = Omit & {
type: "button";
label: string;
category?: "fill" | "outline" | "transparent";
variant?: "round" | "curved" | "block";
size?: "large" | "medium" | "small" | "x-small";
state?: FButtonState;
iconLeft?: string;
iconRight?: string;
counter?: string;
loading?: boolean;
disabled?: boolean;
onMouseLeave?: (event: MouseEvent) => void;
};
// button type field
export type FormBuilderIconButtonField = Omit & {
type: "icon-button";
icon: string;
state?: FIconButtonState;
counter?: string;
loading?: boolean;
disabled?: boolean;
variant?: FIconButtonVariant;
category?: FIconButtonType;
size?: FIconButtonSize;
onMouseLeave?: (event: MouseEvent) => void;
};
export type CheckboxOption = {
id: string;
qaId?: string;
title?: string | HTMLTemplateResult;
description?: string;
iconTooltip?: FRootTooltip;
subTitle?: string;
disabled?: boolean;
};
export type RadioOption = CheckboxOption;
export type CheckboxOptions = CheckboxOption[];
export type RadioOptions = RadioOption[];
export type FormBuilderField =
| FormBuilderTextInputField
| FormBuilderCheckboxField
| FormBuilderTextAreaField
| FormBuilderRadioField
| FormBuilderSwitchField
| FormBuilderSelectField
| FormBuilderButtonField
| FormBuilderIconButtonField
| FormBuilderArrayField
| FormBuilderObjectField
| FormBuilderSuggestField
| FormBuilderFileField
| FormBuilderSeparatorField
| FormBuilderEmojiField
| FormBuilderHiddenField
| FormBuilderDatetimeField
| FormBuilderColorPickerField; // add other field types
export type FormBuilderShowCondition = (value: T) => boolean;
export type FormBuilderSuffixCondition = (value: string) => boolean;
export type FormBuilderLabel = {
title: string | HTMLTemplateResult; // title of field/group/form
description?: string; // more info about title (displayed at bottom of label)
iconTooltip?: FRootTooltip; //icon to display besides title
subTitle?: string | HTMLTemplateResult;
};
export type FormBuilderValidationRuleTriggers =
| "blur"
| "keyup"
| "click"
| "keypress"
| "focus"
| "input"
| "change";
export type FormBuilderValidationMessage = (name: string, value: Type) => string;
export type FormBuilderValidationRule = {
when?: FormBuilderValidationRuleTriggers[]; // if not specified then validation triggers on @input event.
message?: string | FormBuilderValidationMessage; // custom message by using variables in message e.x. {{name}} is required field.
params?: Record;
};
export type FormBuilderValidationRequiredRule = FormBuilderValidationRule & {
name: "required";
};
export type FormBuilderValidationEmailRule = FormBuilderValidationRule & {
name: "email";
};
export type FormBuilderValidationBetweenRule = FormBuilderValidationRule & {
name: "between";
params: BetweenParams;
};
export type FormBuilderValidationMaxRule = FormBuilderValidationRule & {
name: "max";
params: MaxParams;
};
export type FormBuilderValidationMinRule = FormBuilderValidationRule & {
name: "min";
params: MinParams;
};
export type FormBuilderValidationMaxValueRule = FormBuilderValidationRule & {
name: "max-value";
params: MaxValueParams;
};
export type FormBuilderValidationMinValueRule = FormBuilderValidationRule & {
name: "min-value";
params: MinValueParams;
};
export type FormBuilderValidationRegexRule = FormBuilderValidationRule & {
name: "regex";
params: RegexParams;
};
export type FormBuilderCustomValidationRule = FormBuilderValidationRule & {
name: "custom";
when?: FormBuilderValidationRuleTriggers[];
validate: FormBuilderValidatorFunction | FormBuilderAsyncValidatorFunction;
};
export type FormBuilderValidatorFunction<
TValue = string | unknown[],
TParams = Record
> = (value: TValue, params?: TParams) => boolean;
export type FormBuilderAsyncValidatorFunction<
TValue = string | unknown[],
TParams = Record
> = (value: TValue, params?: TParams) => Promise;
export type FormBuilderGenericValidationRule =
| FormBuilderValidationRequiredRule
| FormBuilderCustomValidationRule
| FormBuilderValidationEmailRule
| FormBuilderValidationBetweenRule
| FormBuilderValidationMaxRule
| FormBuilderValidationMinRule
| FormBuilderValidationMinValueRule
| FormBuilderValidationMaxValueRule
| FormBuilderValidationRegexRule;
export type FormBuilderValidationRules = FormBuilderGenericValidationRule[];
export type FomrBuilderSuffixStateObject = {
suffixFunction?: FormBuilderSuffixCondition;
suffix?: string;
};
export type FormBuilderFieldRenderFunction = (
name: string,
field: FormBuilderField,
fieldRef: Ref,
value: unknown
) => TemplateResult;
export type FFormInputElements = {
value: FormBuilderValues;
state?: "primary" | "default" | "success" | "warning" | "danger";
validate: (silent: boolean) => FormBuilderValidationPromise;
showWhenSubject: SimpleSubject;
} & LitElement;
export type FormBuilderValidationPromise = Promise<{
result: boolean;
message: string | null;
name: string;
label?: FormBuilderLabel | string;
rule: FormBuilderGenericValidationRule["name"];
}>;
export type FormBuilderValues =
| Record
| Record[]
| string[]
| string
| number
| number[];
export type ValidationResults = (
| {
result: boolean;
message: string | null;
name: string;
rule: FormBuilderGenericValidationRule["name"];
}
| ValidationResults
)[];
export type ValidationResult = {
result: boolean;
message: string | null;
name: string;
rule: FormBuilderGenericValidationRule["name"];
};
export type FormBuilderState = {
errors?: ValidationResult[];
isValid: boolean;
isChanged: boolean;
};
export type FormBuilderSize = "medium" | "small";
export type FormBuilderVariant = "curved" | "round" | "block";
export type FormBuilderCategory = "fill" | "outline" | "transparent";
export type FormBuilderGap = "large" | "medium" | "small" | "x-small";