UNPKG

@proangular/pro-form

Version:

A predefined set of reactive and reusable form input components based on Angular Material.

1 lines 86 kB
{"version":3,"file":"proangular-pro-form.mjs","sources":["../../../src/app/public/input.directive.ts","../../../src/app/public/input-checkbox/input-checkbox.component.ts","../../../src/app/public/input-checkbox/input-checkbox.component.html","../../../src/app/public/input-chips/input-chip.component.ts","../../../src/app/public/input-chips/input-chips.component.ts","../../../src/app/public/input-chips/input-chips.component.html","../../../src/app/public/input-loading/loading-input.component.ts","../../../src/app/public/input/input.component.ts","../../../src/app/public/input/input.component.html","../../../src/app/public/utilities/type-checks.ts","../../../src/app/public/utilities/custom-validators.ts","../../../src/app/public/pipes/date-time.pipe.ts","../../../src/app/public/input-datepicker/input-datepicker.component.ts","../../../src/app/public/input-datepicker/input-datepicker.component.html","../../../src/app/public/input-dropdown/input-dropdown-option.component.ts","../../../src/app/public/input-dropdown/input-dropdown-option-group.component.ts","../../../src/app/public/input-dropdown/input-dropdown.component.ts","../../../src/app/public/input-dropdown/input-dropdown.component.html","../../../src/app/public/input-radio/input-radio-option.component.ts","../../../src/app/public/input-radio/input-radio.component.ts","../../../src/app/public/input-radio/input-radio.component.html","../../../src/app/public/input-textarea/input-textarea.component.ts","../../../src/app/public/input-textarea/input-textarea.component.html","../../../src/app/public/input-timepicker/input-timepicker.component.ts","../../../src/app/public/input-timepicker/input-timepicker.component.html","../../../src/app/public/input-toggle/input-toggle.component.ts","../../../src/app/public/input-toggle/input-toggle.component.html","../../../src/app/public/form.directive.ts","../../../src/app/public/public.ts","../../../src/app/public/proangular-pro-form.ts"],"sourcesContent":["import {\n Directive,\n ElementRef,\n Input,\n forwardRef,\n inject,\n} from '@angular/core';\nimport {\n ControlValueAccessor,\n FormControl,\n NG_VALUE_ACCESSOR,\n NgControl,\n Validators,\n} from '@angular/forms';\n\nlet id = 0;\nconst rF = { required: false };\n\n@Directive({\n providers: [\n {\n multi: true,\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => InputDirective),\n },\n ],\n})\nexport abstract class InputDirective<T> implements ControlValueAccessor {\n public constructor() {\n if (this.ngControl) {\n this.ngControl.valueAccessor = this;\n }\n }\n\n public elementRef = inject(ElementRef);\n public ngControl = inject(NgControl, { self: true, optional: true });\n\n public get formControl(): FormControl<T> {\n if (!this.ngControl) {\n throw new Error('Input requires a NgControl to be provided.');\n }\n\n return this.ngControl.control as FormControl<T>;\n }\n\n @Input(rF) public hint: string | number | null = null;\n @Input(rF) public id = `pro-input-${++id}`;\n @Input(rF) public placeholder: string | null = null;\n @Input({ required: true }) public label!: string;\n\n public get isRequired(): boolean {\n return this.formControl.hasValidator(Validators.required);\n }\n\n public onChange: (value: T) => void = () => undefined;\n public onTouched: () => void = () => undefined;\n public writeValue: (value: T) => void = () => undefined;\n\n public registerOnChange(fn: (value: T) => void): void {\n this.onChange = fn;\n }\n\n public registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n public scrollIntoView(options?: ScrollIntoViewOptions): void {\n const defaultOptions: ScrollIntoViewOptions = { behavior: 'smooth' };\n this.elementRef.nativeElement.scrollIntoView({\n ...defaultOptions,\n ...options,\n });\n }\n}\n","import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';\nimport { startWith } from 'rxjs';\n\nimport { CommonModule } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n OnInit,\n Output,\n} from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\nimport { MatFormFieldModule } from '@angular/material/form-field';\n\nimport { InputDirective } from '../input.directive';\n\nconst rF = { required: false };\n\n@UntilDestroy()\n@Component({\n selector: 'pro-input-checkbox',\n templateUrl: './input-checkbox.component.html',\n styleUrls: ['./input-checkbox.component.scss'],\n standalone: true,\n imports: [\n CommonModule,\n FormsModule,\n MatCheckboxModule,\n MatFormFieldModule,\n ReactiveFormsModule,\n ],\n changeDetection: ChangeDetectionStrategy.Default,\n})\nexport class InputCheckboxComponent\n extends InputDirective<boolean | null>\n implements OnInit\n{\n @Input(rF)\n public labelPosition: 'before' | 'after' = 'after';\n\n // eslint-disable-next-line @angular-eslint/no-output-native\n @Output() public readonly change = new EventEmitter<boolean>();\n\n public ngOnInit(): void {\n this.formControl.valueChanges\n .pipe(startWith(this.formControl.value), untilDestroyed(this))\n .subscribe((isChecked) => {\n if (this.formControl.disabled) {\n return;\n }\n\n if (this.isRequired && !isChecked) {\n this.formControl.setErrors({ required: true }, { emitEvent: false });\n this.formControl.setValue(null, { emitEvent: false });\n } else if (this.isRequired && isChecked) {\n this.formControl.setErrors(null);\n }\n\n if (isChecked !== null) {\n this.change.emit(isChecked);\n }\n });\n }\n}\n","<mat-checkbox [formControl]=\"formControl\" [labelPosition]=\"labelPosition\">{{\n label + (isRequired ? '*' : '')\n}}</mat-checkbox>\n@if (formControl.invalid && formControl.touched) {\n <mat-error>\n @if (formControl.hasError('required')) {\n {{ label }} is required.\n }\n </mat-error>\n}\n","import { coerceElement } from '@angular/cdk/coercion';\nimport { Component, ElementRef, inject } from '@angular/core';\nimport { MatChip } from '@angular/material/chips';\n\n@Component({\n selector: 'pro-input-chip',\n template: `<ng-content></ng-content>`,\n standalone: true,\n})\nexport class InputChipComponent extends MatChip {\n private readonly elementRef = inject(ElementRef<HTMLElement>);\n\n public get element(): HTMLElement {\n return coerceElement(this.elementRef);\n }\n}\n","import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { CommonModule } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n ContentChildren,\n Input,\n QueryList,\n ViewChild,\n} from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { MatChipListbox, MatChipsModule } from '@angular/material/chips';\nimport { MatFormFieldModule } from '@angular/material/form-field';\n\nimport { InputDirective } from '../input.directive';\nimport { InputChipComponent } from './input-chip.component';\n\nconst rF = { required: false };\nconst rFc = { required: false, transform: coerceBooleanProperty };\n\n@Component({\n selector: 'pro-input-chips',\n templateUrl: './input-chips.component.html',\n styleUrl: './input-chips.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n CommonModule,\n FormsModule,\n MatChipsModule,\n MatFormFieldModule,\n ReactiveFormsModule,\n ],\n standalone: true,\n})\nexport class InputChipsComponent extends InputDirective<string> {\n @ContentChildren(InputChipComponent) public readonly chips =\n new QueryList<InputChipComponent>();\n @ViewChild(MatChipListbox) public readonly matChipListbox?: MatChipListbox;\n\n @Input(rF) public max: number | undefined;\n\n @Input(rFc) public multiple = false;\n\n @Input(rF) public compareWith: MatChipListbox['compareWith'] = (\n optionValue,\n selectedValue,\n ) => {\n return (\n JSON.stringify(optionValue) === JSON.stringify(selectedValue) ||\n optionValue === selectedValue\n );\n };\n}\n","<mat-label>{{ label }}</mat-label>\n<mat-chip-listbox\n [compareWith]=\"compareWith\"\n [formControl]=\"formControl\"\n [multiple]=\"multiple\"\n>\n @for (chip of chips; track chip) {\n <mat-chip-option [disabled]=\"chip.disabled\" [value]=\"chip.value\">{{\n chip.element.textContent\n }}</mat-chip-option>\n }\n</mat-chip-listbox>\n@if (formControl.invalid && formControl.touched) {\n <mat-error>\n @if (formControl.hasError('required')) {\n {{ label }} is required.\n } @else if (formControl.hasError('maxlength')) {\n {{ label }} cannot exceed\n {{ formControl.errors?.['maxlength'].requiredLength }} selections.\n } @else if (formControl.hasError('minlength')) {\n {{ label }} must have at least\n {{ formControl.errors?.['minlength'].requiredLength }} selections.\n }\n </mat-error>\n}\n","import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';\nimport { interval } from 'rxjs';\n\nimport { CommonModule } from '@angular/common';\nimport { Component, Input, OnInit } from '@angular/core';\nimport { FormControl, ReactiveFormsModule } from '@angular/forms';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatInputModule } from '@angular/material/input';\n\nimport { InputAppearance } from '../types';\n\nconst rF = { required: false };\n\n@UntilDestroy()\n@Component({\n selector: 'pro-input-loading',\n template: `\n <mat-form-field [appearance]=\"appearance\">\n <input [formControl]=\"formControl\" matInput type=\"text\" />\n @if (hint) {\n <mat-hint [title]=\"hint\">{{ hint }}</mat-hint>\n }\n </mat-form-field>\n `,\n styles: [':host { width: 100%; }'],\n imports: [\n CommonModule,\n MatFormFieldModule,\n MatInputModule,\n ReactiveFormsModule,\n ],\n standalone: true,\n})\nexport class InputLoadingComponent implements OnInit {\n @Input(rF) public appearance: InputAppearance = 'outline';\n @Input(rF) public hint?: string;\n @Input(rF) public label?: string;\n\n protected readonly formControl = new FormControl<string | null>(null);\n protected loadingText = 'Loading';\n\n public ngOnInit(): void {\n this.formControl.disable();\n\n interval(500)\n .pipe(untilDestroyed(this))\n .subscribe(() => {\n if (this.loadingText === 'Loading') {\n this.loadingText = this.label\n ? `Loading \"${this.label}\".`\n : 'Loading.';\n } else if (this.loadingText.endsWith('...')) {\n this.loadingText = this.label ? `Loading \"${this.label}\"` : 'Loading';\n } else {\n this.loadingText = this.loadingText + '.';\n }\n this.formControl.setValue(this.loadingText);\n });\n }\n}\n","import { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatInputModule } from '@angular/material/input';\n\nimport { InputLoadingComponent } from '../input-loading/loading-input.component';\nimport { InputDirective } from '../input.directive';\nimport { InputAppearance, InputAutocomplete, InputType } from '../types';\n\nconst rF = { required: false };\n\n@Component({\n selector: 'pro-input',\n templateUrl: './input.component.html',\n standalone: true,\n imports: [\n CommonModule,\n InputLoadingComponent,\n MatFormFieldModule,\n MatInputModule,\n ReactiveFormsModule,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class InputComponent extends InputDirective<string> {\n @Input(rF) public appearance: InputAppearance = 'outline';\n @Input(rF) public autocomplete: InputAutocomplete = 'off';\n\n @Input(rF) public set max(value: number | string) {\n this.setMax(value);\n }\n public get max(): number | undefined {\n return this.getMax();\n }\n #max: number | undefined;\n\n @Input(rF) public set min(value: number | string) {\n this.setMin(value);\n }\n public get min(): number | undefined {\n return this.getMin();\n }\n #min: number | undefined;\n\n @Input(rF) public set maxLength(value: number | string) {\n this.setMaxLength(value);\n }\n public get maxLength(): number | undefined {\n return this.#maxLength;\n }\n #maxLength: number | undefined;\n\n @Input(rF) public set minLength(value: number | string) {\n this.setMinLength(value);\n }\n public get minLength(): number | undefined {\n return this.#minLength;\n }\n #minLength: number | undefined;\n\n @Input(rF) public name: string | undefined;\n\n @Input(rF) public set step(value: number | string) {\n const stepParsed = Number(value);\n if (isNaN(stepParsed)) {\n this.#step = undefined;\n return;\n }\n\n this.#step = stepParsed;\n }\n public get step(): number | undefined {\n if (this.type !== 'number') {\n return undefined;\n }\n return this.#step;\n }\n #step: number | undefined;\n\n @Input(rF) public type: InputType = 'text';\n\n private getMax(): number | undefined {\n if (this.type !== 'number') {\n return undefined;\n }\n return this.#max;\n }\n\n private getMin(): number | undefined {\n if (this.type !== 'number') {\n return undefined;\n }\n return this.#min;\n }\n\n private setMax(value: number | string): void {\n const maxParsed = Number(value);\n if (isNaN(maxParsed)) {\n this.#max = undefined;\n return;\n }\n this.#max = maxParsed;\n }\n\n private setMaxLength(value: number | string): void {\n const maxLengthParsed = Number(value);\n if (isNaN(maxLengthParsed)) {\n this.#maxLength = undefined;\n return;\n }\n this.#maxLength = maxLengthParsed;\n }\n\n private setMin(value: number | string): void {\n const minParsed = Number(value);\n if (isNaN(minParsed)) {\n this.#min = undefined;\n return;\n }\n\n this.#min = minParsed;\n }\n\n private setMinLength(value: number | string): void {\n const minLengthParsed = Number(value);\n if (isNaN(minLengthParsed)) {\n this.#minLength = undefined;\n return;\n }\n\n this.#minLength = minLengthParsed;\n }\n}\n","@if (formControl) {\n <mat-form-field [appearance]=\"appearance\">\n <mat-label>{{ label }}</mat-label>\n <input\n [attr.step]=\"step\"\n [autocomplete]=\"autocomplete\"\n [formControl]=\"formControl\"\n [id]=\"id\"\n [name]=\"name || id\"\n [placeholder]=\"placeholder || ''\"\n [type]=\"type\"\n matInput\n />\n <mat-hint [title]=\"hint\">{{ hint }}</mat-hint>\n @if (formControl.invalid && formControl.touched) {\n <mat-error>\n @if (formControl.hasError('required')) {\n {{ label }} is required.\n } @else if (formControl.hasError('min')) {\n {{ label }} must be at least {{ formControl.errors?.['min'].min }}.\n } @else if (formControl.hasError('max')) {\n {{ label }} cannot exceed {{ formControl.errors?.['max'].max }}.\n } @else if (formControl.hasError('minlength')) {\n {{ label }} must be at least\n {{ formControl.errors?.['minlength'].requiredLength }} characters.\n } @else if (formControl.hasError('maxlength')) {\n {{ label }} cannot exceed\n {{ formControl.errors?.['maxlength'].requiredLength }} characters.\n } @else if (formControl.hasError('email')) {\n {{ label }} must be a valid email address.\n } @else if (formControl.hasError('nonNumber')) {\n {{ label }} must be a number.\n } @else if (formControl.hasError('wholeNumber')) {\n {{ label }} must be a whole number.\n }\n </mat-error>\n }\n </mat-form-field>\n} @else {\n <pro-input-loading [label]=\"label\" />\n}\n","/**\n * Validate that the value is an empty value.\n *\n * @param value The value to check.\n * @returns True if the value is an empty value, false otherwise.\n */\nexport function isEmptyValue(value: unknown): value is null | undefined {\n return value === null || value === undefined;\n}\n\n/**\n * Validate that the value is a non-empty value.\n *\n * @param value The value to check.\n * @returns True if the value is a non-empty value, false otherwise.\n */\nexport function isNonEmptyValue<T>(value: T): value is NonNullable<T> {\n return value !== null && value !== undefined;\n}\n\n/**\n * Validate that the value is a number.\n *\n * @param value The value to check.\n * @returns True if the value is a number, false otherwise.\n */\nexport function isNumber(value: unknown): value is number {\n return typeof value === 'number' && !isNaN(value);\n}\n\n/**\n * Validate that the value is a string. This includes both primitive strings\n * and string objects.\n *\n * @param value The value to check.\n * @returns True if the value is a string, false otherwise.\n */\nexport function isString(value: unknown): value is string {\n return typeof value === 'string' || value instanceof String;\n}\n\n/**\n * Validate that the value is an empty string. An empty string is a string that\n * contains no characters.\n *\n * @param value The value to check.\n * @returns True if the value is an empty string, false otherwise.\n */\nexport function isEmptyString(value: unknown): value is '' {\n return value === '';\n}\n\n/**\n * Validate that the value is a blank string. A blank string is a string that\n * contains only whitespace characters.\n *\n * @param value\n * @returns\n */\nexport function isWhitespaceString(value: unknown): boolean {\n return typeof value === 'string' && value.trim() === '';\n}\n\n/**\n * Validate that the value is a string that is non-empty.\n *\n * @param value The value to check.\n * @returns True if the value is a string that is non-empty, false otherwise.\n */\nexport function isNonEmptyString(value: unknown): value is string {\n return isString(value) && !isWhitespaceString(value);\n}\n","import { DateTime } from 'luxon';\n\nimport { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';\n\nimport { isNumber } from '../utilities';\n\nexport class CustomValidators {\n /**\n * Validates that a given DateTime value does not exceed a maximum allowed DateTime.\n *\n * @param max The maximum allowed DateTime.\n * @returns A validator function that checks if the value exceeds the max DateTime.\n */\n public static maxDateTime(max: DateTime): ValidatorFn {\n return (control: AbstractControl): ValidationErrors | null => {\n const value = control.value;\n return value instanceof DateTime && value.isValid && value > max\n ? { max: { max, actual: value } }\n : null;\n };\n }\n\n /**\n * Validates that a given DateTime value is not earlier than a minimum allowed DateTime.\n *\n * @param min The minimum allowed DateTime.\n * @returns A validator function that checks if the value is below the min DateTime.\n */\n public static minDateTime(min: DateTime): ValidatorFn {\n return (control: AbstractControl): ValidationErrors | null => {\n const value = control.value;\n return value instanceof DateTime && value.isValid && value < min\n ? { min: { min, actual: value } }\n : null;\n };\n }\n\n /**\n * Validates that a given value is **not** a string.\n *\n * @param control The form control being validated.\n * @returns A validation error if the value is a string, otherwise null.\n */\n public static nonString(control: AbstractControl): ValidationErrors | null {\n return typeof control.value !== 'string' ? null : { nonString: true };\n }\n\n /**\n * Validates that a given value is a number.\n *\n * @returns A validator function that checks if the value is a number.\n */\n public static isNumber(): ValidatorFn {\n return (control: AbstractControl): ValidationErrors | null => {\n return isNumber(control.value) ? null : { nonNumber: true };\n };\n }\n\n /**\n * Validates that a given value is a whole number (integer).\n *\n * @returns A validator function that checks if the value is a whole number.\n */\n public static wholeNumber(): ValidatorFn {\n return (control: AbstractControl): ValidationErrors | null => {\n if (!isNumber(control.value)) {\n return null;\n }\n return Number.isInteger(control.value) ? null : { wholeNumber: true };\n };\n }\n}\n","import { DateTime } from 'luxon';\n\nimport { Pipe, PipeTransform } from '@angular/core';\n\nimport { DateTimeFormat } from '../types';\nimport { isNonEmptyValue } from '../utilities';\n\n@Pipe({ name: 'dateTime', standalone: true })\nexport class DateTimePipe implements PipeTransform {\n private readonly defaultFormat: DateTimeFormat = 'MM/dd/yyyy';\n\n /** Transform DateTime object into a readable string. */\n public transform(\n value: DateTime | null | undefined | unknown,\n format: DateTimeFormat = this.defaultFormat,\n ): string {\n if (!isNonEmptyValue(value) || !(value instanceof DateTime)) {\n return '';\n }\n\n if (format === 'relative-date') {\n return this.getRelativeDate(value);\n } else if (format === 'relative-datetime') {\n return this.getRelativeDateTime(value);\n }\n\n return value.toFormat(format);\n }\n\n private getRelativeDate(value: DateTime): string {\n const relativeTime = value.toRelative();\n if (!relativeTime) {\n throw new Error(\n `There was an issue converting the datetime object \"${value.toString()}\" to a relative time.`,\n );\n }\n\n const now = DateTime.local();\n const hoursDiff = now.diff(value).as('hours');\n\n if (hoursDiff < 24) {\n return 'Today';\n } else if (hoursDiff < 48) {\n return 'Yesterday';\n } else if (hoursDiff > 168) {\n return value.toFormat(this.defaultFormat);\n }\n\n return relativeTime;\n }\n\n private getRelativeDateTime(value: DateTime): string {\n const time = value.toFormat('h:mm a');\n return `${this.getRelativeDate(value)}, ${time}`;\n }\n}\n","import { DateTime } from 'luxon';\n\nimport { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { provideLuxonDateAdapter } from '@angular/material-luxon-adapter';\nimport { MatDatepickerModule } from '@angular/material/datepicker';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatInputModule } from '@angular/material/input';\n\nimport { InputLoadingComponent } from '../input-loading/loading-input.component';\nimport { InputDirective } from '../input.directive';\nimport { DateTimePipe } from '../pipes';\nimport { InputAppearance } from '../types';\n\nconst rF = { required: false };\n\n@Component({\n selector: 'pro-input-datepicker',\n templateUrl: './input-datepicker.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n CommonModule,\n DateTimePipe,\n InputLoadingComponent,\n MatDatepickerModule,\n MatFormFieldModule,\n MatInputModule,\n ReactiveFormsModule,\n ],\n providers: [provideLuxonDateAdapter()],\n standalone: true,\n})\nexport class InputDatepickerComponent extends InputDirective<DateTime> {\n @Input(rF) public appearance: InputAppearance = 'outline';\n @Input(rF) public max: DateTime | undefined;\n @Input(rF) public min: DateTime | undefined;\n}\n","@if (formControl) {\n <mat-form-field [appearance]=\"appearance\">\n <mat-label>{{ label }}</mat-label>\n <input\n [formControl]=\"formControl\"\n [matDatepicker]=\"datepicker\"\n [max]=\"max\"\n [min]=\"min\"\n [placeholder]=\"placeholder ?? ''\"\n matInput\n />\n <mat-datepicker-toggle [for]=\"datepicker\" matSuffix />\n <mat-datepicker #datepicker />\n <mat-hint [title]=\"hint\">{{ hint }}</mat-hint>\n @if (formControl.invalid && formControl.touched) {\n <mat-error>\n @if (formControl.hasError('required')) {\n {{ label }} is required.\n } @else if (formControl.hasError('min')) {\n {{ label }} must be at least\n {{ formControl.errors?.['min'].min | dateTime: 'MM/dd/yyyy' }}.\n } @else if (formControl.hasError('max')) {\n {{ label }} cannot exceed\n {{ formControl.errors?.['max'].max | dateTime: 'MM/dd/yyyy' }}.\n }\n </mat-error>\n }\n </mat-form-field>\n} @else {\n <pro-input-loading [label]=\"label\" />\n}\n","import { coerceElement } from '@angular/cdk/coercion';\nimport {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n inject,\n} from '@angular/core';\nimport { MatOption } from '@angular/material/core';\n\n@Component({\n selector: 'pro-input-dropdown-option',\n template: `<ng-content></ng-content>`,\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: true,\n})\nexport class InputDropdownOptionComponent extends MatOption {\n private readonly elementRef = inject(ElementRef<HTMLElement>);\n\n public get element(): HTMLElement {\n return coerceElement(this.elementRef);\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ContentChildren,\n Input,\n QueryList,\n} from '@angular/core';\n\nimport { InputDropdownOptionComponent } from './input-dropdown-option.component';\n\n@Component({\n selector: 'pro-input-dropdown-option-group',\n template: `<ng-content></ng-content>`,\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: true,\n})\nexport class InputDropdownOptionGroupComponent {\n @Input({ required: true }) public label!: string;\n\n @ContentChildren(InputDropdownOptionComponent)\n public readonly options: QueryList<InputDropdownOptionComponent> =\n new QueryList<InputDropdownOptionComponent>();\n}\n","import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { CommonModule } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n ContentChildren,\n Input,\n QueryList,\n ViewChild,\n} from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport {\n MatOption,\n MatSelect,\n MatSelectModule,\n} from '@angular/material/select';\n\nimport { InputLoadingComponent } from '../input-loading/loading-input.component';\nimport { InputDirective } from '../input.directive';\nimport { InputAppearance } from '../types';\nimport { InputDropdownOptionGroupComponent } from './input-dropdown-option-group.component';\nimport { InputDropdownOptionComponent } from './input-dropdown-option.component';\n\nconst rF = { required: false };\nconst rFc = { required: false, transform: coerceBooleanProperty };\n\n@Component({\n selector: 'pro-input-dropdown',\n templateUrl: './input-dropdown.component.html',\n styleUrl: './input-dropdown.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n CommonModule,\n FormsModule,\n InputLoadingComponent,\n MatFormFieldModule,\n MatSelectModule,\n ReactiveFormsModule,\n ],\n standalone: true,\n})\nexport class InputDropdownComponent<T> extends InputDirective<T> {\n @ContentChildren(InputDropdownOptionComponent)\n public readonly options: QueryList<InputDropdownOptionComponent> =\n new QueryList<InputDropdownOptionComponent>();\n\n @ContentChildren(InputDropdownOptionGroupComponent)\n public readonly optionGroups: QueryList<InputDropdownOptionGroupComponent> =\n new QueryList<InputDropdownOptionGroupComponent>();\n\n @ViewChild(MatSelect) public readonly matSelect?: MatSelect;\n\n @Input(rF)\n public appearance: InputAppearance = 'outline';\n\n @Input() public max: number | undefined;\n\n private get exceedsMax(): boolean {\n return this.max !== undefined && this.selectedOptions.length > this.max;\n }\n\n protected get selectedOptions(): readonly InputDropdownOptionComponent[] {\n if (!this.matSelect) {\n return [];\n }\n\n const allOptions = [\n ...this.options.toArray(),\n ...this.optionGroups\n .toArray()\n .flatMap((group) => group.options.toArray()),\n ];\n\n // Single selection\n if (this.matSelect.selected instanceof MatOption) {\n const selectedValue = this.matSelect.selected.value;\n return allOptions.filter((option) => option.value === selectedValue);\n }\n\n // Multi-selection\n if (\n Array.isArray(this.matSelect.selected) &&\n this.matSelect.selected.every((s) => s instanceof MatOption)\n ) {\n const selectedValues = this.matSelect.selected.map(\n (selected) => (selected as MatOption).value,\n );\n return allOptions.filter((option) =>\n selectedValues.includes(option.value),\n );\n }\n\n // Default: No option is selected.\n return [];\n }\n\n @Input(rFc) public multiple = false;\n\n @Input(rF) public compareWith: MatSelect['compareWith'] = (\n optionValue,\n selectedValue,\n ) => {\n return (\n JSON.stringify(optionValue) === JSON.stringify(selectedValue) ||\n optionValue === selectedValue\n );\n };\n}\n","@if (formControl && (options || optionGroups)) {\n <mat-form-field [appearance]=\"appearance\">\n <mat-label>{{ label }}</mat-label>\n <mat-select\n [compareWith]=\"compareWith\"\n [formControl]=\"formControl\"\n [multiple]=\"multiple\"\n [placeholder]=\"placeholder || ''\"\n >\n @for (option of options; track option) {\n <mat-option [disabled]=\"option.disabled\" [value]=\"option.value\">{{\n option.element.textContent\n }}</mat-option>\n }\n @for (optionGroup of optionGroups; track optionGroup) {\n <mat-optgroup [label]=\"optionGroup.label\">\n @for (option of optionGroup.options; track option) {\n <mat-option [disabled]=\"option.disabled\" [value]=\"option.value\">{{\n option.element.textContent\n }}</mat-option>\n }\n </mat-optgroup>\n }\n </mat-select>\n <mat-hint [title]=\"hint\">{{ hint }}</mat-hint>\n @if (formControl.invalid && formControl.touched) {\n <mat-error>\n @if (formControl.hasError('required')) {\n {{ label }} is required.\n } @else if (formControl.hasError('maxlength')) {\n {{ label }} cannot exceed\n {{ formControl.errors?.['maxlength'].requiredLength }} selections.\n } @else if (formControl.hasError('minlength')) {\n {{ label }} must have at least\n {{ formControl.errors?.['minlength'].requiredLength }} selections.\n }\n </mat-error>\n }\n </mat-form-field>\n} @else {\n <pro-input-loading [label]=\"label\" />\n}\n","import { coerceElement } from '@angular/cdk/coercion';\nimport {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n Input,\n inject,\n} from '@angular/core';\n\n@Component({\n selector: 'pro-input-radio-option',\n template: `<ng-content></ng-content>`,\n changeDetection: ChangeDetectionStrategy.Default,\n standalone: true,\n})\nexport class InputRadioOptionComponent<T> {\n private readonly elementRef = inject(ElementRef<HTMLElement>);\n\n @Input({ required: true }) public value!: T;\n\n public get element(): HTMLElement {\n return coerceElement(this.elementRef);\n }\n}\n","import { CommonModule } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n ContentChildren,\n QueryList,\n} from '@angular/core';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatRadioModule } from '@angular/material/radio';\n\nimport { InputDirective } from '../input.directive';\nimport { InputRadioOptionComponent } from './input-radio-option.component';\n\n@Component({\n selector: 'pro-input-radio',\n templateUrl: './input-radio.component.html',\n styleUrls: ['./input-radio.component.scss'],\n changeDetection: ChangeDetectionStrategy.Default,\n imports: [\n CommonModule,\n MatFormFieldModule,\n MatRadioModule,\n ReactiveFormsModule,\n ],\n standalone: true,\n})\nexport class InputRadioComponent<T> extends InputDirective<T> {\n @ContentChildren(InputRadioOptionComponent)\n protected readonly options: QueryList<InputRadioOptionComponent<T>> =\n new QueryList<InputRadioOptionComponent<T>>();\n}\n","@if (label) {\n <mat-label>{{ label + (isRequired ? '*' : '') }}</mat-label>\n}\n<mat-radio-group\n [ariaLabel]=\"label + ' radio group'\"\n [formControl]=\"formControl\"\n>\n @for (option of options; track option) {\n <mat-radio-button [value]=\"option.value\">{{\n option.element.textContent\n }}</mat-radio-button>\n }\n</mat-radio-group>\n<mat-hint [title]=\"hint\">{{ hint }}</mat-hint>\n@if (formControl.invalid && formControl.touched) {\n <mat-error>\n @if (formControl.hasError('required')) {\n {{ label }} is required.\n }\n </mat-error>\n}\n","import { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatInputModule } from '@angular/material/input';\n\nimport { InputDirective } from '../input.directive';\nimport { InputAppearance, InputAutocomplete } from '../types';\n\nconst rF = { required: false };\n\n@Component({\n selector: 'pro-input-textarea',\n templateUrl: './input-textarea.component.html',\n styleUrls: [],\n standalone: true,\n imports: [\n CommonModule,\n MatFormFieldModule,\n MatInputModule,\n ReactiveFormsModule,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class InputTextareaComponent extends InputDirective<string> {\n @Input(rF) public appearance: InputAppearance = 'outline';\n @Input(rF) public autocomplete: InputAutocomplete = 'off';\n @Input(rF) public name: string | undefined;\n\n @Input(rF) public set maxLength(value: number | string) {\n const maxLengthParsed = Number(value);\n if (isNaN(maxLengthParsed)) {\n this.#maxLength = undefined;\n return;\n }\n this.#maxLength = maxLengthParsed;\n }\n public get maxLength(): number | undefined {\n return this.#maxLength;\n }\n #maxLength: number | undefined;\n\n @Input(rF) public set minLength(value: number | string) {\n const minLengthParsed = Number(value);\n if (isNaN(minLengthParsed)) {\n this.#minLength = undefined;\n return;\n }\n\n this.#minLength = minLengthParsed;\n }\n public get minLength(): number | undefined {\n return this.#minLength;\n }\n #minLength: number | undefined;\n}\n","<mat-form-field [appearance]=\"appearance\">\n <mat-label>{{ label }}</mat-label>\n @if (formControl) {\n <textarea\n [autocomplete]=\"autocomplete\"\n [formControl]=\"formControl\"\n [id]=\"id\"\n [name]=\"name || id\"\n [placeholder]=\"placeholder || ''\"\n matInput\n ></textarea>\n } @else {\n Loading{{ label ? ' ' + label : '' }}...\n }\n <mat-hint [title]=\"hint\">{{ hint }}</mat-hint>\n @if (formControl.invalid && formControl.touched) {\n <mat-error>\n @if (formControl.hasError('required')) {\n {{ label }} is required.\n } @else if (formControl.hasError('minlength')) {\n {{ label }} must be at least\n {{ formControl.errors?.['minlength'].requiredLength }} characters.\n } @else if (formControl.hasError('maxlength')) {\n {{ label }} cannot exceed\n {{ formControl.errors?.['maxlength'].requiredLength }} characters.\n }\n </mat-error>\n }\n</mat-form-field>\n","import { DateTime } from 'luxon';\n\nimport { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { provideLuxonDateAdapter } from '@angular/material-luxon-adapter';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatTimepickerModule } from '@angular/material/timepicker';\n\nimport { InputLoadingComponent } from '../input-loading/loading-input.component';\nimport { InputDirective } from '../input.directive';\nimport { DateTimePipe } from '../pipes';\nimport { InputAppearance } from '../types';\n\nconst rF = { required: false };\n\n@Component({\n selector: 'pro-input-timepicker',\n templateUrl: './input-timepicker.component.html',\n styleUrls: [],\n standalone: true,\n imports: [\n CommonModule,\n DateTimePipe,\n InputLoadingComponent,\n MatFormFieldModule,\n MatInputModule,\n MatTimepickerModule,\n ReactiveFormsModule,\n ],\n providers: [provideLuxonDateAdapter()],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class InputTimepickerComponent extends InputDirective<DateTime> {\n @Input(rF) public appearance: InputAppearance = 'outline';\n @Input(rF) public interval: string | number | null = null;\n @Input(rF) public max: DateTime | undefined;\n @Input(rF) public min: DateTime | undefined;\n}\n","@if (formControl) {\n <mat-form-field [appearance]=\"appearance\">\n <mat-label>{{ label }}</mat-label>\n <input\n [formControl]=\"formControl\"\n [matTimepicker]=\"timepicker\"\n [max]=\"max\"\n [min]=\"min\"\n [placeholder]=\"placeholder ?? ''\"\n matInput\n />\n <mat-timepicker-toggle [for]=\"timepicker\" matSuffix />\n <mat-timepicker #timepicker [interval]=\"interval\" />\n <mat-hint [title]=\"hint\">{{ hint }}</mat-hint>\n @if (formControl.invalid && formControl.touched) {\n <mat-error>\n @if (formControl.hasError('required')) {\n {{ label }} is required.\n } @else if (formControl.hasError('min')) {\n {{ label }} must be at least\n {{ formControl.errors?.['min'].min | dateTime: 'h:mm a (ZZZZ)' }}.\n } @else if (formControl.hasError('max')) {\n {{ label }} cannot exceed\n {{ formControl.errors?.['max'].max | dateTime: 'h:mm a (ZZZZ)' }}.\n }\n </mat-error>\n }\n </mat-form-field>\n} @else {\n <pro-input-loading [label]=\"label\" />\n}\n","import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';\nimport { startWith } from 'rxjs';\n\nimport { CommonModule } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n OnInit,\n Output,\n} from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatSlideToggleModule } from '@angular/material/slide-toggle';\n\nimport { InputDirective } from '../input.directive';\n\n@UntilDestroy()\n@Component({\n selector: 'pro-input-toggle',\n templateUrl: './input-toggle.component.html',\n styleUrls: ['./input-toggle.component.scss'],\n standalone: true,\n imports: [\n CommonModule,\n FormsModule,\n MatFormFieldModule,\n MatSlideToggleModule,\n ReactiveFormsModule,\n ],\n changeDetection: ChangeDetectionStrategy.Default,\n})\nexport class InputToggleComponent\n extends InputDirective<boolean | null>\n implements OnInit\n{\n // eslint-disable-next-line @angular-eslint/no-output-native\n @Output() public readonly change = new EventEmitter<boolean>();\n\n public ngOnInit(): void {\n this.formControl.valueChanges\n .pipe(startWith(this.formControl.value), untilDestroyed(this))\n .subscribe((isChecked) => {\n if (this.formControl.disabled) {\n return;\n }\n\n if (this.isRequired && !isChecked) {\n this.formControl.setErrors({ required: true }, { emitEvent: false });\n this.formControl.setValue(null, { emitEvent: false });\n } else if (this.isRequired && isChecked) {\n this.formControl.setErrors(null);\n }\n\n if (isChecked !== null) {\n this.change.emit(isChecked);\n }\n });\n }\n}\n","<mat-slide-toggle [formControl]=\"formControl\"\n ><span class=\"label\">{{\n label + (isRequired ? '*' : '')\n }}</span></mat-slide-toggle\n>\n@if (formControl.invalid && formControl.touched) {\n <mat-error>\n @if (formControl.hasError('required')) {\n {{ label }} is required.\n }\n </mat-error>\n}\n","import {\n AfterViewInit,\n Directive,\n QueryList,\n ViewChildren,\n} from '@angular/core';\nimport { AbstractControl, FormGroup } from '@angular/forms';\n\nimport { InputCheckboxComponent } from './input-checkbox/input-checkbox.component';\nimport { InputChipsComponent } from './input-chips/input-chips.component';\nimport { InputDatepickerComponent } from './input-datepicker/input-datepicker.component';\nimport { InputDropdownComponent } from './input-dropdown/input-dropdown.component';\nimport { InputRadioComponent } from './input-radio/input-radio.component';\nimport { InputTextareaComponent } from './input-textarea/input-textarea.component';\nimport { InputTimepickerComponent } from './input-timepicker/input-timepicker.component';\nimport { InputToggleComponent } from './input-toggle/input-toggle.component';\nimport { InputComponent } from './input/input.component';\n\n@Directive()\nexport class FormDirective<T extends { [K in keyof T]: AbstractControl }>\n implements AfterViewInit\n{\n protected readonly formGroup!: FormGroup<T>;\n\n @ViewChildren(InputComponent)\n private readonly inputs!: QueryList<InputComponent>;\n\n @ViewChildren(InputCheckboxComponent)\n private readonly inputCheckboxes!: QueryList<InputCheckboxComponent>;\n\n @ViewChildren(InputChipsComponent)\n private readonly inputChips!: QueryList<InputChipsComponent>;\n\n @ViewChildren(InputDatepickerComponent)\n private readonly inputDatepickers!: QueryList<InputDatepickerComponent>;\n\n @ViewChildren(InputDropdownComponent)\n private readonly inputDropdowns!: QueryList<InputDropdownComponent<T>>;\n\n @ViewChildren(InputRadioComponent)\n private readonly inputRadios!: QueryList<InputRadioComponent<T>>;\n\n @ViewChildren(InputTextareaComponent)\n private readonly inputTextareas!: QueryList<InputTextareaComponent>;\n\n @ViewChildren(InputTimepickerComponent)\n private readonly inputTimepickers!: QueryList<InputTimepickerComponent>;\n\n @ViewChildren(InputToggleComponent)\n private readonly inputToggles!: QueryList<InputToggleComponent>;\n\n private get formInputs(): ReadonlyArray<\n | InputComponent\n | InputCheckboxComponent\n | InputChipsComponent\n | InputDatepickerComponent\n | InputDropdownComponent<T>\n | InputRadioComponent<T>\n | InputTextareaComponent\n | InputTimepickerComponent\n | InputToggleComponent\n > {\n return [\n ...this.inputs.toArray(),\n ...this.inputCheckboxes.toArray(),\n ...this.inputChips.toArray(),\n ...this.inputDatepickers.toArray(),\n ...this.inputDropdowns.toArray(),\n ...this.inputRadios.toArray(),\n ...this.inputTextareas.toArray(),\n ...this.inputTimepickers.toArray(),\n ...this.inputToggles.toArray(),\n ];\n }\n\n public ngAfterViewInit(): void {\n if (!this.formGroup) {\n throw new Error('You must provide a `FormGroup` to `FormDirective`!');\n }\n }\n\n /** Trigger validation checks & highlight all invalid controls. */\n public highlightInvalidControls(): void {\n if (this.formInputs.length === 0) {\n throw new Error('No inputs available for highlight!');\n }\n\n for (const input of this.formInputs) {\n if (!input.formControl) {\n throw new Error(\n `Input \"${\n input.label ?? String(input)\n }\" doesn't have a form control!`,\n );\n }\n if (input.formControl.invalid) {\n input.formControl.markAsTouched();\n }\n }\n }\n\n /** Reset the form to its original state. */\n protected reset(): void {\n if (this.formGroup.pristine && this.formGroup.untouched) {\n return;\n }\n\n this.formGroup.reset();\n }\n\n /**\n * Scroll to the first invalid control in the form.\n *\n * @returns The label of the first invalid control.\n */\n public scrollToFirstInvalidControl(): string | null {\n if (this.formInputs.length === 0) {\n throw new Error('No form inputs provided to scroll to!');\n }\n\n for (const input of this.formInputs) {\n if (!input.formControl) {\n throw new Error(\n `Input \"${\n input.label ?? String(input)\n }\" doesn't have a form control!`,\n );\n }\n\n if (input.formControl.invalid) {\n input.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n });\n return input.label;\n }\n }\n\n return null;\n }\n}\n","// Components\nexport { InputCheckboxComponent } from './input-checkbox/input-checkbox.component';\nexport { InputChipComponent } from './input-chips/input-chip.component';\nexport { InputChipsComponent } from './input-chips/input-chips.component';\nexport { InputComponent } from './input/input.component';\nexport { InputDatepickerComponent } from './input-datepicker/input-datepicker.component';\nexport { InputDropdownComponent } from './input-dropdown/input-dropdown.component';\nexport { InputDropdownOptionComponent } from './input-dropdown/input-dropdown-option.component';\nexport { InputDropdownOptionGroupComponent } from './input-dropdown/input-dropdown-option-group.component';\nexport { InputLoadingComponent } from './input-loading/loading-input.component';\nexport { InputRadioComponent } from './input-radio/input-radio.component';\nexport { InputRadioOptionComponent } from './input-radio/input-radio-option.component';\nexport { InputTextareaComponent } from './input-textarea/input-textarea.component';\nexport { InputTimepickerComponent } from './input-timepicker/input-timepicker.component';\nexport { InputToggleComponent } from './input-toggle/input-toggle.component';\n\n// Directives\nexport { FormDirective } from './form.directive';\nexport { InputDirective } from './input.directive';\n\n// Pipes\nexport { DateTimePipe } from './pipes';\n\n// Utilities\nexport * from './utilities';\n\n// Types\nexport type {\n DateTimeFormat,\n InputAppearance,\n InputAutocomplete,\n InputType,\n Option,\n} from './types';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public';\n"],"names":["rF","i1","i3","rFc","i2","MatOption"],"mappings":"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