import type { FieldDefAddress, FieldDefAddressSingle } from "./FormFieldAddress"; import type { FieldDefAdvancedSelection } from "./FormFieldAdvancedSelection"; import type { FieldDefCheckbox } from "./FormFieldCheckbox"; import type { FieldDefChip } from "./FormFieldChips"; import type { FieldDefCode } from "./FormFieldCode/FormFieldCodeTypes"; import type { FieldDefColor } from "./FormFieldColor/FormFieldColorTypes"; import type { FieldDefDate } from "./FormFieldDate"; import type { FieldDefTime } from "./FormFieldTime/TimeField"; import type { FieldDefDropdown } from "./FormFieldDropdown"; import type { FieldDefMapCoordinates } from "./FormFieldMapCoordinates"; import type { FieldDefMatrix } from "./FormFieldMatrix"; import type { FieldDefNumber } from "./FormFieldNumber"; import type { FieldDefNumberTable } from "./FormFieldNumberTable"; import type { FieldDefPhoneSelection } from "./FormFieldPhone"; import type { FieldDefRadio } from "./FormFieldRadio"; import type { FieldDefRaw } from "./FormFieldRaw"; import type { FieldDefText } from "./FormFieldText"; import type { FieldDefTextEditor } from "./FormFieldTextEditor/FormFieldTextEditorTypes"; import type { FieldDefToggle } from "./FormFieldToggle"; import type { FieldDefUpload } from "./FormFieldUpload"; import type { MosaicToggle } from "../../types"; import type { ElementType, HTMLAttributes, MemoExoticComponent, MutableRefObject, ReactNode } from "react"; import type { ExternalToInternalValue, FormSpacing, InternalToExternalValue } from "../Form"; import type { FieldPath, FormMethods, FormState, Validator } from "../Form/useForm/types"; import type { FieldDefGroup } from "./FormFieldGroup/FormFieldGroupTypes"; export interface MosaicFieldProps { /** * Field identifier that matches the field name. */ id?: string; /** * Object that contains all the properties from the current field defined * by the developer. */ fieldDef: FieldDefBase; /** * Function that listens to changes on the field and updates its value. */ onChange?: (value: V | ((current: V) => V), options?: any) => Promise; /** * Function that listens to a blur event on the field and executes an action. */ onBlur?: (e?: any) => Promise; /** * Value written by the user into the text field. */ value?: V; /** * Flag to style text field as erroneous. */ error?: string | boolean; /** * React Element or component to be rendered as child of the field component. */ children?: ReactNode; /** * Number that represents the amount of fields that share the same row. */ colsInRow?: number; /** * Form action dispatcher */ dispatch?: any; /** * Spacing type */ spacing?: FormSpacing; /** * Whether or not the field is disabled */ disabled?: boolean; /** * Methods that can be used to manipulate the form */ methods?: FormMethods; /** * Reference to the field control, i.e. the HTML input, * select or textarea element */ inputRef?: MutableRefObject; /** * Whether or not to display a skeleton representation * of this component */ skeleton?: boolean; /** * For fields with multiple input/controls, we should * not render a label element because they can only target * one control. Instead, render a legend element. */ useRealLabel?: boolean; /** * The path to the field. A path with zero members is a * root field. */ path?: FieldPath; /** * Optional ref that section-based fields assign a flush callback to. * Invoked before submit validation to sync UI-only state into form data. */ flushRef?: MutableRefObject<(() => void) | null>; /** * Owned by the form system, not a FieldDef consumer prop. Derived in * Field from the field definition `id` or `name` plus React `useId`, * and only set when instruction text is rendered inline. Field components * should apply it as aria-describedby on their interactive controls. */ instructionTextId?: string; } export interface FieldDefBase { /** * Significant name related to its field. */ name: string; /** * React ref for the field */ ref?: MutableRefObject; /** * Label that will sit on top of the field. */ label: string; /** * Whether or not to display the label to the user. The label * will still be used for the aria-label attribute on the * associated control, if applicable. */ hideLabel?: boolean; /** * Marks field as required */ required?: boolean | { validator: boolean; asterisk: boolean; }; /** * Text to help the user fill the current field. */ helperText?: string | JSX.Element; /** * Instructions about how to fill the current field. */ instructionText?: string; /** * If instruction text is provided, force it to be displayed * in the form of a tooltip rather than alongside the field, * even when the horizontal space is available. */ forceInstructionTooltip?: boolean; /** * Indicates whether the field can be written on or readonly. */ disabled?: MosaicToggle; /** * Settings that belong to a specific field. * They are defined within each field implementation. */ inputSettings?: T; /** * Defined between 100, 280, 450, and 620 px. */ size?: string; /** * Allows additional styling to the current field via className. */ className?: HTMLAttributes["className"]; /** * Allows additional styling to the current field via style object. */ style?: HTMLAttributes["style"]; /** * Defines the type of component from a list of components * found on Col.tsx. This also allows for a custom component type. */ type: Type; /** * Array of validators to be executed by the form when on blur or * when submitted. */ validators?: (((...args: any[]) => string | undefined | JSX.Element | Promise) | string | { fn: string; options: any; })[]; /** * When to validate the field */ validateOn?: FieldValidateOn; /** * An array of other field names to validate when * this one gets validated */ validates?: (string | { name: string; include: Validator["fn"][]; })[]; /** * Identifier passed by the developer */ id?: string; /** * Callback executed when the current fields has changed */ onBlurCb?: (value?: any) => void; /** * Callback executed when the current fields has changed */ onChangeCb?: (value?: any) => void | Promise; /** * Whether or not to show this field */ show?: MosaicToggle; /** * How to transform a field's value into an internal value * that will be consumed by the field component. By default, * no transformation will be applied and it'll result in the * same value. */ externalToInternalValue?: ExternalToInternalValue; /** * How to transform a field's internal value into its external * value that will be exposed to the consumer. By default, * no transformation will be applied and it'll result in the * same value. */ internalToExternalValue?: InternalToExternalValue; /** * How to decide whether or not the field has a value */ hasValue?: FieldHasValue; } export type FieldDefCustom = FieldDefBase<((props?: any) => JSX.Element) | MemoExoticComponent<(props?: any) => JSX.Element>>; export type FieldDef = FieldDefText | FieldDefToggle | FieldDefTextEditor | FieldDefRadio | FieldDefPhoneSelection | FieldDefMatrix | FieldDefMapCoordinates | FieldDefDropdown | FieldDefDate | FieldDefTime | FieldDefColor | FieldDefCode | FieldDefChip | FieldDefCheckbox | FieldDefAdvancedSelection | FieldDefAddress | FieldDefAddressSingle | FieldDefUpload | FieldDefCustom | FieldDefNumber | FieldDefNumberTable | FieldDefRaw | FieldDefGroup; export type FieldObj = Omit & { externalToInternalValue: (value: any) => any; internalToExternalValue: (value: any) => any; order: number; fields?: Record; hasValue: FieldHasValue; required?: Exclude; }; export type FieldDefSanitized = FieldDef; export type FieldValidateOn = "onBlur" | "onChange" | "onBlurAmend" | "onBlurChange" | "onSubmit"; export type FieldHasValue = ({ value, internalValue }: { value: any; internalValue: any; }) => boolean; export interface FieldConfig { Component: ElementType; validate: FieldValidateOn; externalToInternalValue: ExternalToInternalValue; internalToExternalValue: InternalToExternalValue; hasValue: FieldHasValue; /** * When true, the field remounts when the form's `inputRevision` increments * (e.g. on reset or `setFormValues({ resetInputs: true })`). Used by * section-based MUI date/time pickers to clear partially filled input. */ needsInputReset?: boolean; }