@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
414 lines (413 loc) • 19.7 kB
TypeScript
import type { AriaAttributes } from 'react';
import type { SpacingProps } from '../../components/space/types';
import type { ContextState, DataPathHandlerParameters, EventListenerCall, FieldInternalsValue, FilterData, TransformData, VisibleDataOptions } from './DataContext';
import type { SharedFieldBlockProps } from './FieldBlock';
import type { JSONSchema4, JSONSchema6, JSONSchema7 } from 'json-schema';
import type { JSONSchemaType } from 'ajv/dist/2020';
import { JsonObject, FormError } from './utils';
import { FormsTranslationFlat, FormsTranslationLocale } from './hooks/useTranslation';
import { GetValueByPath } from './hooks/useDataValue';
import { HelpProps } from '../../components/help-button/HelpButtonInline';
export type * from 'json-schema';
export type JSONSchema = JSONSchema7;
export type AllJSONSchemaVersionsBasis<DataType> = JSONSchema4 | JSONSchema6 | JSONSchema7 | JSONSchemaType<DataType>;
export type AllJSONSchemaVersions<DataType = unknown> = AllJSONSchemaVersionsBasis<DataType> | (Omit<AllJSONSchemaVersionsBasis<DataType>, 'required'> & {
required?: readonly string[];
});
export { JSONSchemaType };
export type ValidatorReturnSync<Value> = Error | FormError | string | React.ReactElement | undefined | void | Array<Validator<Value>> | Array<Error | FormError>;
export type ValidatorReturnAsync<Value> = ValidatorReturnSync<Value> | Promise<ValidatorReturnSync<Value>>;
export type Validator<Value, ErrorMessages = DefaultErrorMessages> = (value: Value, additionalArgs: ReceiveAdditionalEventArgs<Value, ErrorMessages>) => ValidatorReturnAsync<Value>;
export type ReceiveAdditionalEventArgs<Value, ErrorMessages = DefaultErrorMessages> = {
/**
* Returns the error messages from the { errorMessages } object.
*/
errorMessages: ErrorMessages;
/**
* Connects the validator to another field.
* This allows you to rerun the validator function once the value of the connected field changes.
*/
connectWithPath: (path: Path) => {
getValue: () => Value;
};
/**
* Connects the validator to another field within an Iterate.Array.
* This allows you to rerun the validator function once the value of the connected field changes.
*/
connectWithItemPath: (path: Path) => {
getValue: () => Value;
};
/**
* Returns the value of the given path.
*/
getValueByPath: GetValueByPath<Value>;
/**
* Returns the value of the given path or the source value.
*/
getSourceValue: GetValueByPath<Value>;
/**
* Used internally to connect a field event listener to a path.
*/
setFieldEventListener: (path: Path, type: EventListenerCall['type'], callback: EventListenerCall['callback']) => void;
/**
* Returns the validators from the { exportValidators } object.
*/
validators: Record<string, Validator<Value>> | undefined;
/**
* The props passed to the Field component.
*/
props: UseFieldProps<Value>;
/**
* The internal data context.
*/
dataContext: ContextState;
} & {
/** @deprecated use the error messages from the { errorMessages } object instead. */
pattern?: string;
/** @deprecated use the error messages from the { errorMessages } object instead. */
required?: string;
};
export type ValidatorDisableable<Value> = Validator<Value> | false;
/**
* Accept any key, so custom message keys can be used
* including the path to the field the message is for
*/
export type GlobalErrorMessagesWithPaths = VariousErrorMessages | {
[K in `/${string}`]?: VariousErrorMessages;
};
/**
* 'MyCustom.message': 'Your custom message'
*/
export type DotNotationErrorMessages = Record<`${string}` | `${string}.${string}`, string | React.ReactElement>;
/**
* { 'nb-NO': { 'Field.errorRequired': 'Dette feltet er påkrevd' } }
*/
export type ErrorMessagesWithLocaleSupport = Record<FormsTranslationLocale, DefaultErrorMessages>;
export type InternalErrorMessages = Record<Exclude<FormsTranslationFlat, undefined>, string>;
export type DefaultErrorMessages = Partial<InternalErrorMessages> & Partial<DotNotationErrorMessages> & Partial<DeprecatedErrorMessages>;
export type VariousErrorMessages = DefaultErrorMessages | ErrorMessagesWithLocaleSupport;
export type DeprecatedErrorMessages = {
/**
* @deprecated Use translation keys as the message instead of this parameter (e.g. Field.errorRequired)
*/
required?: string;
/**
* @deprecated Use translation keys as the message instead of this parameter (e.g. Field.errorPattern)
*/
pattern?: string;
/**
* @deprecated use StringField.errorMinLength instead
*/
minLength?: string;
/**
* @deprecated use StringField.errorMaxLength instead
*/
maxLength?: string;
/**
* @deprecated use NumberField.errorMinimum instead
*/
minimum?: string;
/**
* @deprecated use NumberField.errorMaximum instead
*/
maximum?: string;
/**
* @deprecated use NumberField.errorExclusiveMinimum instead
*/
exclusiveMinimum?: string;
/**
* @deprecated use NumberField.errorExclusiveMaximum instead
*/
exclusiveMaximum?: string;
/**
* @deprecated use NumberField.errorMultipleOf instead
*/
multipleOf?: string;
};
export interface DataValueReadProps<Value = unknown> {
/** JSON Pointer for where the data for this field is located in the source dataset */
path?: Path;
/** JSON Pointer for where the data for this field is located in the source iterate loop element */
itemPath?: Path;
/** Source data value for the field. Will take precedence over the path value given in the data context */
value?: Value;
/** Default source data value for the field. Will not take precedence over the path value given in the data context */
defaultValue?: Value;
}
export declare function pickDataValueReadProps<Props extends DataValueReadProps>(props: Props): DataValueReadProps;
export declare function omitDataValueReadProps<Props extends DataValueReadProps>(props: Props): Omit<DataValueReadProps, keyof DataValueReadProps>;
type EventArgs<Value, ExtraValue extends ProvideAdditionalEventArgs> = [
value: Value,
additionalArgs?: ExtraValue & ReceiveAdditionalEventArgs<Value>
];
export interface DataValueWriteProps<Value = unknown, EmptyValue = undefined | unknown, ExtraValue extends ProvideAdditionalEventArgs = ProvideAdditionalEventArgs> {
emptyValue?: EmptyValue;
onFocus?: (...args: EventArgs<Value | EmptyValue, ExtraValue>) => void;
onBlur?: (...args: EventArgs<Value | EmptyValue, ExtraValue>) => void;
onChange?: (...args: EventArgs<Value | EmptyValue, ExtraValue>) => OnChangeReturnType;
}
export declare function pickDataValueWriteProps<Props extends DataValueWriteProps>(props: Props): DataValueWriteProps;
export declare function omitDataValueWriteProps<Props extends DataValueWriteProps>(props: Props): Omit<DataValueWriteProps, keyof DataValueWriteProps>;
export type DataValueReadWriteProps<Value = unknown, EmptyValue = undefined | unknown> = DataValueReadProps<Value> & DataValueWriteProps<Value, EmptyValue>;
export declare function pickDataValueReadWriteProps<Props extends DataValueReadWriteProps>(props: Props): DataValueReadWriteProps;
export declare function omitDataValueReadWriteProps<Props extends DataValueReadWriteProps>(props: Props): Omit<DataValueReadWriteProps, keyof DataValueReadWriteProps>;
export type ComponentProps = SpacingProps & {
className?: string;
};
export type ProvideAdditionalEventArgs = Record<string, unknown>;
export type DataValueReadComponentProps<Value = unknown> = ComponentProps & DataValueReadProps<Value>;
export type DataValueReadWriteComponentProps<Value = unknown, EmptyValue = undefined | unknown> = ComponentProps & DataValueReadProps<Value> & DataValueWriteProps<Value, EmptyValue>;
export type MessagePropParams<Value, ReturnValue> = {
conditionally: (callback: () => ReturnValue | void, options?: {
showInitially?: boolean;
}) => ReturnValue;
getValueByPath: GetValueByPath<Value>;
getFieldByPath: (path: Path) => FieldInternalsValue;
};
export type MessageProp<Value, ReturnValue> = ReturnValue | ((value: Value, options: MessagePropParams<Value, ReturnValue>) => ReturnValue | undefined);
export type MessageTypes<Value> = UseFieldProps<Value>['info'] | UseFieldProps<Value>['warning'] | UseFieldProps<Value>['error'];
export type ConnectorProps<Value = unknown> = Pick<UseFieldProps<Value>, 'onChange' | 'onBlurValidator'>;
export type InfoProp<Value> = MessageProp<Value, React.ReactNode | Array<React.ReactNode>>;
export type WarningProp<Value> = MessageProp<Value, React.ReactNode | Array<React.ReactNode>>;
export type ErrorProp<Value> = MessageProp<Value, string | React.ReactElement | Error | FormError | Array<string | React.ReactElement | Error | FormError>>;
export interface UseFieldProps<Value = unknown, EmptyValue = undefined | unknown, ErrorMessages extends DefaultErrorMessages = DefaultErrorMessages> extends DataValueReadWriteComponentProps<Value, EmptyValue>, AriaAttributes {
/**
* ID added to the actual field component, and linked to the label via for-attribute
*/
id?: Identifier;
name?: string;
disabled?: boolean;
readOnly?: boolean;
autoComplete?: HTMLInputElement['autocomplete'] | HTMLTextAreaElement['autocomplete'];
/**
* Text showing in place of the value if no value is given
*/
placeholder?: React.ReactNode;
/**
* NB: Undocumented for now.
* Forwards all possible props to the underlying component.
*/
htmlAttributes?: Record<string, unknown>;
/**
* NB: Undocumented for now.
* Forwards all given props in a props object.
*/
props?: Record<string, unknown>;
info?: InfoProp<Value>;
warning?: WarningProp<Value>;
error?: ErrorProp<Value>;
required?: boolean;
schema?: AllJSONSchemaVersions<Value>;
/** @deprecated Use `onChangeValidator` instead */
validator?: Validator<Value>;
onChangeValidator?: Validator<Value>;
onBlurValidator?: Validator<Value>;
exportValidators?: Record<string, Validator<Value>>;
validateRequired?: (internal: Value, { emptyValue, required, isChanged, error, }: {
emptyValue: EmptyValue;
required: boolean;
isChanged: boolean;
error: FormError | undefined;
}) => FormError | undefined;
/**
* Should error messages based on validation be shown initially (from given value-prop or source data)
* before the user interacts with the field?
* @default false
*/
validateInitially?: boolean;
/**
* Should error messages be shown when touching (like focusing a field and blurring) without having changed
* the value? So the user did not introduce a new error, but it was invalid based on validation initially.
*/
validateUnchanged?: boolean;
/**
* Should validation be done while writing, not just when blurring the field?
*/
/**
* @deprecated – Replaced with validateContinuously, continuousValidation can be removed in v11.
*/
continuousValidation?: boolean;
/**
* Should validation be done while writing, not just when blurring the field?
*/
validateContinuously?: boolean;
/**
* Provide custom error messages for the field
*/
errorMessages?: ErrorMessages;
/**
* Transforms the `value` before it's displayed in the field (e.g. input).
* Public API. Should not be used internally.
*/
transformIn?: (external: unknown) => Value;
/**
* Transforms the value before it gets forwarded to the form data object or returned as the onChange value parameter.
* Public API. Should not be used internally.
*/
transformOut?: (internal: Value, additionalArgs?: unknown) => unknown;
/**
* Transforms the value given by `handleChange` after `fromInput` and before `updateValue` and `toEvent`. The second parameter returns the current value.
*/
transformValue?: (value: Value, currentValue?: Value) => Value;
/**
* Transform additionalArgs or generate it based on `value`.
*/
provideAdditionalArgs?: (value: Value, additionalArgs?: ProvideAdditionalEventArgs) => ProvideAdditionalEventArgs;
/**
* Transforms the value before it gets returned as the `value`.
*/
toInput?: (external: Value | unknown) => Value | unknown;
/**
* Transforms the internal value before it gets returned by even callbacks such as `onChange`, `onFocus` and `onBlur`. The second parameter returns the event type: `onChange`, `onFocus`, `onBlur` or `onBlurValidator`.
*/
toEvent?: (internal: Value, type: 'onChange' | 'onFocus' | 'onBlur' | 'onBlurValidator') => Value;
/**
* Transforms the value given by `handleChange` before it is used in the further process flow. Use it to destruct the value from the original event object.
*/
fromInput?: (external: Value | unknown) => Value;
/**
* Transforms the given props `value` before any other step gets entered.
*/
fromExternal?: (external: Value) => Value;
/**
* For internal use only.
*/
valueType?: string | number | boolean | Array<string | number | boolean>;
}
export type FieldProps<Value = unknown, EmptyValue = undefined | unknown, ErrorMessages extends DefaultErrorMessages = DefaultErrorMessages> = UseFieldProps<Value, EmptyValue, ErrorMessages> & SharedFieldBlockProps;
export type FieldPropsGeneric<Value = unknown, EmptyValue = undefined | unknown, ErrorMessages extends DefaultErrorMessages = DefaultErrorMessages> = Omit<FieldProps<Value, EmptyValue, ErrorMessages>, keyof DataValueWriteProps> & DataValueWriteProps<Value, EmptyValue, ProvideAdditionalEventArgs>;
export type FieldPropsWithExtraValue<Value = unknown, ExtraValue extends ProvideAdditionalEventArgs = ProvideAdditionalEventArgs, EmptyValue = undefined | unknown, ErrorMessages extends DefaultErrorMessages = DefaultErrorMessages> = Omit<FieldProps<Value, EmptyValue, ErrorMessages>, keyof DataValueWriteProps> & DataValueWriteProps<Value, EmptyValue, ExtraValue>;
export interface ValueProps<Value = unknown> extends DataValueReadComponentProps<Value> {
/**
* Field label to show above the data value.
*/
label?: React.ReactNode;
/** Use `true` to make the label only readable by screen readers. */
labelSrOnly?: boolean;
/**
* Use `true` to inherit the label from a visible (rendered) field with the same path.
*/
inheritLabel?: boolean;
/**
* Use `true` to inherit the visibility from a field with the same path.
*/
inheritVisibility?: boolean;
/**
* Shows the value even if it is empty.
*/
showEmpty?: boolean;
/**
* Text showing in place of the value if no value is given.
*/
placeholder?: React.ReactNode;
/**
* For showing the value inline (not as a block element)
*/
inline?: boolean;
/** The max-width of a value block. Defaults to large */
maxWidth?: 'small' | 'medium' | 'large' | 'auto';
/**
* Provide help content for the value.
*/
help?: HelpProps;
/**
* Transforms the label before it gets displayed. Receives the label as the first parameter. The second parameter is a object containing the `convertJsxToString` function.
*/
transformLabel?: (label: React.ReactNode, convertJsxToString: (label: React.ReactNode) => string) => React.ReactNode;
/**
* Transforms the `value` before it's displayed in the field (e.g. input).
* Public API. Should not be used internally.
*/
transformIn?: (external: Value | unknown) => Value | unknown;
/**
* Transforms the value before it gets returned as the `value`.
*/
toInput?: (external: Value | unknown) => Value | unknown;
/**
* Transforms the given props `value` before any other step gets entered.
*/
fromExternal?: (external: Value) => Value;
}
export type Path = string;
export type PathStrict = `/${string}`;
export type Identifier = string;
export type SubmitState = 'pending' | 'complete' | 'success' | 'error' | 'abort';
/**
* Provide a error that shows in the FormStatus of a field.
*/
type EventStateObjectError = Error;
/**
* Provide a warning that shows in the FormStatus of a field.
*/
type EventStateObjectWarning = React.ReactNode;
/**
* Provide an info that shows in the FormStatus of a field.
*/
type EventStateObjectInfo = React.ReactNode;
/**
* Provide a status that will enforce the form to stay in pending state
*/
type EventStateObjectStatus = 'pending';
/**
* Provide a success state that will show an indicator on the related field label
*/
type EventStateObjectSuccess = 'saved';
/**
* Provide an error or status messages that shows in the FormStatus of a field
*/
export type EventStateObjectOr = {
error?: EventStateObjectError;
warning?: EventStateObjectWarning;
info?: EventStateObjectInfo;
pending?: EventStateObjectStatus;
customStatus?: unknown;
};
export type EventStateObjectEitherOr = {
error: EventStateObjectError;
} | {
warning: EventStateObjectWarning;
} | {
info: EventStateObjectInfo;
} | {
status: EventStateObjectStatus;
} | {
customStatus: unknown;
};
export type EventStateObject = EventStateObjectOr & EventStateObjectEitherOr;
/**
* Provide 'saved' to indicate the data has been saved successfully. Cannot be combined with `error`.
*/
export type EventStateObjectWithSuccess = EventStateObjectOr & {
success?: EventStateObjectSuccess;
} & (EventStateObjectEitherOr | {
success: EventStateObjectSuccess;
});
/**
* Provide an error or status messages that shows in the FormStatus of a field
*/
export type EventReturnWithStateObject = Error | EventStateObject;
export type EventReturnWithStateObjectAndSuccess = Error | EventStateObjectWithSuccess;
export type OnSubmitParams<Data = JsonObject> = {
/** Will remove data entries of fields that are not visible */
reduceToVisibleFields: (data: Data, options?: VisibleDataOptions) => Partial<Data>;
/** Will call the given function for each data path. The returned `value` will replace each data entry. It's up to you to define the shape of the value. */
transformData: (data: Data, handler: TransformData) => Partial<Data>;
/** Will filter data based on the given "filterDataHandler" method */
filterData: (filterDataHandler: FilterData) => Partial<Data>;
/** Will remove browser-side stored autocomplete data */
resetForm: () => void;
/** Will empty the whole internal data set of the form */
clearData: () => void;
};
export type OnSubmitReturn = EventReturnWithStateObject | void | Promise<EventReturnWithStateObject | void>;
export type OnSubmit<Data = JsonObject> = (data: Data, { reduceToVisibleFields, transformData, filterData, resetForm, clearData, }: OnSubmitParams) => OnSubmitReturn;
export type OnSubmitRequest = ({ getErrors, }: {
getErrors: () => Array<DataPathHandlerParameters>;
}) => void;
export type OnCommit<Data = JsonObject> = (data: Data, { clearData, preventCommit, }: {
clearData: () => void;
preventCommit?: () => void;
}) => EventReturnWithStateObject | void | Promise<EventReturnWithStateObject | void>;
export type OnChange<Data = JsonObject> = (data: Data, additionalArgs: Pick<OnSubmitParams, 'filterData'>) => OnChangeReturnType;
type OnChangeReturnType = EventReturnWithStateObjectAndSuccess | void | Promise<EventReturnWithStateObjectAndSuccess | void>;
export type CountryCode = PathStrict | `${Uppercase<string>}${Uppercase<string>}`;