UNPKG

@adaptabletools/adaptable

Version:

Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

366 lines (365 loc) 15 kB
import * as React from 'react'; import { AdaptableButton } from './AdaptableButton'; import { BaseContext } from '../../types'; /** * Data which appears in an AdapTable Form. * * The default shape is a loosely-typed `Record<string, any>`, but consumers * who care about strong typing can declare their own shape and pass it as * the second generic parameter to {@link AdaptableForm}. */ export type AdaptableFormData = Record<string, any>; /** * Defines a form which appears dynamically; used by Alerts, Export Custom * Destinations and Dashboard Custom Toolbars. * * @typeParam T - The host's button/handler context (e.g. * `CustomToolbarFormContext`). * @typeParam TData - Optional shape of the form data. Defaults to the * loosely-typed {@link AdaptableFormData}; declare your * own shape (e.g. `{ name: string; age: number }`) for * strongly-typed `formData` in `onSubmit` callbacks. */ export interface AdaptableForm<T extends BaseContext, TData extends AdaptableFormData = AdaptableFormData> { /** * Title to appear in the Form */ title?: string; /** * Additional information to appear in the Form */ description?: string; /** * Collection of Dynamic Fields and Field Groups to display. * * Items can be: * - a single {@link AdaptableFormField} (rendered on its own row in the * default `rows` layout, or as one cell in the `inline` layout), * - an array of {@link AdaptableFormField} (rendered side-by-side on the * same row in the `rows` layout), or * - an {@link AdaptableFormFieldGroup} (a labelled section that * visually groups related fields). */ fields?: (AdaptableFormField | AdaptableFormField[] | AdaptableFormFieldGroup)[]; /** * Buttons to include in the Form */ buttons?: AdaptableButton<T>[]; /** * How the form's fields are arranged on screen. * * - `rows` (default): each field on its own row, label on the left and * input on the right. Suitable for popups / wizards. * - `inline`: fields are placed side-by-side on a single horizontal line, * with the label rendered immediately before its input. Designed for * compact contexts such as Dashboard Custom Toolbars where vertical * real-estate is scarce. * * @defaultValue 'rows' */ layout?: AdaptableFormLayout; /** * Optional form-level submit hook. * * Fired when the user presses `Enter` while focus is inside any field * input AND the form is currently valid. The full `formData` is passed * through, typed as `TData` if you've supplied a custom shape. * * Use this as an ergonomic shortcut to avoid wiring an explicit "Submit" * button - or in addition to one, so power users can press Enter to * commit. If the form is invalid the hook is not invoked. */ onSubmit?: (formData: TData, context: T) => void; } /** * How an AdaptableForm's fields are visually arranged */ export type AdaptableFormLayout = 'rows' | 'inline'; /** * Logical grouping of related fields, with an optional title and * description. Use to break long forms into visually distinct sections. * * Groups behave like fields when it comes to `hidden`: a hidden group is * not rendered and its child fields are excluded from validation. They * are otherwise transparent - each child field continues to drive its * own value, validation, and `onValueChange` lifecycle. * * In the `inline` layout the group's title/description are not rendered * (the layout is too compact for sectioning). The child fields are * laid out inline alongside the rest. */ export interface AdaptableFormFieldGroup { /** * Discriminator - identifies the item as a group rather than a field. */ kind: 'group'; /** * Optional title rendered as the section header. */ title?: string; /** * Optional description rendered immediately below the title. */ description?: string; /** * Fields contained in the group. Inner items may be a single field or * an array of fields (rendered side-by-side on the same row, exactly * like the top-level shorthand). */ fields: (AdaptableFormField | AdaptableFormField[])[]; /** * Hide the entire group. Either a boolean or a function evaluated * against the current form data. Hidden groups skip rendering and * exclude their children from validation. */ hidden?: boolean | ((formData: AdaptableFormData, context: BaseContext) => boolean); } /** * Defines a Field that appears in an Adaptable Form */ export interface AdaptableFormField { /** * Name of the Field */ name: string; /** * Label to display in the Field */ label: string; /** * Field Type - dictates which UI control is rendered */ fieldType: AdaptableFormFieldType; /** * Field Default Value - can be of type string, boolean, number, or for * `select` fields with `multi: true` an array of those. * * For single `select` fields, this is also the value restored when the user * clears the combobox (unless {@link clearToDefault} is `false`). */ defaultValue?: string | boolean | number | Array<string | number | boolean>; /** * For single `select` fields only. When the user clears the combobox, * whether to restore {@link defaultValue} instead of leaving the field empty. * * Defaults to `true` when `defaultValue` is set, otherwise `false`. * Set to `false` when an empty selection is a distinct state from the default. */ clearToDefault?: boolean; /** * Items to populate the `select` and `radio` fieldTypes. * * Either a static array, or a function that derives the options from the * current form data and Adaptable context. The function form may return * a Promise for asynchronously-loaded options - the form will render the * field with no items until the promise resolves. */ options?: AdaptableFormFieldOption[] | ((formData: AdaptableFormData, context: BaseContext) => AdaptableFormFieldOption[] | Promise<AdaptableFormFieldOption[]>); /** * For `select` fields only. When `true` the field renders as a * multi-select combobox; the field's value is an array of selected * `option.value`s rather than a single value. * * @defaultValue false */ multi?: boolean; /** * For `custom` fields only. Renders an arbitrary React node as the * field's input. Receives the current value, a `setValue` setter * (controlled), the current form data, the Adaptable context and the * resolved `disabled` state. * * Use this as an escape hatch when none of the built-in `fieldType`s * fit - e.g. to render a star-rating widget, a tag editor or any * bespoke control. */ render?: (params: AdaptableFormFieldRenderParams) => React.ReactNode; /** * Placeholder text shown inside `text`, `textarea`, `number`, `date`, * `time` and `datetime` inputs when empty. For `select` fields it is * rendered as the empty-state label when no value is selected. * * When omitted on a `select` field with a {@link defaultValue}, the label of * the matching `options` entry is used as the empty-state label. */ placeholder?: string; /** * Inline help text rendered immediately below the field's input. Useful * for short explanations such as "format: YYYY-MM-DD" or "min 3 chars". */ helpText?: string; /** * Tooltip shown when hovering the field's label. */ tooltip?: string; /** * Hide the field. Either a boolean or a function evaluated against the * current form data. Hidden fields are not rendered and are excluded from * validation. */ hidden?: boolean | ((formData: AdaptableFormData, context: BaseContext) => boolean); /** * Disable the field's input. Either a boolean or a function evaluated * against the current form data. Disabled fields render but the user * cannot edit them. */ disabled?: boolean | ((formData: AdaptableFormData, context: BaseContext) => boolean); /** * If `true` the field is treated as required. An empty value (`''`, * `null`, `undefined`, or unchecked checkbox) will produce a validation * error. */ required?: boolean; /** * Custom field-level validation. Return an error message string to mark * the field invalid, or `null`/`undefined` if the value is valid. * * Custom validation runs *after* built-in checks (`required`, `min`, * `max`, `pattern`, etc.) - the first failing check wins. */ validate?: (value: any, formData: AdaptableFormData, context: BaseContext) => string | null | undefined; /** * Minimum allowed value. For `number` and `slider`: the lowest accepted * number. For `date`, `time` and `datetime`: the earliest allowed value * in ISO format (`YYYY-MM-DD` / `HH:mm` / `YYYY-MM-DDTHH:mm`). */ min?: number | string; /** * Maximum allowed value. For `number` and `slider`: the highest accepted * number. For `date`, `time` and `datetime`: the latest allowed value in * ISO format. */ max?: number | string; /** * Stepping interval for `number`, `slider`, `time` and `datetime` * fields. */ step?: number; /** * Minimum length for `text` and `textarea` fields. */ minLength?: number; /** * Maximum length for `text` and `textarea` fields. */ maxLength?: number; /** * Regular expression that the value of a `text` field must match. */ pattern?: string; /** * For `textarea` fields: the visible number of text rows. * * @defaultValue 3 */ rows?: number; /** * Optional callback invoked whenever value of this field changes */ onValueChange?: (value: any, context: BaseContext) => void; } /** * Map of validation errors produced by {@link validateAdaptableForm}, * keyed by field `name`. A field is valid when its key is not present. */ export type AdaptableFormErrors = Record<string, string>; /** * Types of Controls used in an AdapTable Form (standard form set) */ export type AdaptableFormFieldType = 'text' | 'textarea' | 'select' | 'radio' | 'date' | 'time' | 'datetime' | 'number' | 'slider' | 'color' | 'checkbox' | 'textOutput' | 'custom'; /** * A single option used by a `select` or `radio` field. */ export interface AdaptableFormFieldOption { value: any; label: string; } /** * Parameters provided to {@link AdaptableFormField.render} when rendering * a `custom` field type. */ export interface AdaptableFormFieldRenderParams { /** * The field's current value */ value: any; /** * Setter to update the field's value. Triggers form-level `onChange`, * per-field `onValueChange` and re-validation. */ setValue: (newValue: any) => void; /** * The field definition itself - useful when sharing one render function * across several `custom` fields. */ field: AdaptableFormField; /** * The current values of all fields in the form, keyed by field `name`. */ formData: AdaptableFormData; /** * Adaptable context (carries `adaptableApi`, etc.). When the form is * hosted by a Custom Toolbar this is in fact a * `CustomToolbarFormContext`. */ context: BaseContext; /** * Resolved disabled state of the field (after evaluating `field.disabled` * if it's a function). */ disabled: boolean; /** * Current validation error for this field, if any. */ error?: string; } /** * Returns true if the supplied entry from a form's `fields` array is a * group rather than a single field or an inline-row array of fields. */ export declare function isAdaptableFormFieldGroup(entry: AdaptableFormField | AdaptableFormField[] | AdaptableFormFieldGroup): entry is AdaptableFormFieldGroup; /** * Flattens a form's `fields` array (which may contain field groups and * inline-row arrays) into a single flat list of fields. Useful when * computing defaults, validation or per-field lookups. */ export declare function flattenAdaptableFormFields<T extends BaseContext>(formDef?: AdaptableForm<T, any>): AdaptableFormField[]; export declare function shouldClearSelectToDefault(field: AdaptableFormField): boolean; export declare function resolveSelectValueAfterClear(field: AdaptableFormField, newValue: unknown): unknown; export declare function resolveSelectPlaceholder(field: AdaptableFormField, options: AdaptableFormFieldOption[]): string | undefined; export declare function getDefaultAdaptableFormData<T extends BaseContext = BaseContext>(formDef?: AdaptableForm<T, any>): AdaptableFormData; /** * Resolves a field's `options` to the current array of options. * * - When `options` is already an array, it's returned as-is. * - When it's a synchronous function, the function is invoked. * - When the function returns a Promise this helper returns `undefined` - * asynchronous resolution is the caller's responsibility (the * `AdaptableFormComponent` resolves promises via internal state). */ export declare function resolveAdaptableFormFieldOptionsSync(field: AdaptableFormField, formData: AdaptableFormData, context: BaseContext): AdaptableFormFieldOption[] | undefined; /** * Returns true if the given field should be hidden given the current form * data and context. Resolves both boolean and function forms of `hidden`. */ export declare function isAdaptableFormFieldHidden(field: AdaptableFormField, formData: AdaptableFormData, context: BaseContext): boolean; /** * Returns true if the given group should be hidden given the current * form data and context. */ export declare function isAdaptableFormFieldGroupHidden(group: AdaptableFormFieldGroup, formData: AdaptableFormData, context: BaseContext): boolean; /** * Returns true if the given field should be disabled given the current * form data and context. Resolves both boolean and function forms of * `disabled`. */ export declare function isAdaptableFormFieldDisabled(field: AdaptableFormField, formData: AdaptableFormData, context: BaseContext): boolean; /** * Validates an entire AdaptableForm. Hidden fields and fields inside * hidden groups are skipped. Returns a map of field-name to error * message; fields without entries are valid. * * Validation order per field: `required` -> built-in (min/max/length/ * pattern) -> custom `validate`. The first failing check wins. */ export declare function validateAdaptableForm<T extends BaseContext = BaseContext>(formDef: AdaptableForm<T, any>, formData: AdaptableFormData, context: BaseContext): AdaptableFormErrors;