@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
1 lines • 201 kB
Source Map (JSON)
{"version":3,"file":"mmstack-form-adapters.mjs","sources":["../../../../../packages/form/adapters/src/lib/util/tooltip.ts","../../../../../packages/form/adapters/src/lib/boolean/base-boolean.ts","../../../../../packages/form/adapters/src/lib/boolean/toggle.ts","../../../../../packages/form/adapters/src/lib/date/base-date.ts","../../../../../packages/form/adapters/src/lib/date/date-range.ts","../../../../../packages/form/adapters/src/lib/date/time.ts","../../../../../packages/form/adapters/src/lib/date/date-time.ts","../../../../../packages/form/adapters/src/lib/number/base-number.ts","../../../../../packages/form/adapters/src/lib/selectable/select.ts","../../../../../packages/form/adapters/src/lib/selectable/button-group.ts","../../../../../packages/form/adapters/src/lib/selectable/multi-select.ts","../../../../../packages/form/adapters/src/lib/selectable/chips.ts","../../../../../packages/form/adapters/src/lib/selectable/search.ts","../../../../../packages/form/adapters/src/lib/signal-error-validator.ts","../../../../../packages/form/adapters/src/lib/string/base-string.ts","../../../../../packages/form/adapters/src/lib/string/autocomplete.ts","../../../../../packages/form/adapters/src/lib/string/textarea.ts","../../../../../packages/form/adapters/src/mmstack-form-adapters.ts"],"sourcesContent":["import { computed, Signal } from '@angular/core';\r\n\r\ntype TooltipedSignals = {\r\n shortened: Signal<string>;\r\n tooltip: Signal<string>;\r\n};\r\n\r\nexport function tooltip(\r\n message: Signal<string>,\r\n providedMaxLen?: () => number,\r\n): TooltipedSignals {\r\n const maxLen = computed(() => providedMaxLen?.() ?? 40);\r\n const resolved = computed(() => {\r\n const max = maxLen();\r\n const m = message();\r\n if (m.length <= maxLen()) {\r\n return { value: m, tooltip: '' };\r\n }\r\n\r\n return {\r\n value: `${m.slice(0, max)}...`,\r\n tooltip: m,\r\n };\r\n });\r\n\r\n return {\r\n shortened: computed(() => resolved().value),\r\n tooltip: computed(() => resolved().tooltip),\r\n };\r\n}\r\n","import { computed, Signal } from '@angular/core';\r\nimport {\r\n formControl,\r\n type CreateFormControlOptions,\r\n type DerivedSignal,\r\n type FormControlSignal,\r\n} from '@mmstack/form-core';\r\nimport { injectValidators } from '@mmstack/form-validation';\r\nimport { tooltip } from '../util';\r\n\r\n/**\r\n * Represents the reactive state for a boolean form control (e.g., checkbox).\r\n * Extends the base `FormControlSignal<boolean>` and includes a `type` discriminator.\r\n * Intended for use with checkbox-like UI elements. For toggle switches, see `ToggleState`.\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable.\r\n * @see ToggleState\r\n */\r\nexport type BooleanState<TParent = undefined> = FormControlSignal<\r\n boolean,\r\n TParent\r\n> & {\r\n /** signal for error tooltip, default is shortened when error is longer than 40 chars */\r\n errorTooltip: Signal<string>;\r\n /** signal for hint tooltip, default is shortened when hint is longer than 40 chars */\r\n hintTooltip: Signal<string>;\r\n /** Type discriminator for boolean controls. */\r\n type: 'boolean';\r\n};\r\n\r\n/**\r\n * Configuration options for creating a `BooleanState`, used with `createBooleanState`.\r\n *\r\n * Inherits options from `CreateFormControlOptions<boolean>` but omits `required`,\r\n * as boolean \"required\" validation typically means \"must be true\", which is handled\r\n * via the `validation` option in `injectCreateBooleanState`.\r\n *\r\n * @see CreateFormControlOptions\r\n * @see injectCreateBooleanState\r\n */\r\nexport type BooleanStateOptions = Omit<\r\n CreateFormControlOptions<boolean, 'control'>,\r\n 'required'\r\n> & {\r\n /* shortens error/hint message & provides errorTooltip with full message, default 40 */\r\n maxErrorHintLength?: () => number;\r\n};\r\n\r\n/**\r\n * Creates the reactive state object (`BooleanState`) for a boolean form control\r\n * without relying on Angular's dependency injection for validation setup.\r\n *\r\n * Use this function directly if:\r\n * - You don't need validation or are providing a pre-built `validator` function manually.\r\n * - You are creating state outside of an Angular injection context.\r\n *\r\n * For easier integration with `@mmstack/form-validation`, prefer `injectCreateBooleanState`.\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable.\r\n * @param value The initial boolean value, or a `DerivedSignal` linking it to a parent state.\r\n * @param opt Optional configuration (`BooleanStateOptions`), potentially including a `validator` function.\r\n * @returns A `BooleanState` instance managing the control's reactive state.\r\n * @see injectCreateBooleanState\r\n */\r\nexport function createBooleanState<TParent = undefined>(\r\n value: boolean | DerivedSignal<TParent, boolean>,\r\n opt?: BooleanStateOptions,\r\n): BooleanState<TParent> {\r\n const state = formControl(value, opt);\r\n\r\n const { shortened: error, tooltip: errorTooltip } = tooltip(\r\n state.error,\r\n opt?.maxErrorHintLength,\r\n );\r\n\r\n const { shortened: hint, tooltip: hintTooltip } = tooltip(\r\n state.hint,\r\n opt?.maxErrorHintLength,\r\n );\r\n\r\n return {\r\n ...state,\r\n hint,\r\n hintTooltip,\r\n error,\r\n errorTooltip,\r\n type: 'boolean',\r\n };\r\n}\r\n\r\n/**\r\n * Configuration options specifically for the factory function returned by\r\n * `injectCreateBooleanState`.\r\n *\r\n * This type is derived from `BooleanStateOptions` but explicitly excludes the\r\n * `validator` property (as validation rules are configured via the `validation`\r\n * property below) and adds the `validation` configuration specific to boolean controls.\r\n *\r\n * @see injectCreateBooleanState\r\n * @see BooleanStateOptions\r\n */\r\nexport type InjectedBooleanStateOptions = Omit<\r\n BooleanStateOptions,\r\n 'validator'\r\n> & {\r\n /**\r\n * Optional configuration for boolean-specific validation rules.\r\n * The factory function uses the injected `validators` service based on this configuration.\r\n */\r\n validation?: () => {\r\n /**\r\n * If `true`, applies the `validators.boolean.mustBeTrue()` validator,\r\n * requiring the control's value to be `true` to be considered valid.\r\n */\r\n requireTrue?: boolean;\r\n };\r\n};\r\n\r\n/**\r\n * Factory function (returned by `injectCreateBooleanState`) that creates `BooleanState`.\r\n * Integrates with `@mmstack/form-validation` via DI to apply validation rules.\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable.\r\n * @param value The initial boolean value, or a `DerivedSignal` linking it to a parent state.\r\n * @param opt Configuration options specific to this injected factory, defined by\r\n * the `InjectedBooleanStateOptions` type, including the `validation` property.\r\n * @returns A `BooleanState` instance managing the control's reactive state.\r\n */\r\nexport function injectCreateBooleanState() {\r\n const validators = injectValidators();\r\n\r\n /**\r\n * Factory function (returned by `injectCreateBooleanState`) that creates `BooleanState`.\r\n * Integrates with `@mmstack/form-validation` via DI.\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable.\r\n * @param value The initial boolean value, or a `DerivedSignal` linking it to a parent state.\r\n * @param opt Configuration options, excluding `validator` but adding a `validation` property.\r\n * @param opt.validation Optional configuration for boolean-specific validation rules.\r\n * @param opt.validation.requireTrue If `true`, applies the `validators.boolean.mustBeTrue()` validator.\r\n * @returns A `BooleanState` instance managing the control's reactive state.\r\n */\r\n return <TParent = undefined>(\r\n value: boolean | DerivedSignal<TParent, boolean>,\r\n opt?: InjectedBooleanStateOptions,\r\n ): BooleanState<TParent> => {\r\n const validation = computed(() => ({\r\n requireTrue: false,\r\n ...opt?.validation?.(),\r\n }));\r\n\r\n const validator = computed(() => {\r\n if (validation().requireTrue) return validators.boolean.mustBeTrue();\r\n return () => '';\r\n });\r\n\r\n return createBooleanState(value, { ...opt, validator });\r\n };\r\n}\r\n","import { type DerivedSignal } from '@mmstack/primitives';\r\nimport {\r\n createBooleanState,\r\n injectCreateBooleanState,\r\n type BooleanState,\r\n type BooleanStateOptions,\r\n type InjectedBooleanStateOptions,\r\n} from './base-boolean';\r\n\r\n/**\r\n * Represents the reactive state for a toggle switch form control (e.g., `mat-slide-toggle`).\r\n *\r\n * This type is functionally equivalent to `BooleanState` but overrides the `type`\r\n * discriminator to `'toggle'` for specific identification if needed.\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable.\r\n * @see BooleanState\r\n */\r\nexport type ToggleState<TParent = undefined> = Omit<\r\n BooleanState<TParent>,\r\n 'type'\r\n> & {\r\n /** Type discriminator for toggle switch controls. */\r\n type: 'toggle';\r\n};\r\n\r\n/**\r\n * Configuration options for `createToggleState`.\r\n * This is a direct type alias for `BooleanStateOptions`.\r\n *\r\n * @see BooleanStateOptions\r\n * @see createToggleState\r\n */\r\nexport type ToggleStateOptions = BooleanStateOptions;\r\n\r\n/**\r\n * Configuration options for the factory function returned by `injectCreateToggleState`.\r\n * This is a direct type alias for `InjectedBooleanStateOptions`.\r\n *\r\n * @see InjectedBooleanStateOptions\r\n * @see injectCreateToggleState\r\n */\r\nexport type InjectedToggleStateOptions = InjectedBooleanStateOptions;\r\n\r\n/**\r\n * Creates the reactive state object (`ToggleState`) for a toggle switch form control\r\n * without relying on Angular's dependency injection for validation setup.\r\n *\r\n * This function wraps `createBooleanState` and simply overrides the `type` property\r\n * to `'toggle'`. Use this function if creating state outside an injection context\r\n * or providing a manual `validator` function via the options.\r\n *\r\n * For easier validation integration (like `requireTrue`), prefer `injectCreateToggleState`.\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable.\r\n * @param value The initial boolean value (`true`/`false`), or a `DerivedSignal` linking it to a parent state.\r\n * @param opt Optional configuration (`ToggleStateOptions`, alias for `BooleanStateOptions`).\r\n * @returns A `ToggleState` object managing the toggle's reactive state.\r\n * @see createBooleanState\r\n * @see injectCreateToggleState\r\n */\r\nexport function createToggleState<TParent = undefined>(\r\n value: boolean | DerivedSignal<TParent, boolean>,\r\n opt?: ToggleStateOptions,\r\n): ToggleState<TParent> {\r\n return {\r\n ...createBooleanState(value, opt),\r\n type: 'toggle',\r\n };\r\n}\r\n\r\n/**\r\n * Creates and returns a factory function for generating `ToggleState` instances.\r\n *\r\n * This factory utilizes Angular's dependency injection by wrapping the factory\r\n * returned from `injectCreateBooleanState`. It simplifies validation integration\r\n * (e.g., setting `requireTrue` via the `validation` option).\r\n *\r\n * This is the **recommended** way to create `ToggleState` when working within\r\n * an Angular injection context, especially if validation is needed.\r\n *\r\n * @returns A factory function: `(value: boolean | DerivedSignal<TParent, boolean>, opt?: InjectedToggleStateOptions) => ToggleState<TParent>`.\r\n * @see injectCreateBooleanState\r\n * @see InjectedToggleStateOptions\r\n * @example\r\n * // Within an Angular injection context (component, service, etc.):\r\n * const createToggle = injectCreateToggleState(); // Get the factory\r\n *\r\n * // Create state for an optional dark mode toggle\r\n * const darkModeState = createToggle(false, { label: () => 'Dark Mode' });\r\n *\r\n * // Create state for a toggle that must be enabled\r\n * const enableAnalyticsState = createToggle(false, {\r\n * label: () => 'Enable Analytics',\r\n * validation: () => ({ requireTrue: true }) // Use validation option\r\n * });\r\n */\r\nexport function injectCreateToggleState() {\r\n const factory = injectCreateBooleanState();\r\n\r\n /**\r\n * Factory function (returned by `injectCreateToggleState`) that creates `ToggleState`.\r\n * It wraps the factory from `injectCreateBooleanState` and sets the `type` to `'toggle'`.\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable.\r\n * @param value The initial boolean value, or a `DerivedSignal` linking it to a parent state.\r\n * @param opt Configuration options (`InjectedToggleStateOptions`), including the `validation` property.\r\n * @returns A `ToggleState` instance managing the toggle's reactive state.\r\n */\r\n return <TParent = undefined>(\r\n value: boolean | DerivedSignal<TParent, boolean>,\r\n opt?: InjectedToggleStateOptions,\r\n ): ToggleState<TParent> => {\r\n return {\r\n ...factory(value, opt),\r\n type: 'toggle',\r\n };\r\n };\r\n}\r\n","import { computed, inject, LOCALE_ID, type Signal } from '@angular/core';\r\nimport {\r\n type CreateFormControlOptions,\r\n type DerivedSignal,\r\n formControl,\r\n FormControlSignal,\r\n} from '@mmstack/form-core';\r\nimport {\r\n type DateValidatorOptions,\r\n injectValidators,\r\n} from '@mmstack/form-validation';\r\nimport { tooltip } from '../util';\r\n\r\n/**\r\n * Represents the reactive state for a date input form control.\r\n *\r\n * Extends the base `FormControlSignal<TDate | null>` and adds date-specific\r\n * properties like `placeholder` and enhanced `error`/`errorTooltip` signals derived\r\n * from the validation result's `.resolve()` method (when using the injected factory).\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.\r\n * @template TDate The type used for date values within the control (e.g., `Date`, Luxon `DateTime`, Moment). Defaults to `Date`.\r\n * @see FormControlSignal\r\n */\r\nexport type DateState<TParent = undefined, TDate = Date> = FormControlSignal<\r\n TDate | null, // Value can be the specific date type or null\r\n TParent\r\n> & {\r\n /** Signal holding the input placeholder text (e.g., \"YYYY-MM-DD\"). */\r\n placeholder: Signal<string>;\r\n /**\r\n * Signal holding the formatted error message suitable for tooltips or detailed display.\r\n * When multiple validation errors occur, this may contain all messages, while `error()` might show a summary.\r\n * (Generated by `injectCreateDateState` using the validator's `.resolve()` method, or shortened by provided maxErrorHintLength).\r\n */\r\n errorTooltip: Signal<string>;\r\n /** signal for hint tooltip, default is shortened when hint is longer than 40 chars */\r\n hintTooltip: Signal<string>;\r\n /**\r\n * Signal holding the minimum selectable date (inclusive), derived from options.\r\n * Returns `null` if no minimum date is set. The value is always a `Date` object internally\r\n * for reliable comparison, regardless of the input option format (`string` or `Date`).\r\n * Useful for binding to date picker component properties (e.g., `[min]`).\r\n */\r\n min: Signal<Date | null>;\r\n /**\r\n * Signal holding the maximum selectable date (inclusive), derived from options.\r\n * Returns `null` if no maximum date is set. The value is always a `Date` object internally.\r\n * Useful for binding to date picker component properties (e.g., `[max]`).\r\n */\r\n max: Signal<Date | null>;\r\n /** Type discriminator for date controls. */\r\n type: 'date';\r\n};\r\n\r\n/**\r\n * Configuration options for the `createDateState` function (the non-DI version).\r\n * Extends base form control options for a `TDate | null` value.\r\n *\r\n * @template TDate The type used for date values. Defaults to `Date`.\r\n * @see CreateFormControlOptions\r\n * @see createDateState\r\n */\r\nexport type DateStateOptions<TDate = Date> = CreateFormControlOptions<\r\n TDate | null,\r\n 'control'\r\n> & {\r\n /**\r\n * The locale string (e.g., 'en-US', 'de-DE'). While required by this type,\r\n * it's primarily intended to be passed down internally when using the\r\n * dependency-injected factory (`injectCreateDateState`) which obtains it from `LOCALE_ID`.\r\n * If using `createDateState` directly, you must provide it manually, but its primary\r\n * use is within the validation message formatting handled by the injected system.\r\n */\r\n locale: string;\r\n /** Optional function returning the placeholder text for the date input. */\r\n placeholder?: () => string;\r\n /**\r\n * Optional function returning the minimum selectable date (inclusive).\r\n * Accepts a string (parsed as `new Date(string)`), a `Date` object, or `null`.\r\n * Populates the `min` signal on the `DateState`.\r\n * Note: If using `injectCreateDateState`, setting `min` via the `validation`\r\n * options is generally preferred as it enables validation messages.\r\n */\r\n min?: () => string | Date | null;\r\n /**\r\n * Optional function returning the maximum selectable date (inclusive).\r\n * Accepts a string (parsed as `new Date(string)`), a `Date` object, or `null`.\r\n * Populates the `max` signal on the `DateState`.\r\n * Note: If using `injectCreateDateState`, setting `max` via the `validation`\r\n * options is generally preferred as it enables validation messages.\r\n */\r\n max?: () => string | Date | null;\r\n /* shortens error/hint message & provides errorTooltip with full message, default 40 */\r\n maxErrorHintLength?: () => number;\r\n};\r\n\r\n/**\r\n * Configuration options specifically for the factory function returned by\r\n * `injectCreateDateState`.\r\n *\r\n * This type omits base properties handled internally by the factory (like `validator`, `required`, `locale`)\r\n * and requires validation rules to be provided via the `validation` property using `DateValidatorOptions`\r\n * from `@mmstack/form-validation`.\r\n *\r\n * @template TDate The type used for date values. Defaults to `Date`.\r\n * @see injectCreateDateState\r\n * @see DateStateOptions\r\n * @see DateValidatorOptions\r\n */\r\nexport type InjectedDateStateOptions<TDate = Date> = Omit<\r\n // Options related to validation rules or locale are handled internally\r\n DateStateOptions<TDate>,\r\n 'required' | 'validator' | 'locale' | 'min' | 'max'\r\n> & {\r\n /**\r\n * Optional function returning a `DateValidatorOptions` object defining the validation rules.\r\n * The `min`, `max` & `required` properties set here will be used for both validation *and* to populate\r\n * the `min`, `max` & `required` signals on the resulting `DateState`.\r\n * The factory function uses this configuration with the injected `validators.date.all()` method.\r\n *\r\n * @example validation: () => ({ required: true, min: new Date(), max: '2099-12-31' })\r\n */\r\n validation?: () => DateValidatorOptions;\r\n};\r\n\r\n/**\r\n * Creates the reactive state object (`DateState`) for a date form control\r\n * without relying on Angular's dependency injection for validation or locale.\r\n * Includes computed signals for `min` and `max` date constraints based directly on the provided options.\r\n *\r\n * Use this function directly only if creating state outside an injection context\r\n * or providing a fully custom `validator`, `locale`, `min`, and `max` manually via `opt`.\r\n * Prefer `injectCreateDateState` for standard usage within Angular applications.\r\n *\r\n * Note: The `errorTooltip` signal returned by this function will initially be empty.\r\n * Enhanced tooltip generation based on multiple errors is handled by `injectCreateDateState`.\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.\r\n * @template TDate The type used for date values. Defaults to `Date`.\r\n * @param value The initial date value (`TDate | null`), or a `DerivedSignal` linking it to a parent state.\r\n * @param opt Configuration options (`DateStateOptions`), requires `locale`, optionally `validator`, `placeholder`, `min`, `max`.\r\n * @returns A `DateState` instance managing the control's reactive state, including `min` and `max` signals.\r\n * @see injectCreateDateState\r\n */\r\nexport function createDateState<TParent = undefined, TDate = Date>(\r\n value: TDate | null | DerivedSignal<TParent, TDate | null>,\r\n opt: DateStateOptions<TDate>,\r\n): DateState<TParent, TDate> {\r\n const state = formControl<TDate | null, TParent>(value, opt);\r\n\r\n const { shortened: error, tooltip: errorTooltip } = tooltip(\r\n state.error,\r\n opt.maxErrorHintLength,\r\n );\r\n const { shortened: hint, tooltip: hintTooltip } = tooltip(\r\n state.hint,\r\n opt.maxErrorHintLength,\r\n );\r\n\r\n return {\r\n ...state,\r\n min: computed(\r\n () => {\r\n const min = opt.min?.();\r\n if (!min) return null;\r\n return typeof min === 'string' ? new Date(min) : min;\r\n },\r\n {\r\n equal: (a, b) => a?.getTime() === b?.getTime(),\r\n },\r\n ),\r\n max: computed(() => {\r\n const max = opt.max?.();\r\n if (!max) return null;\r\n return typeof max === 'string' ? new Date(max) : max;\r\n }),\r\n placeholder: computed(() => opt.placeholder?.() ?? ''),\r\n error,\r\n errorTooltip,\r\n hint,\r\n hintTooltip,\r\n type: 'date',\r\n };\r\n}\r\n\r\n/**\r\n * Creates and returns a factory function for generating `DateState` instances.\r\n *\r\n * This factory utilizes Angular's dependency injection (`injectValidators`, `LOCALE_ID`)\r\n * to automatically handle:\r\n * - Validation configuration via `DateValidatorOptions` (passed to the `validation` option).\r\n * - Localization for default validation error messages.\r\n * - Enhanced error message formatting (splitting merged errors into `error` and `errorTooltip` signals).\r\n * - Populating the `min` and `max` signals on `DateState` based on the constraints specified\r\n * within the `validation` options object.\r\n * - Configuration of date handling based on `provideValidatorConfig`.\r\n *\r\n * This is the **recommended** way to create `DateState` within an Angular application.\r\n *\r\n * @returns A factory function: `(value: TDate | null | DerivedSignal<TParent, TDate | null>, opt?: InjectedDateStateOptions<TDate>) => DateState<TParent, TDate>`.\r\n * @template TDate The type used for date values passed to the factory (e.g., `Date`, Luxon `DateTime`).\r\n * Must match the `TDate` used during `provideValidatorConfig` if custom date handling is required. Defaults to `Date`.\r\n *\r\n * @example\r\n * // Within an injection context:\r\n * const createDate = injectCreateDateState();\r\n * // If using Luxon: const createDate = injectCreateDateState<DateTime>();\r\n *\r\n * const eventDateState = createDate(null, {\r\n * label: () => 'Event Date',\r\n * placeholder: () => 'Select event date',\r\n * validation: () => ({ // Provide DateValidatorOptions here\r\n * required: true,\r\n * min: new Date(), // Sets min validation AND state.min() signal\r\n * max: '2099-12-31' // Sets max validation AND state.max() signal\r\n * })\r\n * });\r\n *\r\n * // Template can use min/max signals for datepicker limits:\r\n * // <mat-datepicker-toggle [for]=\"picker\" [disabled]=\"eventDateState.disabled()\"></mat-datepicker-toggle>\r\n * // <input matInput [matDatepicker]=\"picker\"\r\n * // [min]=\"eventDateState.min()\"\r\n * // [max]=\"eventDateState.max()\"\r\n * // [(ngModel)]=\"eventDateState.value\" ... >\r\n * // <mat-datepicker #picker></mat-datepicker>\r\n * // <mat-error><span [matTooltip]=\"eventDateState.errorTooltip()\">{{ eventDateState.error() }}</span></mat-error>\r\n */\r\nexport function injectCreateDateState() {\r\n const validators = injectValidators();\r\n const locale = inject(LOCALE_ID);\r\n\r\n /**\r\n * Factory function (returned by `injectCreateDateState`) that creates `DateState`.\r\n * Integrates with `@mmstack/form-validation` via DI for validation and localization.\r\n * Handles splitting of multiple validation errors into `error` and `errorTooltip`.\r\n * Derives `min`/`max` state signals from `validation` options.\r\n *\r\n * @template TDate The type for date values used by this control. Defaults to `Date`.\r\n * @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.\r\n * @param value The initial date value (`TDate | null`), or a `DerivedSignal` linking it to a parent state.\r\n * @param opt Configuration options (`InjectedDateStateOptions`), including the `validation` property\r\n * which accepts `DateValidatorOptions` (used for both validation rules and setting state's `min`/`max` signals).\r\n * @returns A `DateState` instance managing the control's reactive state.\r\n */\r\n return <TDate = Date, TParent = undefined>(\r\n value: TDate | null | DerivedSignal<TParent, TDate | null>,\r\n opt?: InjectedDateStateOptions<TDate>,\r\n ) => {\r\n const validationOptions = computed(() => ({\r\n messageOptions: {\r\n label: opt?.label?.(),\r\n },\r\n ...opt?.validation?.(),\r\n }));\r\n\r\n const mergedValidator = computed(() =>\r\n validators.date.all(validationOptions()),\r\n );\r\n\r\n const validator = computed(() => {\r\n const merged = mergedValidator();\r\n\r\n return (value: TDate | null) => {\r\n return merged(value as Date);\r\n };\r\n });\r\n\r\n const state = createDateState(value, {\r\n ...opt,\r\n locale,\r\n min: computed(() => validationOptions().min ?? null),\r\n max: computed(() => validationOptions().max ?? null),\r\n required: computed(() => validationOptions().required ?? false),\r\n validator,\r\n });\r\n\r\n const resolvedError = computed(() => {\r\n const merger = mergedValidator();\r\n\r\n return merger.resolve(state.errorTooltip() || state.error());\r\n });\r\n\r\n return {\r\n ...state,\r\n error: computed(() => resolvedError().error),\r\n errorTooltip: computed(() => resolvedError().tooltip),\r\n };\r\n };\r\n}\r\n","import {\r\n computed,\r\n inject,\r\n isSignal,\r\n LOCALE_ID,\r\n signal,\r\n type Signal,\r\n} from '@angular/core';\r\nimport {\r\n derived,\r\n formGroup,\r\n type CreateFormGroupOptions,\r\n type DerivedSignal,\r\n type FormGroupSignal,\r\n} from '@mmstack/form-core';\r\nimport {\r\n injectValidators,\r\n Validators,\r\n type DateRange,\r\n type DateValidatorOptions,\r\n} from '@mmstack/form-validation';\r\nimport { tooltip } from '../util';\r\nimport {\r\n createDateState,\r\n type DateState,\r\n type DateStateOptions,\r\n} from './base-date';\r\n\r\nfunction equalDate(a: Date | null, b: Date | null): boolean {\r\n if (a === b) return true;\r\n if (!a || !b) return false;\r\n return a.getTime() === b.getTime();\r\n}\r\n\r\ntype DateRangeStateChildren<TDate = Date> = {\r\n start: DateState<DateRange<TDate>, TDate>;\r\n end: DateState<DateRange<TDate>, TDate>;\r\n};\r\n\r\n/**\r\n * Represents the reactive state for a date range input form group.\r\n *\r\n * Extends the base `FormGroupSignal<DateRange<TDate>>` and adds date-specific\r\n * properties like `placeholder` and enhanced `error`/`errorTooltip` signals derived\r\n * from the validation result's `.resolve()` method (when using the injected factory).\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.\r\n * @template TDate The type used for date values within the control (e.g., `Date`, Luxon `DateTime`, Moment). Defaults to `Date`.\r\n * @see FormGroupSignal\r\n * @see DateState\r\n */\r\nexport type DateRangeState<TParent = undefined, TDate = Date> = FormGroupSignal<\r\n DateRange<TDate>,\r\n DateRangeStateChildren<TDate>,\r\n TParent\r\n> & {\r\n /**\r\n * Signal holding the formatted error message suitable for tooltips or detailed display.\r\n * When multiple validation errors occur, this may contain all messages, while `error()` might show a summary.\r\n * (Generated by `injectCreateDateRangeState` using the validator's `.resolve()` method, or shortened by provided maxErrorHintLength).\r\n */\r\n errorTooltip: Signal<string>;\r\n /** signal for hint tooltip, default is shortened when hint is longer than 40 chars */\r\n hintTooltip: Signal<string>;\r\n /**\r\n * Signal holding the minimum selectable date (inclusive), derived from options.\r\n * Returns `null` if no minimum date is set. The value is always a `Date` object internally\r\n * for reliable comparison, regardless of the input option format (`string` or `Date`).\r\n * Useful for binding to date picker component properties (e.g., `[min]`).\r\n */\r\n min: Signal<Date | null>;\r\n /**\r\n * Signal holding the maximum selectable date (inclusive), derived from options.\r\n * Returns `null` if no maximum date is set. The value is always a `Date` object internally.\r\n * Useful for binding to date picker component properties (e.g., `[max]`).\r\n */\r\n max: Signal<Date | null>;\r\n /** Type discriminator for date-range controls. */\r\n type: 'date-range';\r\n};\r\n\r\n/**\r\n * Optional configuration for the `from/to` date state.\r\n * This allows you to customize the behavior of the `from` date input.\r\n * you can provide specific options such as placeholder.\r\n */\r\ntype ChildDateStateOptions<TDate = Date> = Omit<\r\n DateStateOptions<TDate>,\r\n | 'locale'\r\n | 'min'\r\n | 'max'\r\n | 'label'\r\n | 'disable'\r\n | 'readonly'\r\n | 'maxErrorHintLength'\r\n>;\r\n\r\n/**\r\n * Configuration options for the `createDateRangeState` function (the non-DI version).\r\n * Extends base form group options for a `DateRange<TDate>` value.\r\n *\r\n * @template TDate The type used for date values. Defaults to `Date`.\r\n * @see CreateFormGroupOptions\r\n * @see createDateRangeState\r\n */\r\nexport type DateRangeStateOptions<TDate = Date> = CreateFormGroupOptions<\r\n DateRange<TDate>,\r\n DateRangeStateChildren<TDate>\r\n> & {\r\n /**\r\n * The locale string (e.g., 'en-US', 'de-DE'). While required by this type,\r\n * it's primarily intended to be passed down internally when using the\r\n * dependency-injected factory (`injectCreateDateRangeState`) which obtains it from `LOCALE_ID`.\r\n * If using `createDateRangeState` directly, you must provide it manually, but its primary\r\n * use is within the validation message formatting handled by the injected system.\r\n */\r\n locale: string;\r\n /**\r\n * Optional function returning the minimum selectable date (inclusive).\r\n * Accepts a string (parsed as `new Date(string)`), a `Date` object, or `null`.\r\n * Populates the `min` signal on the `DateRangeState`.\r\n * Note: If using `injectCreateDateRangeState`, setting `min` via the `validation`\r\n * options is generally preferred as it enables validation messages.\r\n */\r\n min?: () => string | Date | null;\r\n /**\r\n * Optional function returning the maximum selectable date (inclusive).\r\n * Accepts a string (parsed as `new Date(string)`), a `Date` object, or `null`.\r\n * Populates the `max` signal on the `DateRangeState`.\r\n * Note: If using `injectCreateDateRangeState`, setting `max` via the `validation`\r\n * options is generally preferred as it enables validation messages.\r\n */\r\n max?: () => string | Date | null;\r\n /* shortens error/hint message & provides errorTooltip with full message, default 40 */\r\n maxErrorHintLength?: () => number;\r\n /** Optional configuration applied specifically to the 'start' date input control (e.g., setting a placeholder). */\r\n start?: ChildDateStateOptions<TDate>;\r\n /** Optional configuration applied specifically to the 'end' date input control (e.g., setting a placeholder). */\r\n end?: ChildDateStateOptions<TDate>;\r\n};\r\n\r\n/**\r\n * Creates the reactive state object (`DateRangeState`) for a date range form control\r\n * without relying on Angular's dependency injection for validation or locale.\r\n *\r\n * Internally creates a `formGroup` with `start` and `end` `DateState` children\r\n * using the non-DI `createDateState` function. It computes overall `min`/`max` signals\r\n * based directly on the provided `opt.min` and `opt.max` options.\r\n *\r\n * Prefer `injectCreateDateRangeState` for standard usage within Angular applications to leverage\r\n * automatic validation integration, localization, and enhanced error display.\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.\r\n * @template TDate The type used for date values. Defaults to `Date`.\r\n * @param value The initial date range value (`DateRange<TDate>`, e.g., `{ start: TDate|null, end: TDate|null }`),\r\n * or a `DerivedSignal` linking it to a parent state.\r\n * @param opt Configuration options (`DateRangeStateOptions`). Requires `locale`. Allows specifying options\r\n * for the child `start`/`end` inputs via `opt.start`/`opt.end`.\r\n * @returns A `DateRangeState` instance managing the control's reactive state.\r\n * @see injectCreateDateRangeState\r\n * @see DateRangeStateOptions\r\n * @see formGroup\r\n * @see createDateState\r\n */\r\nexport function createDateRangeState<TParent = undefined, TDate = Date>(\r\n value: DateRange<TDate> | DerivedSignal<TParent, DateRange<TDate>>,\r\n opt: DateRangeStateOptions<TDate>,\r\n): DateRangeState<TParent, TDate> {\r\n const valueSignal = isSignal(value) ? value : signal(value);\r\n\r\n const min = computed(\r\n () => {\r\n const m = opt.min?.();\r\n if (typeof m === 'string') return new Date(m);\r\n if (m instanceof Date) return m;\r\n return null;\r\n },\r\n {\r\n equal: equalDate,\r\n },\r\n );\r\n\r\n const max = computed(\r\n () => {\r\n const m = opt.max?.();\r\n if (typeof m === 'string') return new Date(m);\r\n if (m instanceof Date) return m;\r\n return null;\r\n },\r\n {\r\n equal: equalDate,\r\n },\r\n );\r\n\r\n const children: DateRangeStateChildren<TDate> = {\r\n start: createDateState(derived(valueSignal, 'start'), {\r\n ...opt.start,\r\n locale: opt.locale,\r\n }),\r\n end: createDateState(derived(valueSignal, 'end'), {\r\n ...opt.end,\r\n locale: opt.locale,\r\n }),\r\n };\r\n\r\n const state = formGroup<\r\n DateRange<TDate>,\r\n DateRangeStateChildren<TDate>,\r\n TParent\r\n >(valueSignal, children, opt);\r\n\r\n const { shortened: error, tooltip: errorTooltip } = tooltip(\r\n state.error,\r\n opt.maxErrorHintLength,\r\n );\r\n const { shortened: hint, tooltip: hintTooltip } = tooltip(\r\n state.hint,\r\n opt.maxErrorHintLength,\r\n );\r\n\r\n return {\r\n ...state,\r\n min,\r\n max,\r\n error,\r\n errorTooltip,\r\n hint,\r\n hintTooltip,\r\n type: 'date-range',\r\n };\r\n}\r\n\r\n/**\r\n * Configuration options specifically for the factory function returned by\r\n * `injectCreateDateRangeState`.\r\n *\r\n * Extends `DateRangeStateOptions` but omits properties handled internally by the factory\r\n * (`locale`, `required`, `validator`, `min`, `max`). Requires validation rules for the\r\n * *date range itself* (including overall `min`/`max` constraints which also drive the state's signals)\r\n * via the `validation` property using `DateValidatorOptions`.\r\n *\r\n * **Assumption:** It's expected that `@mmstack/form-validation` provides range-specific validation logic\r\n * (like ensuring start <= end) accessible via `validators.dateRange.all(...)` when interpreting\r\n * the provided `DateValidatorOptions`.\r\n *\r\n * @template TDate The type used for date values. Defaults to `Date`.\r\n * @see injectCreateDateRangeState\r\n * @see DateRangeStateOptions\r\n * @see DateValidatorOptions\r\n */\r\nexport type InjectedDateRangeStateOptions<TDate = Date> = Omit<\r\n DateRangeStateOptions<TDate>,\r\n 'locale' | 'required' | 'validator' | 'min' | 'max' // Handled by DI / validation prop\r\n> & {\r\n /**\r\n * Optional function returning `DateValidatorOptions`. Defines validation rules for the\r\n * *entire date range* object (e.g., required start/end, overall min/max constraints,\r\n * potentially range validity like start <= end if supported by `validators.dateRange.all`).\r\n * The `min` and `max` specified here also populate the `DateRangeState`'s `min`/`max` signals.\r\n * @example validation: () => ({ required: true, min: new Date(), range: true }) // Assuming 'range' rule exists\r\n */\r\n validation?: () => DateValidatorOptions; // Uses options for single dates, interpreted for range\r\n};\r\n\r\n/**\r\n * Creates and returns a factory function for generating `DateRangeState` instances.\r\n *\r\n * This factory utilizes Angular's dependency injection (`injectValidators`, `LOCALE_ID`)\r\n * to automatically handle validation configuration (expecting range-specific rules like start <= end\r\n * via `validators.dateRange.all` interpreting `DateValidatorOptions`), localization, and enhanced\r\n * error message formatting (`error`/`errorTooltip`). The overall `min`/`max` signals on the state\r\n * are also automatically derived from the `min`/`max` constraints provided within the `validation` options.\r\n *\r\n * This is the **recommended** way to create `DateRangeState` within an Angular application.\r\n *\r\n * @returns A factory function: `(value: DateRange<TDate> | DerivedSignal<TParent, DateRange<TDate>>, opt?: InjectedDateRangeStateOptions<TDate>) => DateRangeState<TParent, TDate>`.\r\n * @template TDate The type used for date values. Defaults to `Date`. Must match type used in `provideValidatorConfig`.\r\n * @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.\r\n *\r\n * @example\r\n * // Within an injection context:\r\n * const createDateRange = injectCreateDateRangeState();\r\n * // Assuming DateRange = { start: Date | null, end: Date | null }\r\n *\r\n * const vacationDatesState = createDateRange({ start: null, end: null }, {\r\n * label: () => 'Vacation Dates',\r\n * start: { placeholder: () => 'Departure Date' }, // Child control options\r\n * end: { placeholder: () => 'Return Date' },\r\n * validation: () => ({ // Validation for the range\r\n * required: true, // Requires both start and end\r\n * min: new Date(), // Overall minimum date for picker & validation\r\n * // Assumes validation library has a rule triggered by DateValidatorOptions\r\n * // that checks if start <= end, potentially enabled by default or specific flag\r\n * })\r\n * });\r\n *\r\n * // Template binds to child states for inputs:\r\n * // <mat-date-range-input [formGroup]=\"vacationDatesFormGroup\"> * // <input matStartDate [(ngModel)]=\"vacationDatesState.children().start.value\" [placeholder]=\"vacationDatesState.children().start.placeholder()\">\r\n * // <input matEndDate [(ngModel)]=\"vacationDatesState.children().end.value\" [placeholder]=\"vacationDatesState.children().end.placeholder()\">\r\n * // </mat-date-range-input>\r\n * // <mat-date-range-picker [min]=\"vacationDatesState.min()\" [max]=\"vacationDatesState.max()\"></mat-date-range-picker>\r\n */\r\nexport function injectCreateDateRangeState() {\r\n const locale = inject(LOCALE_ID);\r\n const v = injectValidators();\r\n\r\n /**\r\n * Factory function (returned by `injectCreateDateRangeState`) that creates `DateRangeState`.\r\n * Integrates with `@mmstack/form-validation` via DI for validation (using `validators.dateRange.all`),\r\n * localization, and enhanced error display. Derives overall `min`/`max` signals from validation options.\r\n *\r\n * @template TDate The type for date values used by this control. Defaults to `Date`.\r\n * @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.\r\n * @param value The initial date range value (`DateRange<TDate>`), or a `DerivedSignal` linking it.\r\n * @param opt Configuration options (`InjectedDateRangeStateOptions`), including options for child\r\n * `start`/`end` controls and the `validation` property (accepting `DateValidatorOptions`\r\n * to be interpreted for range validation by `validators.dateRange.all`).\r\n * @returns A `DateRangeState` instance managing the control's reactive state.\r\n */\r\n return <TDate = Date, TParent = undefined>(\r\n value: DateRange<TDate> | DerivedSignal<TParent, DateRange<TDate>>,\r\n opt?: InjectedDateRangeStateOptions<TDate>,\r\n ): DateRangeState<TParent, TDate> => {\r\n const validators = v as Validators<TDate>;\r\n\r\n const validationOptions = computed(() => ({\r\n messageOptions: {\r\n label: opt?.label?.(),\r\n },\r\n ...opt?.validation?.(),\r\n }));\r\n\r\n const min = computed(() => validationOptions().min ?? null);\r\n const max = computed(() => validationOptions().max ?? null);\r\n\r\n const validator = computed(() =>\r\n validators.dateRange.all(validationOptions()),\r\n );\r\n\r\n const state = createDateRangeState<TParent, TDate>(value, {\r\n ...opt,\r\n locale,\r\n min,\r\n max,\r\n validator,\r\n required: computed(() => validationOptions().required ?? false),\r\n });\r\n\r\n const resolvedError = computed(() => {\r\n const merger = validator();\r\n\r\n return merger.resolve(state.errorTooltip() || state.error());\r\n });\r\n\r\n return {\r\n ...state,\r\n error: computed(() => resolvedError().error),\r\n errorTooltip: computed(() => resolvedError().tooltip),\r\n };\r\n };\r\n}\r\n","import { computed, inject, LOCALE_ID } from '@angular/core';\r\nimport {\r\n defaultToDate,\r\n injectValidators,\r\n type Validators,\r\n} from '@mmstack/form-validation';\r\nimport { type DerivedSignal } from '@mmstack/primitives';\r\nimport {\r\n createDateState,\r\n type DateState,\r\n type DateStateOptions,\r\n type InjectedDateStateOptions,\r\n} from './base-date';\r\n\r\nfunction setDay(date: Date | null, extractFrom: Date | null): Date | null {\r\n if (!date) return null;\r\n const next = new Date(extractFrom || Date.now());\r\n next.setHours(\r\n date.getHours(),\r\n date.getMinutes(),\r\n date.getSeconds(),\r\n date.getMilliseconds(),\r\n );\r\n return next;\r\n}\r\n\r\n/**\r\n * Represents the reactive state for a time input form control.\r\n *\r\n * Extends the base `DateState` angular defaults to todays date, but varies the time if no date is provided\r\n * min and max values adapt automatically to the dates day\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.\r\n * @template TDate The type used for date values within the control (e.g., `Date`, Luxon `DateTime`, Moment). Defaults to `Date`.\r\n * @see DateState\r\n */\r\nexport type TimeState<TParent = undefined, TDate = Date> = Omit<\r\n DateState<TParent, TDate>,\r\n 'type'\r\n> & {\r\n type: 'time';\r\n};\r\n\r\n/**\r\n * @see DateStateOptions\r\n */\r\nexport type TimeStateOptions<TDate = Date> = DateStateOptions<TDate> & {\r\n /**\r\n * A function to convert the date value to a standard `Date` object.\r\n * Defaults to `defaultToDate`, which converts `TDate` to a `Date`.\r\n */\r\n toDate?: (date: TDate | null) => Date | null;\r\n};\r\n\r\n/**\r\n * @see InjectedDateStateOptions\r\n */\r\nexport type InjectedTimeStateOptions<TDate = Date> =\r\n InjectedDateStateOptions<TDate>;\r\n\r\n/**\r\n * Creates the reactive state object (`TimeState`) for a time form control\r\n * without relying on Angular's dependency injection for validation or locale.\r\n * Includes computed signals for `min` and `max` date constraints based directly on the provided options.\r\n * If provided the day will shift to the current values date, in order to only validate the time part.\r\n * Angular defaults to today's date, but varies the time if no date is provided.\r\n *\r\n * Use this function directly only if creating state outside an injection context\r\n * or providing a fully custom `validator`, `locale`, `min`, and `max` manually via `opt`.\r\n * Prefer `injectCreateTimeState` for standard usage within Angular applications.\r\n *\r\n * Note: The `errorTooltip` signal returned by this function will initially be empty.\r\n * Enhanced tooltip generation based on multiple errors is handled by `injectCreateTimeState`.\r\n *\r\n * @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.\r\n * @template TDate The type used for date values. Defaults to `Date`.\r\n * @param value The initial date value (`TDate | null`), or a `DerivedSignal` linking it to a parent state.\r\n * @param opt Configuration options (`TimeStateOptions`), requires `locale`, optionally `validator`, `placeholder`, `min`, `max`.\r\n * @returns A `TimeState` instance managing the control's reactive state, including `min` and `max` signals.\r\n * @see injectCreateTimeState\r\n * @see createDateState\r\n */\r\nexport function createTimeState<TParent = undefined, TDate = Date>(\r\n value: TDate | null | DerivedSignal<TParent, TDate | null>,\r\n opt: TimeStateOptions<TDate>,\r\n): TimeState<TParent, TDate> {\r\n const dateState = createDateState<TParent, TDate>(value, opt);\r\n\r\n const toDate = opt.toDate ?? defaultToDate;\r\n\r\n const dateValue = computed(() => toDate(dateState.value()), {\r\n equal: (a, b) => {\r\n if (!a && !b) return true;\r\n if (!a || !b) return false;\r\n return a.getTime() === b.getTime();\r\n },\r\n });\r\n\r\n return {\r\n ...dateState,\r\n min: computed(() => setDay(dateState.min(), dateValue())),\r\n max: computed(() => setDay(dateState.max(), dateValue())),\r\n type: 'time',\r\n };\r\n}\r\n\r\n/**\r\n * Creates and returns a factory function for generating `TimeState` instances.\r\n *\r\n * This factory utilizes Angular's dependency injection (`injectValidators`, `LOCALE_ID`)\r\n * to automatically handle:\r\n * - Validation configuration via `DateValidatorOptions` (passed to the `validation` option).\r\n * - Localization for default validation error messages.\r\n * - Enhanced error message formatting (splitting merged errors into `error` and `errorTooltip` signals).\r\n * - Populating the `min` and `max` signals on `TimeState` based on the constraints specified\r\n * within the `validation` options object.\r\n * - Configuration of date handling based on `provideValidatorConfig`.\r\n *\r\n * This is the **recommended** way to create `TimeState` within an Angular application.\r\n *\r\n * @returns A factory function: `(value: TDate | null | DerivedSignal<TParent, TDate | null>, opt?: InjectedTimeStateOptions<TDate>) => TimeState<TParent, TDate>`.\r\n * @template TDate The type used for date values passed to the factory (e.g., `Date`, Luxon `DateTime`).\r\n * Must match the `TDate` used during `provideValidatorConfig` if custom date handling is required. Defaults to `Date`.\r\n *\r\n * @example\r\n * // Within an injection context:\r\n * const createTime = injectCreateTimeState();\r\n * // If using Luxon: const createTime = injectCreateTimeState<DateTime>();\r\n *\r\n * const eventTimeState = createTime(null, {\r\n * label: () => 'Event Time',\r\n * placeholder: () => 'Select event time',\r\n * validation: () => ({ // Provide DateValidatorOptions here\r\n * required: true,\r\n * min: new Date(), // Sets min validation AND state.min() signal\r\n * })\r\n * });\r\n *\r\n * // Template can use min/max signals for datepicker limits:\r\n * // <mat-timepicker-toggle [for]=\"picker\" [disabled]=\"eventTimeState.disabled()\"></mat-datepicker-toggle>\r\n * // <input matInput [matTimepicker]=\"picker\"\r\n * // [min]=\"eventTimeState.min()\"\r\n * // [max]=\"eventTimeState.max()\"\r\n * // [(ngModel)]=\"eventTimeState.value\" ... >\r\n * // <mat-timepicker #picker></mat-datepicker>\r\n * // <mat-error><span [matTooltip]=\"eventTimeState.errorTooltip()\">{{ eventTimeState.error() }}</span></mat-error>\r\n */\r\nexport function injectCreateTimeState() {\r\n const v = injectValidators();\r\n const locale = inject(LOCALE_ID);\r\n\r\n /**\r\n * Factory function (returned by `injectCreateTimeState`) that creates `TimeState`.\r\n * Integrates with `@mmstack/form-validation` via DI for validation and localization.\r\n * Handles splitting of multiple validation errors into `error` and `errorTooltip`.\r\n * Derives `min`/`max` state signals from `validation` options.\r\n *\r\n * @template TDate The type for date values used by this control. Defaults to `Date`.\r\n * @template TParent The type of the parent form group's value, if applicable. Defaults to `undefined`.\r\n * @param value The initial date value (`TDate | null`), or a `DerivedSignal` linking it to a parent state.\r\n * @param opt Configuration options (`InjectedTimeStateOptions`), including the `validation` property\r\n * which accepts `DateValidatorOptions` (used for both validation rules and setting state's `min`/`max` signals).\r\n * @returns A `TimeState` instance managing the control's reactive state.\r\n */\r\n return <TDate = Date, TParent = undefined>(\r\n value: TDate | null | DerivedSignal<TParent, TDate | null>,\r\n opt?: InjectedTimeStateOptions<TDate>,\r\n ) => {\r\n const validators = v as Validators<TDate>;\r\n const validationOptions = computed(() => ({