@mmstack/form-adapters
Version:
Provides a collection of **headless, reusable state adapters** for common form field types. Built upon [@mmstack/form-core](https://www.npmjs.com/package/@mmstack/form-core) and integrating with [@mmstack/form-validation](https://www.npmjs.com/package/@mm
934 lines (927 loc) • 115 kB
TypeScript
import * as _angular_core from '@angular/core';
import { Signal, WritableSignal } from '@angular/core';
import { FormControlSignal, CreateFormControlOptions, DerivedSignal, CreateFormGroupOptions, FormGroupSignal } from '@mmstack/form-core';
import { DerivedSignal as DerivedSignal$1 } from '@mmstack/primitives';
import { DateValidatorOptions, DateRange, NumberValidatorOptions, ArrayValidatorOptions, StringValidatorOptions } from '@mmstack/form-validation';
import { HttpResourceRequest } from '@angular/common/http';
import { Validator } from '@angular/forms';
/**
* Represents the reactive state for a boolean form control (e.g., checkbox).
* Extends the base `FormControlSignal<boolean>` and includes a `type` discriminator.
* Intended for use with checkbox-like UI elements. For toggle switches, see `ToggleState`.
*
* @template TParent The type of the parent form group's value, if applicable.
* @see ToggleState
*/
type BooleanState<TParent = undefined> = FormControlSignal<boolean, TParent> & {
/** signal for error tooltip, default is shortened when error is longer than 40 chars */
errorTooltip: Signal<string>;
/** signal for hint tooltip, default is shortened when hint is longer than 40 chars */
hintTooltip: Signal<string>;
/** Type discriminator for boolean controls. */
type: 'boolean';
};
/**
* Configuration options for creating a `BooleanState`, used with `createBooleanState`.
*
* Inherits options from `CreateFormControlOptions<boolean>` but omits `required`,
* as boolean "required" validation typically means "must be true", which is handled
* via the `validation` option in `injectCreateBooleanState`.
*
* @see CreateFormControlOptions
* @see injectCreateBooleanState
*/
type BooleanStateOptions = Omit<CreateFormControlOptions<boolean, 'control'>, 'required'> & {
maxErrorHintLength?: () => number;
};
/**
* Creates the reactive state object (`BooleanState`) for a boolean form control
* without relying on Angular's dependency injection for validation setup.
*
* Use this function directly if:
* - You don't need validation or are providing a pre-built `validator` function manually.
* - You are creating state outside of an Angular injection context.
*
* For easier integration with `@mmstack/form-validation`, prefer `injectCreateBooleanState`.
*
* @template TParent The type of the parent form group's value, if applicable.
* @param value The initial boolean value, or a `DerivedSignal` linking it to a parent state.
* @param opt Optional configuration (`BooleanStateOptions`), potentially including a `validator` function.
* @returns A `BooleanState` instance managing the control's reactive state.
* @see injectCreateBooleanState
*/
declare function createBooleanState<TParent = undefined>(value: boolean | DerivedSignal<TParent, boolean>, opt?: BooleanStateOptions): BooleanState<TParent>;
/**
* Configuration options specifically for the factory function returned by
* `injectCreateBooleanState`.
*
* This type is derived from `BooleanStateOptions` but explicitly excludes the
* `validator` property (as validation rules are configured via the `validation`
* property below) and adds the `validation` configuration specific to boolean controls.
*
* @see injectCreateBooleanState
* @see BooleanStateOptions
*/
type InjectedBooleanStateOptions = Omit<BooleanStateOptions, 'validator'> & {
/**
* Optional configuration for boolean-specific validation rules.
* The factory function uses the injected `validators` service based on this configuration.
*/
validation?: () => {
/**
* If `true`, applies the `validators.boolean.mustBeTrue()` validator,
* requiring the control's value to be `true` to be considered valid.
*/
requireTrue?: boolean;
};
};
/**
* Factory function (returned by `injectCreateBooleanState`) that creates `BooleanState`.
* Integrates with `@mmstack/form-validation` via DI to apply validation rules.
*
* @template TParent The type of the parent form group's value, if applicable.
* @param value The initial boolean value, or a `DerivedSignal` linking it to a parent state.
* @param opt Configuration options specific to this injected factory, defined by
* the `InjectedBooleanStateOptions` type, including the `validation` property.
* @returns A `BooleanState` instance managing the control's reactive state.
*/
declare function injectCreateBooleanState(): <TParent = undefined>(value: boolean | DerivedSignal<TParent, boolean>, opt?: InjectedBooleanStateOptions) => BooleanState<TParent>;
/**
* Represents the reactive state for a toggle switch form control (e.g., `mat-slide-toggle`).
*
* This type is functionally equivalent to `BooleanState` but overrides the `type`
* discriminator to `'toggle'` for specific identification if needed.
*
* @template TParent The type of the parent form group's value, if applicable.
* @see BooleanState
*/
type ToggleState<TParent = undefined> = Omit<BooleanState<TParent>, 'type'> & {
/** Type discriminator for toggle switch controls. */
type: 'toggle';
};
/**
* Configuration options for `createToggleState`.
* This is a direct type alias for `BooleanStateOptions`.
*
* @see BooleanStateOptions
* @see createToggleState
*/
type ToggleStateOptions = BooleanStateOptions;
/**
* Configuration options for the factory function returned by `injectCreateToggleState`.
* This is a direct type alias for `InjectedBooleanStateOptions`.
*
* @see InjectedBooleanStateOptions
* @see injectCreateToggleState
*/
type InjectedToggleStateOptions = InjectedBooleanStateOptions;
/**
* Creates the reactive state object (`ToggleState`) for a toggle switch form control
* without relying on Angular's dependency injection for validation setup.
*
* This function wraps `createBooleanState` and simply overrides the `type` property
* to `'toggle'`. Use this function if creating state outside an injection context
* or providing a manual `validator` function via the options.
*
* For easier validation integration (like `requireTrue`), prefer `injectCreateToggleState`.
*
* @template TParent The type of the parent form group's value, if applicable.
* @param value The initial boolean value (`true`/`false`), or a `DerivedSignal` linking it to a parent state.
* @param opt Optional configuration (`ToggleStateOptions`, alias for `BooleanStateOptions`).
* @returns A `ToggleState` object managing the toggle's reactive state.
* @see createBooleanState
* @see injectCreateToggleState
*/
declare function createToggleState<TParent = undefined>(value: boolean | DerivedSignal$1<TParent, boolean>, opt?: ToggleStateOptions): ToggleState<TParent>;
/**
* Creates and returns a factory function for generating `ToggleState` instances.
*
* This factory utilizes Angular's dependency injection by wrapping the factory
* returned from `injectCreateBooleanState`. It simplifies validation integration
* (e.g., setting `requireTrue` via the `validation` option).
*
* This is the **recommended** way to create `ToggleState` when working within
* an Angular injection context, especially if validation is needed.
*
* @returns A factory function: `(value: boolean | DerivedSignal<TParent, boolean>, opt?: InjectedToggleStateOptions) => ToggleState<TParent>`.
* @see injectCreateBooleanState
* @see InjectedToggleStateOptions
* @example
* // Within an Angular injection context (component, service, etc.):
* const createToggle = injectCreateToggleState(); // Get the factory
*
* // Create state for an optional dark mode toggle
* const darkModeState = createToggle(false, { label: () => 'Dark Mode' });
*
* // Create state for a toggle that must be enabled
* const enableAnalyticsState = createToggle(false, {
* label: () => 'Enable Analytics',
* validation: () => ({ requireTrue: true }) // Use validation option
* });
*/
declare function injectCreateToggleState(): <TParent = undefined>(value: boolean | DerivedSignal$1<TParent, boolean>, opt?: InjectedToggleStateOptions) => ToggleState<TParent>;
/**
* Represents the reactive state for a date input form control.
*
* Extends the base `FormControlSignal<TDate | null>` and adds date-specific
* properties like `placeholder` and enhanced `error`/`errorTooltip` signals derived
* from the validation result's `.resolve()` method (when using the injected factory).
*
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
* @template TDate The type used for date values within the control (e.g., `Date`, Luxon `DateTime`, Moment). Defaults to `Date`.
* @see FormControlSignal
*/
type DateState<TParent = undefined, TDate = Date> = FormControlSignal<TDate | null, // Value can be the specific date type or null
TParent> & {
/** Signal holding the input placeholder text (e.g., "YYYY-MM-DD"). */
placeholder: Signal<string>;
/**
* Signal holding the formatted error message suitable for tooltips or detailed display.
* When multiple validation errors occur, this may contain all messages, while `error()` might show a summary.
* (Generated by `injectCreateDateState` using the validator's `.resolve()` method, or shortened by provided maxErrorHintLength).
*/
errorTooltip: Signal<string>;
/** signal for hint tooltip, default is shortened when hint is longer than 40 chars */
hintTooltip: Signal<string>;
/**
* Signal holding the minimum selectable date (inclusive), derived from options.
* Returns `null` if no minimum date is set. The value is always a `Date` object internally
* for reliable comparison, regardless of the input option format (`string` or `Date`).
* Useful for binding to date picker component properties (e.g., `[min]`).
*/
min: Signal<Date | null>;
/**
* Signal holding the maximum selectable date (inclusive), derived from options.
* Returns `null` if no maximum date is set. The value is always a `Date` object internally.
* Useful for binding to date picker component properties (e.g., `[max]`).
*/
max: Signal<Date | null>;
/** Type discriminator for date controls. */
type: 'date';
};
/**
* Configuration options for the `createDateState` function (the non-DI version).
* Extends base form control options for a `TDate | null` value.
*
* @template TDate The type used for date values. Defaults to `Date`.
* @see CreateFormControlOptions
* @see createDateState
*/
type DateStateOptions<TDate = Date> = CreateFormControlOptions<TDate | null, 'control'> & {
/**
* The locale string (e.g., 'en-US', 'de-DE'). While required by this type,
* it's primarily intended to be passed down internally when using the
* dependency-injected factory (`injectCreateDateState`) which obtains it from `LOCALE_ID`.
* If using `createDateState` directly, you must provide it manually, but its primary
* use is within the validation message formatting handled by the injected system.
*/
locale: string;
/** Optional function returning the placeholder text for the date input. */
placeholder?: () => string;
/**
* Optional function returning the minimum selectable date (inclusive).
* Accepts a string (parsed as `new Date(string)`), a `Date` object, or `null`.
* Populates the `min` signal on the `DateState`.
* Note: If using `injectCreateDateState`, setting `min` via the `validation`
* options is generally preferred as it enables validation messages.
*/
min?: () => string | Date | null;
/**
* Optional function returning the maximum selectable date (inclusive).
* Accepts a string (parsed as `new Date(string)`), a `Date` object, or `null`.
* Populates the `max` signal on the `DateState`.
* Note: If using `injectCreateDateState`, setting `max` via the `validation`
* options is generally preferred as it enables validation messages.
*/
max?: () => string | Date | null;
maxErrorHintLength?: () => number;
};
/**
* Configuration options specifically for the factory function returned by
* `injectCreateDateState`.
*
* This type omits base properties handled internally by the factory (like `validator`, `required`, `locale`)
* and requires validation rules to be provided via the `validation` property using `DateValidatorOptions`
* from `@mmstack/form-validation`.
*
* @template TDate The type used for date values. Defaults to `Date`.
* @see injectCreateDateState
* @see DateStateOptions
* @see DateValidatorOptions
*/
type InjectedDateStateOptions<TDate = Date> = Omit<DateStateOptions<TDate>, 'required' | 'validator' | 'locale' | 'min' | 'max'> & {
/**
* Optional function returning a `DateValidatorOptions` object defining the validation rules.
* The `min`, `max` & `required` properties set here will be used for both validation *and* to populate
* the `min`, `max` & `required` signals on the resulting `DateState`.
* The factory function uses this configuration with the injected `validators.date.all()` method.
*
* @example validation: () => ({ required: true, min: new Date(), max: '2099-12-31' })
*/
validation?: () => DateValidatorOptions;
};
/**
* Creates the reactive state object (`DateState`) for a date form control
* without relying on Angular's dependency injection for validation or locale.
* Includes computed signals for `min` and `max` date constraints based directly on the provided options.
*
* Use this function directly only if creating state outside an injection context
* or providing a fully custom `validator`, `locale`, `min`, and `max` manually via `opt`.
* Prefer `injectCreateDateState` for standard usage within Angular applications.
*
* Note: The `errorTooltip` signal returned by this function will initially be empty.
* Enhanced tooltip generation based on multiple errors is handled by `injectCreateDateState`.
*
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
* @template TDate The type used for date values. Defaults to `Date`.
* @param value The initial date value (`TDate | null`), or a `DerivedSignal` linking it to a parent state.
* @param opt Configuration options (`DateStateOptions`), requires `locale`, optionally `validator`, `placeholder`, `min`, `max`.
* @returns A `DateState` instance managing the control's reactive state, including `min` and `max` signals.
* @see injectCreateDateState
*/
declare function createDateState<TParent = undefined, TDate = Date>(value: TDate | null | DerivedSignal<TParent, TDate | null>, opt: DateStateOptions<TDate>): DateState<TParent, TDate>;
/**
* Creates and returns a factory function for generating `DateState` instances.
*
* This factory utilizes Angular's dependency injection (`injectValidators`, `LOCALE_ID`)
* to automatically handle:
* - Validation configuration via `DateValidatorOptions` (passed to the `validation` option).
* - Localization for default validation error messages.
* - Enhanced error message formatting (splitting merged errors into `error` and `errorTooltip` signals).
* - Populating the `min` and `max` signals on `DateState` based on the constraints specified
* within the `validation` options object.
* - Configuration of date handling based on `provideValidatorConfig`.
*
* This is the **recommended** way to create `DateState` within an Angular application.
*
* @returns A factory function: `(value: TDate | null | DerivedSignal<TParent, TDate | null>, opt?: InjectedDateStateOptions<TDate>) => DateState<TParent, TDate>`.
* @template TDate The type used for date values passed to the factory (e.g., `Date`, Luxon `DateTime`).
* Must match the `TDate` used during `provideValidatorConfig` if custom date handling is required. Defaults to `Date`.
*
* @example
* // Within an injection context:
* const createDate = injectCreateDateState();
* // If using Luxon: const createDate = injectCreateDateState<DateTime>();
*
* const eventDateState = createDate(null, {
* label: () => 'Event Date',
* placeholder: () => 'Select event date',
* validation: () => ({ // Provide DateValidatorOptions here
* required: true,
* min: new Date(), // Sets min validation AND state.min() signal
* max: '2099-12-31' // Sets max validation AND state.max() signal
* })
* });
*
* // Template can use min/max signals for datepicker limits:
* // <mat-datepicker-toggle [for]="picker" [disabled]="eventDateState.disabled()"></mat-datepicker-toggle>
* // <input matInput [matDatepicker]="picker"
* // [min]="eventDateState.min()"
* // [max]="eventDateState.max()"
* // [(ngModel)]="eventDateState.value" ... >
* // <mat-datepicker #picker></mat-datepicker>
* // <mat-error><span [matTooltip]="eventDateState.errorTooltip()">{{ eventDateState.error() }}</span></mat-error>
*/
declare function injectCreateDateState(): <TDate = Date, TParent = undefined>(value: TDate | null | DerivedSignal<TParent, TDate | null>, opt?: InjectedDateStateOptions<TDate>) => {
error: Signal<string>;
errorTooltip: Signal<string>;
id: string;
value: _angular_core.WritableSignal<TDate | null>;
dirty: Signal<boolean>;
touched: Signal<boolean>;
pending: Signal<boolean>;
valid: Signal<boolean>;
disabled: Signal<boolean>;
readonly: Signal<boolean>;
required: Signal<boolean>;
label: Signal<string>;
hint: Signal<string>;
markAsTouched: () => void;
markAllAsTouched: () => void;
markAsPristine: () => void;
markAllAsPristine: () => void;
reconcile: (newValue: TDate | null) => void;
forceReconcile: (newValue: TDate | null) => void;
reset: () => void;
resetWithInitial: (initial: TDate | null) => void;
from?: ((v: TParent) => TDate | null) | undefined;
equal: (a: TDate | null, b: TDate | null) => boolean;
controlType: "control";
partialValue: Signal<TDate | null | undefined>;
/** Signal holding the input placeholder text (e.g., "YYYY-MM-DD"). */
placeholder: Signal<string>;
/** signal for hint tooltip, default is shortened when hint is longer than 40 chars */
hintTooltip: Signal<string>;
/**
* Signal holding the minimum selectable date (inclusive), derived from options.
* Returns `null` if no minimum date is set. The value is always a `Date` object internally
* for reliable comparison, regardless of the input option format (`string` or `Date`).
* Useful for binding to date picker component properties (e.g., `[min]`).
*/
min: Signal<Date | null>;
/**
* Signal holding the maximum selectable date (inclusive), derived from options.
* Returns `null` if no maximum date is set. The value is always a `Date` object internally.
* Useful for binding to date picker component properties (e.g., `[max]`).
*/
max: Signal<Date | null>;
/** Type discriminator for date controls. */
type: "date";
};
type DateRangeStateChildren<TDate = Date> = {
start: DateState<DateRange<TDate>, TDate>;
end: DateState<DateRange<TDate>, TDate>;
};
/**
* Represents the reactive state for a date range input form group.
*
* Extends the base `FormGroupSignal<DateRange<TDate>>` and adds date-specific
* properties like `placeholder` and enhanced `error`/`errorTooltip` signals derived
* from the validation result's `.resolve()` method (when using the injected factory).
*
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
* @template TDate The type used for date values within the control (e.g., `Date`, Luxon `DateTime`, Moment). Defaults to `Date`.
* @see FormGroupSignal
* @see DateState
*/
type DateRangeState<TParent = undefined, TDate = Date> = FormGroupSignal<DateRange<TDate>, DateRangeStateChildren<TDate>, TParent> & {
/**
* Signal holding the formatted error message suitable for tooltips or detailed display.
* When multiple validation errors occur, this may contain all messages, while `error()` might show a summary.
* (Generated by `injectCreateDateRangeState` using the validator's `.resolve()` method, or shortened by provided maxErrorHintLength).
*/
errorTooltip: Signal<string>;
/** signal for hint tooltip, default is shortened when hint is longer than 40 chars */
hintTooltip: Signal<string>;
/**
* Signal holding the minimum selectable date (inclusive), derived from options.
* Returns `null` if no minimum date is set. The value is always a `Date` object internally
* for reliable comparison, regardless of the input option format (`string` or `Date`).
* Useful for binding to date picker component properties (e.g., `[min]`).
*/
min: Signal<Date | null>;
/**
* Signal holding the maximum selectable date (inclusive), derived from options.
* Returns `null` if no maximum date is set. The value is always a `Date` object internally.
* Useful for binding to date picker component properties (e.g., `[max]`).
*/
max: Signal<Date | null>;
/** Type discriminator for date-range controls. */
type: 'date-range';
};
/**
* Optional configuration for the `from/to` date state.
* This allows you to customize the behavior of the `from` date input.
* you can provide specific options such as placeholder.
*/
type ChildDateStateOptions<TDate = Date> = Omit<DateStateOptions<TDate>, 'locale' | 'min' | 'max' | 'label' | 'disable' | 'readonly' | 'maxErrorHintLength'>;
/**
* Configuration options for the `createDateRangeState` function (the non-DI version).
* Extends base form group options for a `DateRange<TDate>` value.
*
* @template TDate The type used for date values. Defaults to `Date`.
* @see CreateFormGroupOptions
* @see createDateRangeState
*/
type DateRangeStateOptions<TDate = Date> = CreateFormGroupOptions<DateRange<TDate>, DateRangeStateChildren<TDate>> & {
/**
* The locale string (e.g., 'en-US', 'de-DE'). While required by this type,
* it's primarily intended to be passed down internally when using the
* dependency-injected factory (`injectCreateDateRangeState`) which obtains it from `LOCALE_ID`.
* If using `createDateRangeState` directly, you must provide it manually, but its primary
* use is within the validation message formatting handled by the injected system.
*/
locale: string;
/**
* Optional function returning the minimum selectable date (inclusive).
* Accepts a string (parsed as `new Date(string)`), a `Date` object, or `null`.
* Populates the `min` signal on the `DateRangeState`.
* Note: If using `injectCreateDateRangeState`, setting `min` via the `validation`
* options is generally preferred as it enables validation messages.
*/
min?: () => string | Date | null;
/**
* Optional function returning the maximum selectable date (inclusive).
* Accepts a string (parsed as `new Date(string)`), a `Date` object, or `null`.
* Populates the `max` signal on the `DateRangeState`.
* Note: If using `injectCreateDateRangeState`, setting `max` via the `validation`
* options is generally preferred as it enables validation messages.
*/
max?: () => string | Date | null;
maxErrorHintLength?: () => number;
/** Optional configuration applied specifically to the 'start' date input control (e.g., setting a placeholder). */
start?: ChildDateStateOptions<TDate>;
/** Optional configuration applied specifically to the 'end' date input control (e.g., setting a placeholder). */
end?: ChildDateStateOptions<TDate>;
};
/**
* Creates the reactive state object (`DateRangeState`) for a date range form control
* without relying on Angular's dependency injection for validation or locale.
*
* Internally creates a `formGroup` with `start` and `end` `DateState` children
* using the non-DI `createDateState` function. It computes overall `min`/`max` signals
* based directly on the provided `opt.min` and `opt.max` options.
*
* Prefer `injectCreateDateRangeState` for standard usage within Angular applications to leverage
* automatic validation integration, localization, and enhanced error display.
*
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
* @template TDate The type used for date values. Defaults to `Date`.
* @param value The initial date range value (`DateRange<TDate>`, e.g., `{ start: TDate|null, end: TDate|null }`),
* or a `DerivedSignal` linking it to a parent state.
* @param opt Configuration options (`DateRangeStateOptions`). Requires `locale`. Allows specifying options
* for the child `start`/`end` inputs via `opt.start`/`opt.end`.
* @returns A `DateRangeState` instance managing the control's reactive state.
* @see injectCreateDateRangeState
* @see DateRangeStateOptions
* @see formGroup
* @see createDateState
*/
declare function createDateRangeState<TParent = undefined, TDate = Date>(value: DateRange<TDate> | DerivedSignal<TParent, DateRange<TDate>>, opt: DateRangeStateOptions<TDate>): DateRangeState<TParent, TDate>;
/**
* Configuration options specifically for the factory function returned by
* `injectCreateDateRangeState`.
*
* Extends `DateRangeStateOptions` but omits properties handled internally by the factory
* (`locale`, `required`, `validator`, `min`, `max`). Requires validation rules for the
* *date range itself* (including overall `min`/`max` constraints which also drive the state's signals)
* via the `validation` property using `DateValidatorOptions`.
*
* **Assumption:** It's expected that `@mmstack/form-validation` provides range-specific validation logic
* (like ensuring start <= end) accessible via `validators.dateRange.all(...)` when interpreting
* the provided `DateValidatorOptions`.
*
* @template TDate The type used for date values. Defaults to `Date`.
* @see injectCreateDateRangeState
* @see DateRangeStateOptions
* @see DateValidatorOptions
*/
type InjectedDateRangeStateOptions<TDate = Date> = Omit<DateRangeStateOptions<TDate>, 'locale' | 'required' | 'validator' | 'min' | 'max'> & {
/**
* Optional function returning `DateValidatorOptions`. Defines validation rules for the
* *entire date range* object (e.g., required start/end, overall min/max constraints,
* potentially range validity like start <= end if supported by `validators.dateRange.all`).
* The `min` and `max` specified here also populate the `DateRangeState`'s `min`/`max` signals.
* @example validation: () => ({ required: true, min: new Date(), range: true }) // Assuming 'range' rule exists
*/
validation?: () => DateValidatorOptions;
};
/**
* Creates and returns a factory function for generating `DateRangeState` instances.
*
* This factory utilizes Angular's dependency injection (`injectValidators`, `LOCALE_ID`)
* to automatically handle validation configuration (expecting range-specific rules like start <= end
* via `validators.dateRange.all` interpreting `DateValidatorOptions`), localization, and enhanced
* error message formatting (`error`/`errorTooltip`). The overall `min`/`max` signals on the state
* are also automatically derived from the `min`/`max` constraints provided within the `validation` options.
*
* This is the **recommended** way to create `DateRangeState` within an Angular application.
*
* @returns A factory function: `(value: DateRange<TDate> | DerivedSignal<TParent, DateRange<TDate>>, opt?: InjectedDateRangeStateOptions<TDate>) => DateRangeState<TParent, TDate>`.
* @template TDate The type used for date values. Defaults to `Date`. Must match type used in `provideValidatorConfig`.
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
*
* @example
* // Within an injection context:
* const createDateRange = injectCreateDateRangeState();
* // Assuming DateRange = { start: Date | null, end: Date | null }
*
* const vacationDatesState = createDateRange({ start: null, end: null }, {
* label: () => 'Vacation Dates',
* start: { placeholder: () => 'Departure Date' }, // Child control options
* end: { placeholder: () => 'Return Date' },
* validation: () => ({ // Validation for the range
* required: true, // Requires both start and end
* min: new Date(), // Overall minimum date for picker & validation
* // Assumes validation library has a rule triggered by DateValidatorOptions
* // that checks if start <= end, potentially enabled by default or specific flag
* })
* });
*
* // Template binds to child states for inputs:
* // <mat-date-range-input [formGroup]="vacationDatesFormGroup"> * // <input matStartDate [(ngModel)]="vacationDatesState.children().start.value" [placeholder]="vacationDatesState.children().start.placeholder()">
* // <input matEndDate [(ngModel)]="vacationDatesState.children().end.value" [placeholder]="vacationDatesState.children().end.placeholder()">
* // </mat-date-range-input>
* // <mat-date-range-picker [min]="vacationDatesState.min()" [max]="vacationDatesState.max()"></mat-date-range-picker>
*/
declare function injectCreateDateRangeState(): <TDate = Date, TParent = undefined>(value: DateRange<TDate> | DerivedSignal<TParent, DateRange<TDate>>, opt?: InjectedDateRangeStateOptions<TDate>) => DateRangeState<TParent, TDate>;
/**
* Represents the reactive state for a time input form control.
*
* Extends the base `DateState` angular defaults to todays date, but varies the time if no date is provided
* min and max values adapt automatically to the dates day
*
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
* @template TDate The type used for date values within the control (e.g., `Date`, Luxon `DateTime`, Moment). Defaults to `Date`.
* @see DateState
*/
type TimeState<TParent = undefined, TDate = Date> = Omit<DateState<TParent, TDate>, 'type'> & {
type: 'time';
};
/**
* @see DateStateOptions
*/
type TimeStateOptions<TDate = Date> = DateStateOptions<TDate> & {
/**
* A function to convert the date value to a standard `Date` object.
* Defaults to `defaultToDate`, which converts `TDate` to a `Date`.
*/
toDate?: (date: TDate | null) => Date | null;
};
/**
* @see InjectedDateStateOptions
*/
type InjectedTimeStateOptions<TDate = Date> = InjectedDateStateOptions<TDate>;
/**
* Creates the reactive state object (`TimeState`) for a time form control
* without relying on Angular's dependency injection for validation or locale.
* Includes computed signals for `min` and `max` date constraints based directly on the provided options.
* If provided the day will shift to the current values date, in order to only validate the time part.
* Angular defaults to today's date, but varies the time if no date is provided.
*
* Use this function directly only if creating state outside an injection context
* or providing a fully custom `validator`, `locale`, `min`, and `max` manually via `opt`.
* Prefer `injectCreateTimeState` for standard usage within Angular applications.
*
* Note: The `errorTooltip` signal returned by this function will initially be empty.
* Enhanced tooltip generation based on multiple errors is handled by `injectCreateTimeState`.
*
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
* @template TDate The type used for date values. Defaults to `Date`.
* @param value The initial date value (`TDate | null`), or a `DerivedSignal` linking it to a parent state.
* @param opt Configuration options (`TimeStateOptions`), requires `locale`, optionally `validator`, `placeholder`, `min`, `max`.
* @returns A `TimeState` instance managing the control's reactive state, including `min` and `max` signals.
* @see injectCreateTimeState
* @see createDateState
*/
declare function createTimeState<TParent = undefined, TDate = Date>(value: TDate | null | DerivedSignal$1<TParent, TDate | null>, opt: TimeStateOptions<TDate>): TimeState<TParent, TDate>;
/**
* Creates and returns a factory function for generating `TimeState` instances.
*
* This factory utilizes Angular's dependency injection (`injectValidators`, `LOCALE_ID`)
* to automatically handle:
* - Validation configuration via `DateValidatorOptions` (passed to the `validation` option).
* - Localization for default validation error messages.
* - Enhanced error message formatting (splitting merged errors into `error` and `errorTooltip` signals).
* - Populating the `min` and `max` signals on `TimeState` based on the constraints specified
* within the `validation` options object.
* - Configuration of date handling based on `provideValidatorConfig`.
*
* This is the **recommended** way to create `TimeState` within an Angular application.
*
* @returns A factory function: `(value: TDate | null | DerivedSignal<TParent, TDate | null>, opt?: InjectedTimeStateOptions<TDate>) => TimeState<TParent, TDate>`.
* @template TDate The type used for date values passed to the factory (e.g., `Date`, Luxon `DateTime`).
* Must match the `TDate` used during `provideValidatorConfig` if custom date handling is required. Defaults to `Date`.
*
* @example
* // Within an injection context:
* const createTime = injectCreateTimeState();
* // If using Luxon: const createTime = injectCreateTimeState<DateTime>();
*
* const eventTimeState = createTime(null, {
* label: () => 'Event Time',
* placeholder: () => 'Select event time',
* validation: () => ({ // Provide DateValidatorOptions here
* required: true,
* min: new Date(), // Sets min validation AND state.min() signal
* })
* });
*
* // Template can use min/max signals for datepicker limits:
* // <mat-timepicker-toggle [for]="picker" [disabled]="eventTimeState.disabled()"></mat-datepicker-toggle>
* // <input matInput [matTimepicker]="picker"
* // [min]="eventTimeState.min()"
* // [max]="eventTimeState.max()"
* // [(ngModel)]="eventTimeState.value" ... >
* // <mat-timepicker #picker></mat-datepicker>
* // <mat-error><span [matTooltip]="eventTimeState.errorTooltip()">{{ eventTimeState.error() }}</span></mat-error>
*/
declare function injectCreateTimeState(): <TDate = Date, TParent = undefined>(value: TDate | null | DerivedSignal$1<TParent, TDate | null>, opt?: InjectedTimeStateOptions<TDate>) => {
error: _angular_core.Signal<string>;
errorTooltip: _angular_core.Signal<string>;
required: _angular_core.Signal<boolean>;
equal: (a: TDate | null, b: TDate | null) => boolean;
readonly: _angular_core.Signal<boolean>;
label: _angular_core.Signal<string>;
id: string;
hint: _angular_core.Signal<string>;
controlType: "control";
pending: _angular_core.Signal<boolean>;
hintTooltip: _angular_core.Signal<string>;
from?: ((v: TParent) => TDate | null) | undefined;
value: _angular_core.WritableSignal<TDate | null>;
dirty: _angular_core.Signal<boolean>;
touched: _angular_core.Signal<boolean>;
valid: _angular_core.Signal<boolean>;
disabled: _angular_core.Signal<boolean>;
markAsTouched: () => void;
markAllAsTouched: () => void;
markAsPristine: () => void;
markAllAsPristine: () => void;
reconcile: (newValue: TDate | null) => void;
forceReconcile: (newValue: TDate | null) => void;
reset: () => void;
resetWithInitial: (initial: TDate | null) => void;
partialValue: _angular_core.Signal<TDate | null | undefined>;
min: _angular_core.Signal<Date | null>;
max: _angular_core.Signal<Date | null>;
placeholder: _angular_core.Signal<string>;
type: "time";
};
/**
* Represents the reactive state for a time input form control.
*
* Extends the base `DateState` to include both date and time components, exposes them as separate controls.
* The base controls uses the date control's min/max & other values
*
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
* @template TDate The type used for date values within the control (e.g., `Date`, Luxon `DateTime`, Moment). Defaults to `Date`.
* @see DateState
* @see TimeState
*/
type DateTimeState<TParent = undefined, TDate = Date> = Omit<DateState<TParent, TDate>, 'type'> & {
type: 'datetime';
/**
* The date control managing the date part of the datetime input.
* It uses the same `min` and `max` constraints as the time control.
*/
dateControl: DateState<TParent, TDate>;
/**
* The time control managing the time part of the datetime input.
* It uses the same `min` and `max` constraints as the date control. But only the time part is validatied
*/
timeControl: TimeState<TParent, TDate>;
};
/**
* @see TimeStateOptions
* @see DateStateOptions
*/
type DateTimeStateOptions<TDate = Date> = TimeStateOptions<TDate> & {
timeLabel?: () => string;
timeHint?: () => string;
timePlaceholder?: () => string;
};
/**
* @see InjectedTimeStateOptions
* @see InjectedDateStateOptions
*/
type InjectedDateTimeStateOptions<TDate = Date> = InjectedTimeStateOptions<TDate> & {
timeLabel?: () => string;
timeHint?: () => string;
timePlaceholder?: () => string;
};
/**
* Creates the reactive state object (`DateTimeState`) for a time form control
* without relying on Angular's dependency injection for validation or locale.
* Includes computed signals for `min` and `max` date constraints based directly on the provided options.
* If provided the day will shift to the current values date, in order to only validate the time part.
* Angular defaults to today's date, but varies the time if no date is provided.
*
* Use this function directly only if creating state outside an injection context
* or providing a fully custom `validator`, `locale`, `min`, and `max` manually via `opt`.
* Prefer `injectCreateDateTimeState` for standard usage within Angular applications.
*
* Note: The `errorTooltip` signal returned by this function will initially be empty.
* Enhanced tooltip generation based on multiple errors is handled by `injectCreateDateTimeState`.
*
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
* @template TDate The type used for date values. Defaults to `Date`.
* @param value The initial date value (`TDate | null`), or a `DerivedSignal` linking it to a parent state.
* @param opt Configuration options (`DateTimeStateOptions`), requires `locale`, optionally `validator`, `placeholder`, `min`, `max`.
* @returns A `DateTimeState` instance managing the control's reactive state, including `min` and `max` signals.
* @see injectCreateDateTimeState
* @see createDateState
*/
declare function createDateTimeState<TParent = undefined, TDate = Date>(initial: TDate | null | DerivedSignal$1<TParent, TDate | null>, opt: DateTimeStateOptions<TDate>): DateTimeState<TParent, TDate>;
/**
* Creates and returns a factory function for generating `DateTimeState` instances.
*
* This factory utilizes Angular's dependency injection (`injectValidators`, `LOCALE_ID`)
* to automatically handle:
* - Validation configuration via `DateValidatorOptions` (passed to the `validation` option).
* - Localization for default validation error messages.
* - Enhanced error message formatting (splitting merged errors into `error` and `errorTooltip` signals).
* - Populating the `min` and `max` signals on `DateTimeState` based on the constraints specified
* within the `validation` options object.
* - Configuration of date handling based on `provideValidatorConfig`.
*
* This is the **recommended** way to create `DateTimeState` within an Angular application.
*
* @returns A factory function: `(value: TDate | null | DerivedSignal<TParent, TDate | null>, opt?: InjectedDateTimeStateOptions<TDate>) => DateTimeState<TParent, TDate>`.
* @template TDate The type used for date values passed to the factory (e.g., `Date`, Luxon `DateTime`).
* Must match the `TDate` used during `provideValidatorConfig` if custom date handling is required. Defaults to `Date`.
*
*/
declare function injectCreateDateTimeState(): <TDate = Date, TParent = undefined>(initial: TDate | null | DerivedSignal$1<TParent, TDate | null>, opt?: InjectedDateTimeStateOptions<TDate>) => DateTimeState<TParent, TDate>;
/**
* Represents the reactive state for a number input form control.
*
* Extends `FormControlSignal<number | null>` with properties and helpers
* for handling placeholders, step increments/decrements, localized number formatting
* (decimal separators), keyboard input filtering/handling for non-standard separators,
* and enhanced error display (error vs tooltip).
*
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
* @see FormControlSignal
*/
type NumberState<TParent = undefined> = FormControlSignal<number | null, TParent> & {
/** Signal holding the input placeholder text (e.g., "Enter quantity", "0"). */
placeholder: Signal<string>;
/**
* Signal holding the step value used for incrementing/decrementing the number,
* typically via spinner buttons or the ArrowUp/ArrowDown keys handled by `keydownHandler`.
* Defaults to `1`.
*/
step: Signal<number>;
/**
* Signal holding the formatted error message suitable for tooltips or detailed display.
* When multiple validation errors occur, this may contain all messages, while `error()` might show a summary.
* (Generated by `injectCreateNumberState` using the validator's `.resolve()` method, or shortened by provided maxErrorHintLength).
*/
errorTooltip: Signal<string>;
/** signal for hint tooltip, default is shortened when hint is longer than 40 chars */
hintTooltip: Signal<string>;
/**
* Signal holding the current numeric value formatted for display.
* If the configured decimal separator is the standard '.', this returns the raw `number | null`.
* Otherwise, it returns a `string | null` with the decimal point replaced by the configured separator.
* Useful for binding directly to the `value` of an `<input [type]="state.inputType()">`.
*/
localizedValue: Signal<string | number | null>;
/**
* Function to update the control's underlying numeric value from user input,
* which might be a string containing a localized decimal separator (e.g., ',').
* Parses the input string (replacing the localized separator with '.') back into a number.
* Handles `null`, empty string, and non-numeric input gracefully (sets value to `null`).
* Intended for use with `(input)` or `(change)` events, especially when `inputType` is 'string'.
* No-op if the control is disabled or readonly.
* @param value The string, number, or null value received from the input element.
*/
setLocalizedValue: (value: string | number | null) => void;
/**
* Signal indicating the appropriate HTML `input` element `type` attribute ('number' or 'string').
* Returns `'number'` if the configured decimal separator is '.', otherwise returns `'string'`.
* Using `<input type="string">` is necessary to allow users to type non-standard decimal separators (like ',').
* Bind using `[type]="state.inputType()"`.
*/
inputType: Signal<'string' | 'number'>;
/**
* Signal returning a keydown event handler function: `(e?: KeyboardEvent) => void`.
* Attach this to the `(keydown)` event of the input element, particularly when `inputType` might be 'string'.
* When active (not disabled/readonly and using non-'.' separator), it:
* - Prevents input of disallowed characters (allows digits, configured separator, minus, editing keys, standard shortcuts).
* - Handles ArrowUp/ArrowDown keys to increment/decrement the value by `step()`.
* It's a no-op if `inputType` is 'number' or the control is disabled/readonly.
*/
keydownHandler: Signal<(e?: KeyboardEvent) => void>;
/** Type discriminator for number controls. */
type: 'number';
};
/**
* Configuration options for the `createNumberState` function (the non-DI version).
* Extends base form control options for a `number | null` value.
*
* @see CreateFormControlOptions
* @see createNumberState
*/
type NumberStateOptions = CreateFormControlOptions<number | null, 'control'> & {
/** Optional function returning the step value for number increments/decrements. Defaults to `() => 1`. */
step?: () => number;
/** Optional function returning the placeholder text for the number input. */
placeholder?: () => string;
/**
* Optional function returning the desired decimal separator character (e.g., ',', '.').
* If not provided, defaults to '.' (ISO standard). This affects the behavior of
* `localizedValue`, `setLocalizedValue`, `inputType`, and `keydownHandler`.
* If using `injectCreateNumberState`, prefer the `localizeDecimal` option instead.
*/
decimalSeparator?: () => string;
maxErrorHintLength?: () => number;
};
/**
* Configuration options specifically for the factory function returned by
* `injectCreateNumberState`.
*
* This type omits base properties handled internally by the factory (like `validator`, `required`, `decimalSeparator`)
* and requires validation rules to be provided via the `validation` property using `NumberValidatorOptions`.
* It adds the `localizeDecimal` option for streamlined locale-based or manual separator configuration.
*
* @see injectCreateNumberState
* @see NumberStateOptions
* @see NumberValidatorOptions
*/
type InjectedNumberStateOptions = Omit<NumberStateOptions, 'required' | 'validator' | 'decimalSeparator'> & {
/**
* Optional function returning a `NumberValidatorOptions` object defining the validation rules.
* The factory uses this configuration with the injected `validators.number.all()` method.
* @example validation: () => ({ required: true, min: 0, integer: true })
*/
validation?: () => NumberValidatorOptions;
/**
* Configures if and how the decimal separator should be localized, affecting input type,
* formatting (`localizedValue`), parsing (`setLocalizedValue`), and keyboard handling (`keydownHandler`).
* Options:
* - `() => true`: Use the decimal separator determined from the injected `LOCALE_ID`.
* - `() => string`: Use the provided string literal as the decimal separator (e.g., `() => ','`).
* - `() => false` or `undefined` (or omit): Use the default '.' separator (results in `<input type="number">`).
* @example localizeDecimal: () => true // Use locale's separator (e.g., ',' for 'de-DE') -> input type="string"
* @example localizeDecimal: () => ',' // Force comma separator -> input type="string"
* @example // No option provided -> uses '.' separator -> input type="number"
*/
localizeDecimal?: () => boolean | string;
};
/**
* Creates the reactive state object (`NumberState`) for a number form control
* without relying on Angular's dependency injection for validation or localization.
*
* Use this function directly only if creating state outside an injection context, providing
* a fully custom `validator`, or needing to manually specify the `decimalSeparator`.
* Prefer `injectCreateNumberState` for standard usage within Angular applications, as it
* integrates validation, locale-based formatting, and enhanced error display.
*
* Note: The `errorTooltip` signal returned by this function will initially be empty.
*
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
* @param value The initial number value (`number | null`), or a `DerivedSignal` linking it to a parent state.
* @param opt Optional configuration options (`NumberStateOptions`), potentially including `validator`, `decimalSeparator`, `step`, `placeholder`.
* @returns A `NumberState` instance managing the control's reactive state.
* @see injectCreateNumberState
*/
declare function createNumberState<TParent = undefined>(value: number | null | DerivedSignal<TParent, number | null>, opt?: NumberStateOptions): NumberState<TParent>;
/**
* Creates and returns a factory function for generating `NumberState` instances.
*
* This factory leverages Angular's dependency injection (`injectValidators`, `LOCALE_ID`)
* to seamlessly integrate:
* - Validation configuration via `NumberValidatorOptions`.
* - Optional localization for decimal separators using the `localizeDecimal` option.
* - Enhanced error message formatting (splitting merged errors into `error` and `errorTooltip`).
*
* This is the **recommended** way to create `NumberState` within an Angular application.
*
* @returns A factory function: `(value: number | null | DerivedSignal<TParent, number | null>, opt?: InjectedNumberStateOptions) => NumberState<TParent>`.
* @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.
*
* @example
* // Within an injection context:
* const createNumber = injectCreateNumberState();
*
* const quantityState = createNumber(1, {
* label: () => 'Qty',
* step: () => 1,
* validation: () => ({ required: true, min: 1, integer: true })
* });
*
* const localPriceState = createNumber(null, {
* label: () => 'Price',
* placeholder: () => '0,00', // Example for comma locale
* localizeDecimal: () => true, // Use locale separator (e.g., ',')
* validation: () => ({ required: true, min: 0, multipleOf: 0.01 })
* });
*
* // Template usage requires handling localized input if localizeDecimal is not false/undefined:
* // <input
* // [type]="localPriceState.inputType()" // Will be 'string' if locale uses ','
* // [value]="localPriceState.localizedValue()" // Formats number with ','
* // (input)="localPriceState.setLocalizedValue($any($event).target.value)" // Parses input with ','
* // (keydown)="localPriceState.keydow