@ng-forge/dynamic-forms-material 1.2.0-next.6 → 1.2.0-next.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/fesm2022/ng-forge-dynamic-forms-material-lazy-addon-button.mjs +106 -0
  2. package/fesm2022/ng-forge-dynamic-forms-material-lazy-addon-button.mjs.map +1 -0
  3. package/fesm2022/ng-forge-dynamic-forms-material-lazy-addon-icon.mjs +34 -0
  4. package/fesm2022/ng-forge-dynamic-forms-material-lazy-addon-icon.mjs.map +1 -0
  5. package/fesm2022/ng-forge-dynamic-forms-material-lazy-button.mjs +60 -0
  6. package/fesm2022/ng-forge-dynamic-forms-material-lazy-button.mjs.map +1 -0
  7. package/fesm2022/ng-forge-dynamic-forms-material-lazy-checkbox.mjs +76 -0
  8. package/fesm2022/ng-forge-dynamic-forms-material-lazy-checkbox.mjs.map +1 -0
  9. package/fesm2022/ng-forge-dynamic-forms-material-lazy-datepicker.mjs +124 -0
  10. package/fesm2022/ng-forge-dynamic-forms-material-lazy-datepicker.mjs.map +1 -0
  11. package/fesm2022/ng-forge-dynamic-forms-material-lazy-input.mjs +196 -0
  12. package/fesm2022/ng-forge-dynamic-forms-material-lazy-input.mjs.map +1 -0
  13. package/fesm2022/ng-forge-dynamic-forms-material-lazy-multi-checkbox.mjs +136 -0
  14. package/fesm2022/ng-forge-dynamic-forms-material-lazy-multi-checkbox.mjs.map +1 -0
  15. package/fesm2022/ng-forge-dynamic-forms-material-lazy-radio.mjs +92 -0
  16. package/fesm2022/ng-forge-dynamic-forms-material-lazy-radio.mjs.map +1 -0
  17. package/fesm2022/ng-forge-dynamic-forms-material-lazy-select.mjs +106 -0
  18. package/fesm2022/ng-forge-dynamic-forms-material-lazy-select.mjs.map +1 -0
  19. package/fesm2022/ng-forge-dynamic-forms-material-lazy-slider.mjs +76 -0
  20. package/fesm2022/ng-forge-dynamic-forms-material-lazy-slider.mjs.map +1 -0
  21. package/fesm2022/ng-forge-dynamic-forms-material-lazy-textarea.mjs +92 -0
  22. package/fesm2022/ng-forge-dynamic-forms-material-lazy-textarea.mjs.map +1 -0
  23. package/fesm2022/ng-forge-dynamic-forms-material-lazy-toggle.mjs +76 -0
  24. package/fesm2022/ng-forge-dynamic-forms-material-lazy-toggle.mjs.map +1 -0
  25. package/fesm2022/ng-forge-dynamic-forms-material-shared.mjs +14 -0
  26. package/fesm2022/ng-forge-dynamic-forms-material-shared.mjs.map +1 -0
  27. package/fesm2022/ng-forge-dynamic-forms-material.mjs +36 -92
  28. package/fesm2022/ng-forge-dynamic-forms-material.mjs.map +1 -1
  29. package/package.json +55 -3
  30. package/types/ng-forge-dynamic-forms-material-lazy-addon-button.d.ts +18 -0
  31. package/types/ng-forge-dynamic-forms-material-lazy-addon-icon.d.ts +17 -0
  32. package/types/ng-forge-dynamic-forms-material-lazy-button.d.ts +114 -0
  33. package/types/ng-forge-dynamic-forms-material-lazy-checkbox.d.ts +26 -0
  34. package/types/ng-forge-dynamic-forms-material-lazy-datepicker.d.ts +37 -0
  35. package/types/ng-forge-dynamic-forms-material-lazy-input.d.ts +55 -0
  36. package/types/ng-forge-dynamic-forms-material-lazy-multi-checkbox.d.ts +29 -0
  37. package/types/ng-forge-dynamic-forms-material-lazy-radio.d.ts +24 -0
  38. package/types/ng-forge-dynamic-forms-material-lazy-select.d.ts +35 -0
  39. package/types/ng-forge-dynamic-forms-material-lazy-slider.d.ts +27 -0
  40. package/types/ng-forge-dynamic-forms-material-lazy-textarea.d.ts +31 -0
  41. package/types/ng-forge-dynamic-forms-material-lazy-toggle.d.ts +28 -0
  42. package/types/ng-forge-dynamic-forms-material-shared.d.ts +91 -0
  43. package/types/ng-forge-dynamic-forms-material.d.ts +8 -159
@@ -1 +1 @@
1
- {"version":3,"file":"ng-forge-dynamic-forms-material.mjs","mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0Cc;;;AAKH;;AAEA;;;AAPU;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA/BT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACiEE;;;;;;;;;AAQH;;AAEA;;AAEA;;AAEA;;AAEA;;;AAhBU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA/DT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDT;;;;;;;;;ACxDD;AACF;;;;ACiKc;;;;AAMH;;AAET,IAKS;;IAGQ;AAER;;AAEA;;AAEA;;AAEA;;IAGU;;;AA3BA;AAlCjB;AACE;AACA;AACD;AACD;gFAME;;AAEE;AACA;AACA;oBAEA;;AAEE;AACE;AACA;;;;;;AAOC;;;;AAIR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA/IO;;;;;;;;;;;;;AAcT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkGC;AACE;AACA;AACD;AACD;4IAME;;AAEE;AACA;AACA;;;AAIE;AACE;AACA;;;;;;AAOC;;;;AAIR;AACF;;;;;;;;AClHW;;;;AAIH;;AAET;AAEI;;AAEF;IAKO;;;;;AAKP;;;AAGF;AACE;AACE;AAEA;AACE;;AAEJ;AAEA;AACE;AACA;;;AAIE;;AAEJ;;;;;AAMI;;;AAEA;;AAEJ;;;AAlDiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA3CT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACwCE;;;;AAIH;;;AAJU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAJlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACcW;;;;;AAMH;;AAEA;;AAEA;;AAEA;;AAEA;;AAET;;AAhBmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAXlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACDW;;AAGH;;AAEA;;;AALU;;;;;;;;;;;;;;;;;;;;;;;;;AAXlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACDW;;AAGH;;AAEA;;AAEA;;;AAGP;;AACA;;;AAXiB;;;;;;;;;;;;;;AAXlB;;;;AAjBS;;;;;;;;;;;;;;;;;;;;;;;AC6CE;;;AAKH;;AAEA;;AACA;;AAEA;;AACA;;;AAXU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAXlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAW;;;AAKH;;AAEA;;;AAPU;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA/BT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACXI;AACJ;AACA;AACA;;;AAKE;AACE;AACA;;;AAKA;;;AAKA;;QAIF;AACA;;AAGI;;AACA;AACF;;;;AAKE;AACA;AACE;;;;;AAMN;AACF;AACF;;;ACnCA;;;AAQA;AACE;AACA;;AAOK;AACL;;AAEE;AACA;;AAEA;AACA;AACE;AACD;AACD;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;;;;AC1IH;AACE;AACA;AACA;;AAeI;;;;AAOA;;AAE+B;AACjC;;AAGF;AACF;AAEA;AAEA;AACE;AACA;AACA;AACE;AACE;;;;AAKN;AACE;AACA;AACA;;AAIE;AACE;;QAKF;AACE;;;;;;AAkBF;AACA;;;AAGC;;AAEL;;;;;IC7FW;;;;AAGU;;;AANR;;;;AATF;AACT;AACA;AACA;AACA;AACE;AACD;;AAEF;;;;;;;;;;ICyDoB;;;;;AAIA;AACjB;;;;;AATS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA1DD","names":[],"ignoreList":[],"sources":["../../../../packages/dynamic-forms-material/src/lib/fields/checkbox/mat-checkbox.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/datepicker/mat-datepicker.component.ts","../../../../packages/dynamic-forms-material/src/lib/addons/preset-actions.ts","../../../../packages/dynamic-forms-material/src/lib/fields/input/mat-input.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/multi-checkbox/mat-multi-checkbox.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/radio/mat-radio.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/select/mat-select.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/slider/mat-slider.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/button/mat-button.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/textarea/mat-textarea.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/toggle/mat-toggle.component.ts","../../../../packages/dynamic-forms-material/src/lib/types/types.ts","../../../../packages/dynamic-forms-material/src/lib/fields/button/mat-button.mapper.ts","../../../../packages/dynamic-forms-material/src/lib/config/material-field-config.ts","../../../../packages/dynamic-forms-material/src/lib/providers/material-providers.ts","../../../../packages/dynamic-forms-material/src/lib/addons/mat-icon-addon.component.ts","../../../../packages/dynamic-forms-material/src/lib/addons/mat-button-addon.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatCheckbox } from '@angular/material/checkbox';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatCheckboxProps } from './mat-checkbox.type';\nimport { MatError } from '@angular/material/input';\nimport { AsyncPipe } from '@angular/common';\nimport { MATERIAL_CONFIG } from '../../models/material-config.token';\n\n@Component({\n selector: 'df-mat-checkbox',\n imports: [MatCheckbox, FormField, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let checkboxId = ngf.key() + '-checkbox';\n\n <mat-checkbox\n ngForgeControl=\"input[type='checkbox']\"\n [id]=\"checkboxId\"\n [formField]=\"f\"\n [labelPosition]=\"props()?.labelPosition || 'after'\"\n [indeterminate]=\"props()?.indeterminate || false\"\n [color]=\"props()?.color || 'primary'\"\n [disableRipple]=\"disableRipple()\"\n [required]=\"!!f().required()\"\n [tabIndex]=\"ngf.tabIndex() ?? 0\"\n [attr.hidden]=\"f().hidden() || null\"\n >\n {{ ngf.label() | dynamicText | async }}\n </mat-checkbox>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\" [attr.hidden]=\"f().hidden() || null\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <div class=\"mat-hint\" [id]=\"ngf.hintId()\" [attr.hidden]=\"f().hidden() || null\">{{ hint | dynamicText | async }}</div>\n }\n `,\n styleUrl: '../../styles/_form-field.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatCheckboxFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<boolean>();\n\n readonly props = input<MatCheckboxProps>();\n\n readonly disableRipple = computed(() => this.props()?.disableRipple ?? this.materialConfig?.disableRipple ?? false);\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatError, MatFormField, MatLabel, MatSuffix } from '@angular/material/form-field';\nimport { MatHint, MatInput } from '@angular/material/input';\nimport { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material/datepicker';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatDatepickerProps } from './mat-datepicker.type';\nimport { provideNativeDateAdapter } from '@angular/material/core';\nimport { AsyncPipe } from '@angular/common';\nimport { MATERIAL_CONFIG } from '../../models/material-config.token';\n\n@Component({\n selector: 'df-mat-datepicker',\n imports: [\n MatFormField,\n MatLabel,\n MatInput,\n MatHint,\n MatDatepicker,\n MatDatepickerInput,\n MatDatepickerToggle,\n MatSuffix,\n FormField,\n MatError,\n DynamicTextPipe,\n AsyncPipe,\n NgForgeControl,\n ],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let inputId = ngf.key() + '-input';\n\n <mat-form-field\n [appearance]=\"appearance()\"\n [subscriptSizing]=\"subscriptSizing()\"\n [floatLabel]=\"floatLabel()\"\n [hideRequiredMarker]=\"hideRequiredMarker()\"\n >\n @if (ngf.label(); as label) {\n <mat-label>{{ label | dynamicText | async }}</mat-label>\n }\n\n <input\n matInput\n ngForgeControl\n [id]=\"inputId\"\n [matDatepicker]=\"picker\"\n [formField]=\"ngf.field()\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n [min]=\"minDate()\"\n [max]=\"maxDate()\"\n />\n\n <mat-datepicker-toggle matIconSuffix [for]=\"picker\" />\n <mat-datepicker #picker [startAt]=\"startAt()\" [startView]=\"props()?.startView || 'month'\" [touchUi]=\"props()?.touchUi ?? false\" />\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <mat-hint [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</mat-hint>\n }\n </mat-form-field>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n mat-form-field {\n width: 100%;\n }\n `,\n ],\n providers: [provideNativeDateAdapter()],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatDatepickerFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<string>();\n\n readonly minDate = input<Date | null>(null);\n readonly maxDate = input<Date | null>(null);\n readonly startAt = input<Date | null>(null);\n readonly props = input<MatDatepickerProps>();\n\n readonly appearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline');\n\n readonly subscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic');\n\n readonly floatLabel = computed(() => this.props()?.floatLabel ?? this.materialConfig?.floatLabel ?? 'auto');\n\n readonly hideRequiredMarker = computed(() => this.props()?.hideRequiredMarker ?? this.materialConfig?.hideRequiredMarker ?? false);\n}\n","import type { AddonActionContext, AddonActionPreset } from '@ng-forge/dynamic-forms';\nimport type { PresetCollaborators } from '@ng-forge/dynamic-forms/integration';\nimport { runPresetAction } from '@ng-forge/dynamic-forms/integration';\n\nexport type { PresetCollaborators };\n\n/** Material adapter binding for the shared preset runner. */\nexport function runMatPresetAction(preset: AddonActionPreset, ctx: AddonActionContext, collaborators: PresetCollaborators): Promise<void> {\n return runPresetAction(preset, ctx, collaborators, 'Material', 'mat-input');\n}\n","import { AsyncPipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, forwardRef, inject, input, signal } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatError, MatFormField, MatLabel, MatPrefix, MatSuffix } from '@angular/material/form-field';\nimport { MatHint, MatInput } from '@angular/material/input';\nimport { AddonActionContext, AddonActionPreset, DynamicFormLogger } from '@ng-forge/dynamic-forms';\nimport { DfAddonSlot } from '@ng-forge/dynamic-forms/integration';\nimport { WrapperFieldInputs } from '@ng-forge/dynamic-forms/integration';\nimport { DynamicTextPipe, FIELD_SIGNAL_CONTEXT } from '@ng-forge/dynamic-forms/integration';\nimport {\n ADDON_PRESET_HANDLER,\n AddonPresetHandler,\n injectNgForgeAddons,\n injectNgForgeField,\n NgForgeAddons,\n NgForgeControl,\n NgForgeFieldHost,\n} from '@ng-forge/dynamic-forms/integration';\nimport { MATERIAL_CONFIG } from '../../models/material-config.token';\nimport { runMatPresetAction } from '../../addons/preset-actions';\nimport { MAT_INPUT_TYPE_OVERRIDE } from '../../tokens/input-type-override.token';\nimport { MatInputAddon, MatInputProps } from './mat-input.type';\n\n@Component({\n selector: 'df-mat-input',\n imports: [\n MatFormField,\n MatLabel,\n MatInput,\n MatHint,\n MatError,\n MatPrefix,\n MatSuffix,\n FormField,\n DynamicTextPipe,\n AsyncPipe,\n NgForgeControl,\n DfAddonSlot,\n ],\n hostDirectives: [NgForgeFieldHost, NgForgeAddons],\n template: `\n @let inputId = ngf.key() + '-input';\n\n <mat-form-field\n [appearance]=\"appearance()\"\n [subscriptSizing]=\"subscriptSizing()\"\n [floatLabel]=\"floatLabel()\"\n [hideRequiredMarker]=\"hideRequiredMarker()\"\n >\n @if (ngf.label()) {\n <mat-label>{{ ngf.label() | dynamicText | async }}</mat-label>\n }\n @for (a of ngfa.prefixAddons(); track $index) {\n <df-addon-slot\n matPrefix\n [class.df-mat-addon-text]=\"a.type === 'text'\"\n [addon]=\"a\"\n [fieldInputs]=\"fieldInputs()\"\n [hidden]=\"ngfa.hiddenSignalCache().get(a)\"\n />\n }\n <input\n matInput\n ngForgeControl\n [id]=\"inputId\"\n [formField]=\"ngf.field()\"\n [type]=\"type()\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n />\n @for (a of ngfa.suffixAddons(); track $index) {\n <df-addon-slot\n matSuffix\n [class.df-mat-addon-text]=\"a.type === 'text'\"\n [addon]=\"a\"\n [fieldInputs]=\"fieldInputs()\"\n [hidden]=\"ngfa.hiddenSignalCache().get(a)\"\n />\n }\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <mat-hint [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</mat-hint>\n }\n </mat-form-field>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n mat-form-field {\n width: 100%;\n }\n :host([hidden]) {\n display: none !important;\n }\n /* matPrefix/matSuffix elements have no default Material spacing.\n All four sides + the text-type variants are independent CSS custom\n properties so consumers can tune each individually:\n prefix-outer = prefix slot's left (border-facing) padding\n prefix-inner = prefix slot's right (text-facing) padding\n suffix-inner = suffix slot's left (text-facing) padding\n suffix-outer = suffix slot's right (border-facing) padding\n Text variants override only the INNER side because <mat-icon> has\n ~4-6px optical padding inside its glyph box (so it looks \"padded\"\n even with a small CSS value) while text glyphs sit flush against\n their bounding box and need the extra room to match. */\n :host {\n --df-mat-addon-prefix-outer-padding: 0.75em;\n --df-mat-addon-prefix-inner-padding: 0.5em;\n --df-mat-addon-suffix-inner-padding: 0.5em;\n --df-mat-addon-suffix-outer-padding: 0.75em;\n --df-mat-addon-prefix-text-outer-padding: 1em;\n --df-mat-addon-prefix-text-inner-padding: 1em;\n --df-mat-addon-suffix-text-inner-padding: 1em;\n --df-mat-addon-suffix-text-outer-padding: 1em;\n }\n df-addon-slot[matprefix] {\n padding-left: var(--df-mat-addon-prefix-outer-padding);\n padding-right: var(--df-mat-addon-prefix-inner-padding);\n }\n df-addon-slot[matsuffix] {\n padding-left: var(--df-mat-addon-suffix-inner-padding);\n padding-right: var(--df-mat-addon-suffix-outer-padding);\n }\n df-addon-slot[matprefix].df-mat-addon-text {\n padding-left: var(--df-mat-addon-prefix-text-outer-padding);\n padding-right: var(--df-mat-addon-prefix-text-inner-padding);\n }\n df-addon-slot[matsuffix].df-mat-addon-text {\n padding-left: var(--df-mat-addon-suffix-text-inner-padding);\n padding-right: var(--df-mat-addon-suffix-text-outer-padding);\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: MAT_INPUT_TYPE_OVERRIDE,\n useFactory: () => signal<string | undefined>(undefined),\n },\n {\n // Adapter-specific preset semantics for `mat-button` addons (clear /\n // reset / paste / copy / toggle-password-visibility). The directive\n // (`NgForgeAddonAction`) delegates here when an addon configures a\n // `preset`. Per-mat-input-instance so the `typeOverride` signal is\n // scoped to one field.\n provide: ADDON_PRESET_HANDLER,\n useFactory: (): AddonPresetHandler => {\n const typeOverride = inject(MAT_INPUT_TYPE_OVERRIDE);\n const fsc = inject(FIELD_SIGNAL_CONTEXT, { optional: true });\n const logger = inject(DynamicFormLogger);\n // forwardRef for baselineType only — host.props()?.type gates toggle-password-visibility.\n const host = inject(forwardRef(() => MatInputFieldComponent));\n return {\n run: (preset: string, ctx: AddonActionContext) => {\n const fieldKey = ctx.field.key;\n return runMatPresetAction(preset as AddonActionPreset, ctx, {\n typeOverride,\n fieldValueSetter: ctx.setValue,\n fieldDefaultValueGetter:\n fsc && fieldKey ? () => (fsc.defaultValues() as Record<string, unknown> | undefined)?.[fieldKey] : undefined,\n baselineType: () => host.props()?.type,\n logger,\n });\n },\n };\n },\n },\n ],\n})\nexport default class MatInputFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<string>();\n protected readonly ngfa = injectNgForgeAddons<MatInputAddon>();\n\n readonly props = input<MatInputProps>();\n\n /**\n * Wrapper-style host bag pushed by `DfFieldOutlet`. Declared at the\n * component level so `setInputIfDeclared` (which uses\n * `reflectComponentType`) can write it.\n */\n readonly fieldInputs = input<WrapperFieldInputs | undefined>();\n\n /** Per-instance type override populated by `toggle-password-visibility` preset. */\n private readonly typeOverride = inject(MAT_INPUT_TYPE_OVERRIDE);\n\n readonly appearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline');\n\n readonly subscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic');\n\n readonly floatLabel = computed(() => this.props()?.floatLabel ?? this.materialConfig?.floatLabel ?? 'auto');\n\n readonly hideRequiredMarker = computed(() => this.props()?.hideRequiredMarker ?? this.materialConfig?.hideRequiredMarker ?? false);\n\n /** Override (set by `toggle-password-visibility` preset) wins over `props().type`. */\n protected readonly type = computed(() => this.typeOverride() ?? this.props()?.type ?? 'text');\n}\n","import { ChangeDetectionStrategy, Component, computed, input, linkedSignal } from '@angular/core';\nimport { MatCheckbox } from '@angular/material/checkbox';\nimport { FieldOption, ValueType } from '@ng-forge/dynamic-forms';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { injectNgForgeField, NgForgeFieldHost, isEqual, NgForgeControl } from '@ng-forge/dynamic-forms/integration';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport { MatMultiCheckboxProps } from './mat-multi-checkbox.type';\nimport { MatError } from '@angular/material/input';\nimport { AsyncPipe } from '@angular/common';\n\n@Component({\n selector: 'df-mat-multi-checkbox',\n imports: [MatCheckbox, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let checkboxGroupId = ngf.key() + '-checkbox-group';\n @let checked = checkedValuesMap();\n\n @if (ngf.label(); as label) {\n <div class=\"checkbox-group-label\">{{ label | dynamicText | async }}</div>\n }\n\n <div\n [id]=\"checkboxGroupId\"\n class=\"checkbox-group\"\n role=\"group\"\n [attr.aria-invalid]=\"ngf.ariaInvalid()\"\n [attr.aria-required]=\"ngf.ariaRequired()\"\n [attr.aria-describedby]=\"ngf.ariaDescribedBy()\"\n >\n @for (option of options(); track option.value) {\n <mat-checkbox\n ngForgeControl=\"input[type='checkbox']\"\n [checked]=\"checked['' + option.value]\"\n [disabled]=\"f().disabled() || option.disabled\"\n [color]=\"props()?.color || 'primary'\"\n [labelPosition]=\"props()?.labelPosition || 'after'\"\n (change)=\"onCheckboxChange(option, $event.checked)\"\n >\n {{ option.label | dynamicText | async }}\n </mat-checkbox>\n }\n </div>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <div class=\"mat-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</div>\n }\n `,\n styleUrl: '../../styles/_form-field.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatMultiCheckboxFieldComponent {\n protected readonly ngf = injectNgForgeField<ValueType[]>();\n\n readonly options = input<FieldOption<ValueType>[]>([]);\n readonly props = input<MatMultiCheckboxProps>();\n\n valueViewModel = linkedSignal<FieldOption<ValueType>[]>(\n () => {\n const currentValues = this.ngf.field()().value();\n return this.options().filter((option) => currentValues.includes(option.value));\n },\n { equal: isEqual },\n );\n\n /** Computed map of checked option values for O(1) lookup in template */\n readonly checkedValuesMap = computed(() => {\n const map: Record<string, boolean> = {};\n for (const opt of this.valueViewModel()) {\n map[String(opt.value)] = true;\n }\n return map;\n });\n\n constructor() {\n explicitEffect([this.valueViewModel], ([selectedOptions]) => {\n const selectedValues = selectedOptions.map((option) => option.value);\n\n if (!isEqual(selectedValues, this.ngf.field()().value())) {\n this.ngf.field()().value.set(selectedValues);\n }\n });\n\n explicitEffect([this.options], ([options]) => {\n const values = options.map((option) => option.value);\n const uniqueValues = new Set(values);\n\n if (values.length !== uniqueValues.size) {\n const duplicates = values.filter((value, index) => values.indexOf(value) !== index);\n throw new Error(`Duplicate option values detected in mat-multi-checkbox: ${duplicates.join(', ')}`);\n }\n });\n }\n\n onCheckboxChange(option: FieldOption<ValueType>, checked: boolean): void {\n this.valueViewModel.update((currentOptions) => {\n if (checked) {\n return currentOptions.some((opt) => opt.value === option.value) ? currentOptions : [...currentOptions, option];\n } else {\n return currentOptions.filter((opt) => opt.value !== option.value);\n }\n });\n }\n}\n","import { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatRadioButton, MatRadioGroup } from '@angular/material/radio';\nimport { FieldOption, ValueType } from '@ng-forge/dynamic-forms';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatRadioProps } from './mat-radio.type';\nimport { MatError } from '@angular/material/input';\nimport { AsyncPipe } from '@angular/common';\n\n@Component({\n selector: 'df-mat-radio',\n imports: [MatRadioGroup, MatRadioButton, FormField, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let radioGroupId = ngf.key() + '-radio-group';\n\n @if (ngf.label()) {\n <div class=\"radio-label\">{{ ngf.label() | dynamicText | async }}</div>\n }\n\n <mat-radio-group\n [id]=\"radioGroupId\"\n [formField]=\"f\"\n [attr.aria-invalid]=\"ngf.ariaInvalid()\"\n [attr.aria-required]=\"ngf.ariaRequired()\"\n [attr.aria-describedby]=\"ngf.ariaDescribedBy()\"\n >\n @for (option of options(); track option.value) {\n <mat-radio-button\n ngForgeControl=\"input[type='radio']\"\n [value]=\"option.value\"\n [disabled]=\"option.disabled || false\"\n [color]=\"props()?.color || 'primary'\"\n [labelPosition]=\"props()?.labelPosition || 'after'\"\n >\n {{ option.label | dynamicText | async }}\n </mat-radio-button>\n }\n </mat-radio-group>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <div class=\"mat-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</div>\n }\n `,\n styleUrl: '../../styles/_form-field.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatRadioFieldComponent {\n protected readonly ngf = injectNgForgeField<ValueType>();\n\n readonly options = input<FieldOption<ValueType>[]>([]);\n readonly props = input<MatRadioProps>();\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatError, MatFormField, MatLabel } from '@angular/material/form-field';\nimport { MatOption, MatSelect } from '@angular/material/select';\nimport { MatHint } from '@angular/material/input';\nimport { FieldOption, ValueType } from '@ng-forge/dynamic-forms';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatSelectProps } from './mat-select.type';\nimport { AsyncPipe } from '@angular/common';\nimport { MATERIAL_CONFIG } from '../../models/material-config.token';\n\n@Component({\n selector: 'df-mat-select',\n imports: [MatFormField, MatLabel, MatSelect, MatOption, MatHint, FormField, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let selectId = ngf.key() + '-select';\n\n <mat-form-field\n [appearance]=\"appearance()\"\n [subscriptSizing]=\"subscriptSizing()\"\n [floatLabel]=\"floatLabel()\"\n [hideRequiredMarker]=\"hideRequiredMarker()\"\n >\n @if (ngf.label(); as label) {\n <mat-label>{{ label | dynamicText | async }}</mat-label>\n }\n\n <mat-select\n ngForgeControl\n [id]=\"selectId\"\n [formField]=\"ngf.field()\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [multiple]=\"props()?.multiple || false\"\n [compareWith]=\"props()?.compareWith || defaultCompare\"\n >\n @for (option of options(); track option.value) {\n <mat-option [value]=\"option.value\" [disabled]=\"option.disabled || false\">\n {{ option.label | dynamicText | async }}\n </mat-option>\n }\n </mat-select>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <mat-hint [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</mat-hint>\n }\n </mat-form-field>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n mat-form-field {\n width: 100%;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatSelectFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<ValueType>();\n\n readonly options = input<FieldOption<ValueType>[]>([]);\n readonly props = input<MatSelectProps>();\n\n readonly appearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline');\n\n readonly subscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic');\n\n readonly floatLabel = computed(() => this.props()?.floatLabel ?? this.materialConfig?.floatLabel ?? 'auto');\n\n readonly hideRequiredMarker = computed(() => this.props()?.hideRequiredMarker ?? this.materialConfig?.hideRequiredMarker ?? false);\n\n defaultCompare = Object.is;\n}\n","import { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatSlider, MatSliderThumb } from '@angular/material/slider';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatSliderProps } from './mat-slider.type';\nimport { MatError } from '@angular/material/input';\nimport { AsyncPipe } from '@angular/common';\n\n@Component({\n selector: 'df-mat-slider',\n imports: [MatSlider, MatSliderThumb, MatError, DynamicTextPipe, AsyncPipe, FormField, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let inputId = ngf.key() + '-input';\n\n @if (ngf.label(); as label) {\n <label class=\"slider-label\" [for]=\"inputId\">{{ label | dynamicText | async }}</label>\n }\n\n <mat-slider\n [min]=\"f().min?.() ?? 0\"\n [max]=\"f().max?.() ?? 100\"\n [step]=\"step() ?? props()?.step ?? 1\"\n [discrete]=\"props()?.thumbLabel || props()?.showThumbLabel\"\n [showTickMarks]=\"props()?.tickInterval !== undefined\"\n [color]=\"props()?.color || 'primary'\"\n class=\"slider-container\"\n >\n <input matSliderThumb ngForgeControl [id]=\"inputId\" [formField]=\"f\" [attr.tabindex]=\"ngf.tabIndex()\" />\n </mat-slider>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <div class=\"mat-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</div>\n }\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n .slider-container {\n width: 100%;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatSliderFieldComponent {\n protected readonly ngf = injectNgForgeField<number>();\n\n readonly step = input<number>();\n\n readonly props = input<MatSliderProps>();\n}\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport { MatButton } from '@angular/material/button';\nimport { AsyncPipe } from '@angular/common';\nimport { FormEvent } from '@ng-forge/dynamic-forms';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { injectNgForgeAction, NgForgeActionHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatButtonProps } from './mat-button.type';\n\n@Component({\n selector: 'df-mat-button',\n imports: [MatButton, DynamicTextPipe, AsyncPipe],\n hostDirectives: [NgForgeActionHost],\n template: `\n @let buttonId = action.key() + '-button';\n <button\n mat-raised-button\n [id]=\"buttonId\"\n [type]=\"buttonType()\"\n [color]=\"props()?.color || 'primary'\"\n [disabled]=\"action.disabled()\"\n [attr.tabindex]=\"action.tabIndex()\"\n [attr.data-testid]=\"buttonTestId()\"\n (click)=\"onClick()\"\n >\n {{ action.label() | dynamicText | async }}\n </button>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n button {\n min-width: fit-content;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatButtonFieldComponent<TEvent extends FormEvent> {\n protected readonly action = injectNgForgeAction<TEvent>();\n\n readonly props = input<MatButtonProps>();\n\n readonly buttonType = computed(() => this.props()?.type ?? 'button');\n\n readonly buttonTestId = computed(() => `${this.buttonType()}-${this.action.key()}`);\n\n onClick(): void {\n if (this.buttonType() === 'submit') return;\n this.action.dispatch();\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatError, MatFormField, MatLabel } from '@angular/material/form-field';\nimport { MatHint, MatInput } from '@angular/material/input';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatTextareaProps } from './mat-textarea.type';\nimport { AsyncPipe } from '@angular/common';\nimport { MATERIAL_CONFIG } from '../../models/material-config.token';\n\n@Component({\n selector: 'df-mat-textarea',\n imports: [MatFormField, MatLabel, MatInput, MatHint, FormField, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let textareaId = ngf.key() + '-textarea';\n\n <mat-form-field\n [appearance]=\"appearance()\"\n [subscriptSizing]=\"subscriptSizing()\"\n [floatLabel]=\"floatLabel()\"\n [hideRequiredMarker]=\"hideRequiredMarker()\"\n >\n @if (ngf.label()) {\n <mat-label>{{ ngf.label() | dynamicText | async }}</mat-label>\n }\n\n <textarea\n ngForgeControl\n matInput\n [id]=\"textareaId\"\n [formField]=\"ngf.field()\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n [style.resize]=\"props()?.resize || 'vertical'\"\n ></textarea>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <mat-hint [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</mat-hint>\n }\n </mat-form-field>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n mat-form-field {\n width: 100%;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatTextareaFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<string>();\n\n readonly props = input<MatTextareaProps>();\n\n readonly appearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline');\n readonly subscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic');\n\n readonly floatLabel = computed(() => this.props()?.floatLabel ?? this.materialConfig?.floatLabel ?? 'auto');\n readonly hideRequiredMarker = computed(() => this.props()?.hideRequiredMarker ?? this.materialConfig?.hideRequiredMarker ?? false);\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatSlideToggle } from '@angular/material/slide-toggle';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\n\nimport { MatToggleProps } from './mat-toggle.type';\nimport { MatError } from '@angular/material/input';\nimport { AsyncPipe } from '@angular/common';\nimport { MATERIAL_CONFIG } from '../../models/material-config.token';\n\n@Component({\n selector: 'df-mat-toggle',\n imports: [MatSlideToggle, FormField, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let toggleId = ngf.key() + '-toggle';\n\n <mat-slide-toggle\n ngForgeControl=\"button[role='switch']\"\n [id]=\"toggleId\"\n [formField]=\"f\"\n [color]=\"props()?.color || 'primary'\"\n [labelPosition]=\"props()?.labelPosition || 'after'\"\n [hideIcon]=\"props()?.hideIcon || false\"\n [disableRipple]=\"disableRipple()\"\n [required]=\"!!f().required()\"\n [tabIndex]=\"ngf.tabIndex() ?? 0\"\n class=\"toggle-container\"\n >\n {{ ngf.label() | dynamicText | async }}\n </mat-slide-toggle>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <div class=\"mat-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</div>\n }\n `,\n styleUrl: '../../styles/_form-field.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatToggleFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<boolean>();\n\n readonly props = input<MatToggleProps>();\n\n readonly disableRipple = computed(() => this.props()?.disableRipple ?? this.materialConfig?.disableRipple ?? false);\n}\n","/**\n * Material Design field type constants\n * Based on available field components in the /fields folder\n */\nexport const MatField = {\n Input: 'input',\n Select: 'select',\n Checkbox: 'checkbox',\n Button: 'button',\n Submit: 'submit',\n Next: 'next',\n Previous: 'previous',\n AddArrayItem: 'add-array-item',\n PrependArrayItem: 'prepend-array-item',\n InsertArrayItem: 'insert-array-item',\n RemoveArrayItem: 'remove-array-item',\n PopArrayItem: 'pop-array-item',\n ShiftArrayItem: 'shift-array-item',\n Textarea: 'textarea',\n Radio: 'radio',\n MultiCheckbox: 'multi-checkbox',\n Datepicker: 'datepicker',\n Slider: 'slider',\n Toggle: 'toggle',\n} as const;\n\nexport type MatFieldType = (typeof MatField)[keyof typeof MatField];\n","import { computed, inject, isSignal, Signal } from '@angular/core';\nimport { FieldDef } from '@ng-forge/dynamic-forms';\nimport { ARRAY_CONTEXT, buildBaseInputs, DEFAULT_PROPS, injectNonFieldLogicResolver } from '@ng-forge/dynamic-forms/integration';\n\n/**\n * Generic button mapper for custom events or basic buttons.\n * For specific button types (submit, next, prev, add/remove array items),\n * use the dedicated field types and their specific mappers.\n *\n * @param fieldDef The button field definition\n * @returns Signal containing Record of input names to values for ngComponentOutlet\n */\nexport function buttonFieldMapper(fieldDef: FieldDef<Record<string, unknown>>): Signal<Record<string, unknown>> {\n const defaultProps = inject(DEFAULT_PROPS);\n const arrayContext = inject(ARRAY_CONTEXT, { optional: true });\n const resolveLogic = injectNonFieldLogicResolver(fieldDef);\n\n return computed(() => {\n const baseInputs = buildBaseInputs(fieldDef, defaultProps());\n\n const inputs: Record<string, unknown> = {\n ...baseInputs,\n ...resolveLogic(),\n };\n\n // Add event binding for button events\n if ('event' in fieldDef && fieldDef.event !== undefined) {\n inputs['event'] = fieldDef.event;\n }\n\n // Add eventArgs binding if provided\n if ('eventArgs' in fieldDef && fieldDef.eventArgs !== undefined) {\n inputs['eventArgs'] = fieldDef.eventArgs;\n }\n\n // Add eventContext for token resolution (supports $template, $arrayKey, $index, etc.)\n const template = 'template' in fieldDef ? fieldDef.template : undefined;\n if (template || arrayContext) {\n // Read signal value if index is a signal (supports differential updates)\n const getIndex = () => {\n if (!arrayContext) return -1;\n return isSignal(arrayContext.index) ? arrayContext.index() : arrayContext.index;\n };\n\n inputs['eventContext'] = {\n key: fieldDef.key,\n index: getIndex(),\n arrayKey: arrayContext?.arrayKey ?? '',\n get formValue() {\n return arrayContext?.formValue ?? {};\n },\n template,\n };\n }\n\n return inputs;\n });\n}\n","import { FieldTypeDefinition } from '@ng-forge/dynamic-forms/integration';\nimport {\n addArrayItemButtonMapper,\n checkboxFieldMapper,\n datepickerFieldMapper,\n insertArrayItemButtonMapper,\n optionsFieldMapper,\n popArrayItemButtonMapper,\n prependArrayItemButtonMapper,\n removeArrayItemButtonMapper,\n shiftArrayItemButtonMapper,\n valueFieldMapper,\n} from '@ng-forge/dynamic-forms/integration';\nimport { MatField } from '../types/types';\nimport { buttonFieldMapper } from '../fields/button/mat-button.mapper';\nimport { nextButtonFieldMapper, previousButtonFieldMapper, submitButtonFieldMapper } from '../fields/button/mat-specific-button.mapper';\n\n/**\n * Base for value-bearing field types — waits for the mapper to emit the `field`\n * input before instantiating the component (matches NgForgeField's\n * `input.required<FieldTree<T>>()` contract).\n */\nconst VALUE_FIELD_TYPES_BASE = {\n renderReadyWhen: ['field'],\n} as const;\n\n/**\n * Base for action/button field types that don't bind to a form value.\n * Renders immediately, opted out of form-value collection.\n */\nconst BUTTON_FIELD_TYPES_BASE = {\n renderReadyWhen: [],\n valueHandling: 'exclude',\n} as const;\n\n/**\n * Material Design field type definitions\n * Follows the FieldTypeDefinition interface for proper registry integration\n */\nexport const MATERIAL_FIELD_TYPES: FieldTypeDefinition[] = [\n {\n name: MatField.Input,\n loadComponent: () => import('../fields/input/mat-input.component'),\n mapper: valueFieldMapper,\n propsToMeta: ['type'],\n scope: ['text-input', 'numeric'],\n addons: {\n slots: ['prefix', 'suffix'],\n },\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Select,\n loadComponent: () => import('../fields/select/mat-select.component'),\n mapper: optionsFieldMapper,\n scope: 'single-select',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Checkbox,\n loadComponent: () => import('../fields/checkbox/mat-checkbox.component'),\n mapper: checkboxFieldMapper,\n scope: 'boolean',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Button,\n loadComponent: () => import('../fields/button/mat-button.component'),\n mapper: buttonFieldMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Submit,\n loadComponent: () => import('../fields/button/mat-button.component'),\n mapper: submitButtonFieldMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Next,\n loadComponent: () => import('../fields/button/mat-button.component'),\n mapper: nextButtonFieldMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Previous,\n loadComponent: () => import('../fields/button/mat-button.component'),\n mapper: previousButtonFieldMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.AddArrayItem,\n loadComponent: () => import('../fields/button/mat-button.component'),\n mapper: addArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.PrependArrayItem,\n loadComponent: () => import('../fields/button/mat-button.component'),\n mapper: prependArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.InsertArrayItem,\n loadComponent: () => import('../fields/button/mat-button.component'),\n mapper: insertArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.RemoveArrayItem,\n loadComponent: () => import('../fields/button/mat-button.component'),\n mapper: removeArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.PopArrayItem,\n loadComponent: () => import('../fields/button/mat-button.component'),\n mapper: popArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.ShiftArrayItem,\n loadComponent: () => import('../fields/button/mat-button.component'),\n mapper: shiftArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Textarea,\n loadComponent: () => import('../fields/textarea/mat-textarea.component'),\n mapper: valueFieldMapper,\n propsToMeta: ['rows', 'cols'],\n scope: 'text-input',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Radio,\n loadComponent: () => import('../fields/radio/mat-radio.component'),\n mapper: optionsFieldMapper,\n scope: 'single-select',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.MultiCheckbox,\n loadComponent: () => import('../fields/multi-checkbox/mat-multi-checkbox.component'),\n mapper: optionsFieldMapper,\n scope: 'multi-select',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Datepicker,\n loadComponent: () => import('../fields/datepicker/mat-datepicker.component'),\n mapper: datepickerFieldMapper,\n scope: 'date',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Slider,\n loadComponent: () => import('../fields/slider/mat-slider.component'),\n mapper: valueFieldMapper,\n scope: 'numeric',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Toggle,\n loadComponent: () => import('../fields/toggle/mat-toggle.component'),\n mapper: checkboxFieldMapper,\n scope: 'boolean',\n ...VALUE_FIELD_TYPES_BASE,\n },\n];\n","import type { Provider } from '@angular/core';\nimport { DynamicFormError, type AddonTypeDefinition } from '@ng-forge/dynamic-forms';\nimport { ADDON_TYPE_DEFINITIONS, type FieldTypeDefinition, type WrapperTypeDefinition } from '@ng-forge/dynamic-forms/integration';\nimport { MATERIAL_FIELD_TYPES } from '../config/material-field-config';\nimport { MaterialConfig } from '../models/material-config';\nimport { MATERIAL_CONFIG } from '../models/material-config.token';\nimport type { MatButtonAddon, MatIconAddon } from '../types/addons';\n\n/** Field type definitions for Material Design components. */\nexport type MaterialFieldTypes = FieldTypeDefinition[];\n\ntype MaterialConfigFeature = {\n ɵkind: 'material-config';\n ɵproviders: Provider[];\n};\n\n/**\n * Default `withMaterialFields()` shape — field defs + the auto-included\n * addons feature so `mat-icon` / `mat-button` work out of the box.\n */\ntype MaterialFieldsWithAddons = [...MaterialFieldTypes, MaterialAddonsFeature, WrapperTypeDefinition];\n\ntype MaterialFieldsWithConfig = [...MaterialFieldTypes, MaterialAddonsFeature, WrapperTypeDefinition, MaterialConfigFeature];\n\n/**\n * Replaces the neutral core `field-errors` wrapper with the Material one, so\n * a container-level validation message renders like a field-level one.\n * Registered under the same name, so the later registration wins.\n */\nconst MATERIAL_FIELD_ERRORS_WRAPPER: WrapperTypeDefinition = {\n wrapperName: 'field-errors',\n loadComponent: () => import('../wrappers/field-errors/mat-field-errors-wrapper.component'),\n rendersFieldErrors: true,\n};\n\n/**\n * Configure dynamic forms with Material Design field types, with\n * Material-shipped addon types (`mat-icon`, `mat-button`) auto-included so\n * addons work out of the box.\n *\n * @param config - Optional global configuration for Material form fields\n * @returns Tuple of field type definitions, the addons feature, and\n * optionally a config feature.\n */\nexport function withMaterialFields(): MaterialFieldsWithAddons;\nexport function withMaterialFields(config: MaterialConfig): MaterialFieldsWithConfig;\nexport function withMaterialFields(config: MaterialConfig | undefined): MaterialFieldsWithAddons | MaterialFieldsWithConfig;\nexport function withMaterialFields(config?: MaterialConfig): MaterialFieldsWithAddons | MaterialFieldsWithConfig {\n // Always include the addons feature — mat-icon / mat-button are part of\n // the canonical Material surface.\n const base: unknown[] = [...MATERIAL_FIELD_TYPES, withMaterialAddons(), MATERIAL_FIELD_ERRORS_WRAPPER];\n\n if (config) {\n base.push({\n ɵkind: 'material-config',\n ɵproviders: [{ provide: MATERIAL_CONFIG, useValue: config }],\n } satisfies MaterialConfigFeature);\n return base as MaterialFieldsWithConfig;\n }\n\n return base as MaterialFieldsWithAddons;\n}\n\n/* -- Material addon types ----------------------------------------------- */\n\nconst MAT_ICON_KIND: AddonTypeDefinition<MatIconAddon> = {\n type: 'mat-icon',\n loadComponent: () => import('../addons/mat-icon-addon.component').then((m) => m.MatIconAddonComponent),\n validate: (addon, fieldKey) => {\n if (typeof addon.icon !== 'string' || addon.icon.length === 0) {\n throw new DynamicFormError(`Addon type 'mat-icon' requires a non-empty 'icon' string (field: '${fieldKey}').`);\n }\n },\n};\n\nconst MAT_BUTTON_KIND: AddonTypeDefinition<MatButtonAddon> = {\n type: 'mat-button',\n loadComponent: () => import('../addons/mat-button-addon.component').then((m) => m.MatButtonAddonComponent),\n validate: (addon, fieldKey) => {\n // Exactly one of preset / actionRef / action — validator drops the addon\n // (with warning) if the rule is violated.\n const set = [addon.preset, addon.actionRef, addon.action].filter((v) => v !== undefined);\n if (set.length > 1) {\n throw new DynamicFormError(\n `Addon type 'mat-button' on field '${fieldKey}' has more than one of preset/actionRef/action — exactly one allowed.`,\n );\n }\n // Icon-only buttons require ariaLabel for screen readers.\n if (addon.icon && !addon.label && !addon.ariaLabel) {\n throw new DynamicFormError(`Addon type 'mat-button' on field '${fieldKey}' is icon-only — provide 'ariaLabel' for accessibility.`);\n }\n },\n};\n\n/**\n * Feature type discriminant for the Material addons feature. Matches core's\n * `'addons'` type so providers flow through the standard addon-type pipeline\n * in `provideDynamicForm`.\n */\ntype MaterialAddonsFeature = {\n ɵkind: 'addons';\n ɵproviders: Provider[];\n};\n\n/** Register Material-shipped addon types (`mat-icon`, `mat-button`) standalone. */\nexport function withMaterialAddons(): MaterialAddonsFeature {\n return {\n ɵkind: 'addons',\n ɵproviders: [\n { provide: ADDON_TYPE_DEFINITIONS, useValue: MAT_ICON_KIND, multi: true },\n { provide: ADDON_TYPE_DEFINITIONS, useValue: MAT_BUTTON_KIND, multi: true },\n ],\n };\n}\n","import { AsyncPipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport { MatIcon } from '@angular/material/icon';\nimport { WrapperFieldInputs } from '@ng-forge/dynamic-forms/integration';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport type { MatIconAddon } from '../types/addons';\n\n/** Renderer for the `mat-icon` addon type. */\n@Component({\n selector: 'df-mat-icon-addon',\n imports: [MatIcon, AsyncPipe, DynamicTextPipe],\n template: `<mat-icon [attr.aria-label]=\"(ariaLabel() | dynamicText | async) ?? null\">{{ addon().icon }}</mat-icon>`,\n host: {\n '[attr.aria-hidden]': 'hasAriaLabel() ? null : \"true\"',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MatIconAddonComponent {\n readonly addon = input.required<MatIconAddon>();\n /** Accepted for contract uniformity — `NgComponentOutlet` setInput is strict; every type must declare it. */\n readonly fieldInputs = input<WrapperFieldInputs | undefined>();\n\n protected readonly ariaLabel = computed(() => this.addon().ariaLabel);\n protected readonly hasAriaLabel = computed(() => this.addon().ariaLabel !== undefined);\n}\n","import { AsyncPipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\nimport { MatButton, MatIconButton } from '@angular/material/button';\nimport { MatIcon } from '@angular/material/icon';\nimport { MatProgressSpinner } from '@angular/material/progress-spinner';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { injectNgForgeAddonAction, NgForgeAddonAction } from '@ng-forge/dynamic-forms/integration';\nimport type { MatButtonAddon } from '../types/addons';\n\n/** Renderer for the `mat-button` addon type. */\n@Component({\n selector: 'df-mat-button-addon',\n imports: [MatButton, MatIconButton, MatIcon, MatProgressSpinner, DynamicTextPipe, AsyncPipe],\n hostDirectives: [NgForgeAddonAction],\n template: `\n @if (isIconOnly()) {\n <button\n mat-icon-button\n type=\"button\"\n [color]=\"addon().color ?? null\"\n [disabled]=\"action.disabled() || action.loading()\"\n [attr.aria-label]=\"(ariaLabel() | dynamicText | async) ?? null\"\n [attr.aria-busy]=\"action.loading() || null\"\n (click)=\"action.dispatch()\"\n >\n @if (action.loading()) {\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"18\" aria-hidden=\"true\" />\n <span class=\"df-mat-sr-only\" role=\"status\">Loading…</span>\n } @else {\n <mat-icon aria-hidden=\"true\">{{ addon().icon }}</mat-icon>\n }\n </button>\n } @else {\n <button\n mat-button\n type=\"button\"\n [color]=\"addon().color ?? null\"\n [disabled]=\"action.disabled() || action.loading()\"\n [attr.aria-label]=\"(ariaLabel() | dynamicText | async) ?? null\"\n [attr.aria-busy]=\"action.loading() || null\"\n (click)=\"action.dispatch()\"\n >\n @if (action.loading()) {\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"18\" aria-hidden=\"true\" />\n <span class=\"df-mat-sr-only\" role=\"status\">Loading…</span>\n } @else if (addon().icon; as icon) {\n <mat-icon aria-hidden=\"true\">{{ icon }}</mat-icon>\n }\n {{ label() | dynamicText | async }}\n </button>\n }\n `,\n styles: [\n `\n .df-mat-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MatButtonAddonComponent {\n protected readonly action = injectNgForgeAddonAction<MatButtonAddon>();\n\n /** Re-exposed for template binding — same signal stored on the directive. */\n protected readonly addon = this.action.addon;\n\n protected readonly label = computed(() => this.addon().label);\n protected readonly ariaLabel = computed(() => this.addon().ariaLabel);\n protected readonly isIconOnly = computed(() => {\n const a = this.addon();\n return !!a.icon && !a.label;\n });\n}\n"]}
1
+ {"version":3,"file":"ng-forge-dynamic-forms-material.mjs","mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0Cc;;;AAKH;;AAEA;;;AAPU;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA/BT;;;;;;;;;;;;;;;;;;;;;;;;;;;ACiEE;;;;;;;;;AAQH;;AAEA;;AAEA;;AAEA;;AAEA;;;AAhBU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA/DT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDT;;;ACwGW;;;;AAMH;;AAET,IAKS;;IAGQ;AAER;;AAEA;;AAEA;;AAEA;;IAGU;;;AA3BA;AAlCjB;AACE;AACA;AACD;AACD;gFAME;;AAEE;AACA;AACA;oBAEA;;AAEE;AACE;AACA;;;;;;AAOC;;;;AAIR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA/IO;;;;;;;;;;;;;AAcT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkGC;AACE;AACA;AACD;AACD;4IAME;;AAEE;AACA;AACA;;;AAIE;AACE;AACA;;;;;;AAOC;;;;AAIR;AACF;;;AChHW;;;;AAIH;;AAET;AAEI;;AAEF;IAKO;;;;;AAKP;;;AAGF;AACE;AACE;AAEA;AACE;;AAEJ;AAEA;AACE;AACA;;;AAIE;;AAEJ;;;;;AAMI;;;AAEA;;AAEJ;;;AAlDiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA3CT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACwCE;;;;AAIH;;;AAJU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAJlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACcW;;;;;AAMH;;AAEA;;AAEA;;AAEA;;AAEA;;AAET;;AAhBmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAXlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACDW;;AAGH;;AAEA;;;AALU;;;;;;;;;;;;;;;;;;;;;;;;;AAXlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACDW;;AAGH;;AAEA;;AAEA;;;AAGP;;AACA;;;AAXiB;;;;;;;;;;;;;;AAXlB;;;;AAjBS;;;;;;;;;;;;;;;;;;AC6CE;;;AAKH;;AAEA;;AACA;;AAEA;;AACA;;;AAXU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAXlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAW;;;AAKH;;AAEA;;;AAPU;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA/BT;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACXI;AACJ;AACA;AACA;;;AAKE;AACE;AACA;;;AAKA;;;AAKA;;QAIF;AACA;;AAGI;;AACA;AACF;;;;AAKE;AACA;AACE;;;;;AAMN;AACF;AACF;;;AClCA;;;AAQA;AACE;AACA;;AAGF;AAEA;AAEA;AAEA;AAEA;AAEA;AAEA;AAIA;AAEA;AAEA;AAOO;AACL;;AAEE;AACA;;AAEA;AACA;AACE;AACD;AACD;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;AACD;;AAEE;AACA;AACA;AACA;AACD;;;;ACnKH;AACE;AACA;AACA;;AAeI;;;;AAOA;;AAE+B;AACjC;;AAGF;AACF;AAEA;AAEA;AACE;AACA;AACA;AACE;AACE;;;;AAKN;AACE;AACA;AACA;;AAIE;AACE;;QAKF;AACE;;;;;;AAkBF;AACA;;;AAGC;;AAEL;;;;;IC5FW;;;;AAGU;;;AANR;;;;AATF;AACT;AACA;AACA;AACA;AACE;AACD;;AAEF;;;;;ICyDoB;;;;;AAIA;AACjB;;;;;AATS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA1DD","names":[],"ignoreList":[],"sources":["../../../../packages/dynamic-forms-material/src/lib/fields/checkbox/mat-checkbox.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/datepicker/mat-datepicker.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/input/mat-input.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/multi-checkbox/mat-multi-checkbox.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/radio/mat-radio.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/select/mat-select.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/slider/mat-slider.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/button/mat-button.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/textarea/mat-textarea.component.ts","../../../../packages/dynamic-forms-material/src/lib/fields/toggle/mat-toggle.component.ts","../../../../packages/dynamic-forms-material/src/lib/types/types.ts","../../../../packages/dynamic-forms-material/src/lib/fields/button/mat-button.mapper.ts","../../../../packages/dynamic-forms-material/src/lib/config/material-field-config.ts","../../../../packages/dynamic-forms-material/src/lib/providers/material-providers.ts","../../../../packages/dynamic-forms-material/src/lib/addons/mat-icon-addon.component.ts","../../../../packages/dynamic-forms-material/src/lib/addons/mat-button-addon.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatCheckbox } from '@angular/material/checkbox';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatCheckboxProps } from './mat-checkbox.type';\nimport { MatError } from '@angular/material/input';\nimport { AsyncPipe } from '@angular/common';\nimport { MATERIAL_CONFIG } from '@ng-forge/dynamic-forms-material/shared';\n\n@Component({\n selector: 'df-mat-checkbox',\n imports: [MatCheckbox, FormField, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let checkboxId = ngf.key() + '-checkbox';\n\n <mat-checkbox\n ngForgeControl=\"input[type='checkbox']\"\n [id]=\"checkboxId\"\n [formField]=\"f\"\n [labelPosition]=\"props()?.labelPosition || 'after'\"\n [indeterminate]=\"props()?.indeterminate || false\"\n [color]=\"props()?.color || 'primary'\"\n [disableRipple]=\"disableRipple()\"\n [required]=\"!!f().required()\"\n [tabIndex]=\"ngf.tabIndex() ?? 0\"\n [attr.hidden]=\"f().hidden() || null\"\n >\n {{ ngf.label() | dynamicText | async }}\n </mat-checkbox>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\" [attr.hidden]=\"f().hidden() || null\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <div class=\"mat-hint\" [id]=\"ngf.hintId()\" [attr.hidden]=\"f().hidden() || null\">{{ hint | dynamicText | async }}</div>\n }\n `,\n styleUrl: '../../styles/_form-field.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatCheckboxFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<boolean>();\n\n readonly props = input<MatCheckboxProps>();\n\n readonly disableRipple = computed(() => this.props()?.disableRipple ?? this.materialConfig?.disableRipple ?? false);\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatError, MatFormField, MatLabel, MatSuffix } from '@angular/material/form-field';\nimport { MatHint, MatInput } from '@angular/material/input';\nimport { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material/datepicker';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatDatepickerProps } from './mat-datepicker.type';\nimport { provideNativeDateAdapter } from '@angular/material/core';\nimport { AsyncPipe } from '@angular/common';\nimport { MATERIAL_CONFIG } from '@ng-forge/dynamic-forms-material/shared';\n\n@Component({\n selector: 'df-mat-datepicker',\n imports: [\n MatFormField,\n MatLabel,\n MatInput,\n MatHint,\n MatDatepicker,\n MatDatepickerInput,\n MatDatepickerToggle,\n MatSuffix,\n FormField,\n MatError,\n DynamicTextPipe,\n AsyncPipe,\n NgForgeControl,\n ],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let inputId = ngf.key() + '-input';\n\n <mat-form-field\n [appearance]=\"appearance()\"\n [subscriptSizing]=\"subscriptSizing()\"\n [floatLabel]=\"floatLabel()\"\n [hideRequiredMarker]=\"hideRequiredMarker()\"\n >\n @if (ngf.label(); as label) {\n <mat-label>{{ label | dynamicText | async }}</mat-label>\n }\n\n <input\n matInput\n ngForgeControl\n [id]=\"inputId\"\n [matDatepicker]=\"picker\"\n [formField]=\"ngf.field()\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n [min]=\"minDate()\"\n [max]=\"maxDate()\"\n />\n\n <mat-datepicker-toggle matIconSuffix [for]=\"picker\" />\n <mat-datepicker #picker [startAt]=\"startAt()\" [startView]=\"props()?.startView || 'month'\" [touchUi]=\"props()?.touchUi ?? false\" />\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <mat-hint [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</mat-hint>\n }\n </mat-form-field>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n mat-form-field {\n width: 100%;\n }\n `,\n ],\n providers: [provideNativeDateAdapter()],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatDatepickerFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<string>();\n\n readonly minDate = input<Date | null>(null);\n readonly maxDate = input<Date | null>(null);\n readonly startAt = input<Date | null>(null);\n readonly props = input<MatDatepickerProps>();\n\n readonly appearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline');\n\n readonly subscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic');\n\n readonly floatLabel = computed(() => this.props()?.floatLabel ?? this.materialConfig?.floatLabel ?? 'auto');\n\n readonly hideRequiredMarker = computed(() => this.props()?.hideRequiredMarker ?? this.materialConfig?.hideRequiredMarker ?? false);\n}\n","import { AsyncPipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, forwardRef, inject, input, signal } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatError, MatFormField, MatLabel, MatPrefix, MatSuffix } from '@angular/material/form-field';\nimport { MatHint, MatInput } from '@angular/material/input';\nimport { AddonActionContext, AddonActionPreset, DynamicFormLogger } from '@ng-forge/dynamic-forms';\nimport { DfAddonSlot } from '@ng-forge/dynamic-forms/integration';\nimport { WrapperFieldInputs } from '@ng-forge/dynamic-forms/integration';\nimport { DynamicTextPipe, FIELD_SIGNAL_CONTEXT } from '@ng-forge/dynamic-forms/integration';\nimport {\n ADDON_PRESET_HANDLER,\n AddonPresetHandler,\n injectNgForgeAddons,\n injectNgForgeField,\n NgForgeAddons,\n NgForgeControl,\n NgForgeFieldHost,\n} from '@ng-forge/dynamic-forms/integration';\nimport { MATERIAL_CONFIG, MAT_INPUT_TYPE_OVERRIDE, runMatPresetAction } from '@ng-forge/dynamic-forms-material/shared';\nimport { MatInputAddon, MatInputProps } from './mat-input.type';\n\n@Component({\n selector: 'df-mat-input',\n imports: [\n MatFormField,\n MatLabel,\n MatInput,\n MatHint,\n MatError,\n MatPrefix,\n MatSuffix,\n FormField,\n DynamicTextPipe,\n AsyncPipe,\n NgForgeControl,\n DfAddonSlot,\n ],\n hostDirectives: [NgForgeFieldHost, NgForgeAddons],\n template: `\n @let inputId = ngf.key() + '-input';\n\n <mat-form-field\n [appearance]=\"appearance()\"\n [subscriptSizing]=\"subscriptSizing()\"\n [floatLabel]=\"floatLabel()\"\n [hideRequiredMarker]=\"hideRequiredMarker()\"\n >\n @if (ngf.label()) {\n <mat-label>{{ ngf.label() | dynamicText | async }}</mat-label>\n }\n @for (a of ngfa.prefixAddons(); track $index) {\n <df-addon-slot\n matPrefix\n [class.df-mat-addon-text]=\"a.type === 'text'\"\n [addon]=\"a\"\n [fieldInputs]=\"fieldInputs()\"\n [hidden]=\"ngfa.hiddenSignalCache().get(a)\"\n />\n }\n <input\n matInput\n ngForgeControl\n [id]=\"inputId\"\n [formField]=\"ngf.field()\"\n [type]=\"type()\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n />\n @for (a of ngfa.suffixAddons(); track $index) {\n <df-addon-slot\n matSuffix\n [class.df-mat-addon-text]=\"a.type === 'text'\"\n [addon]=\"a\"\n [fieldInputs]=\"fieldInputs()\"\n [hidden]=\"ngfa.hiddenSignalCache().get(a)\"\n />\n }\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <mat-hint [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</mat-hint>\n }\n </mat-form-field>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n mat-form-field {\n width: 100%;\n }\n :host([hidden]) {\n display: none !important;\n }\n /* matPrefix/matSuffix elements have no default Material spacing.\n All four sides + the text-type variants are independent CSS custom\n properties so consumers can tune each individually:\n prefix-outer = prefix slot's left (border-facing) padding\n prefix-inner = prefix slot's right (text-facing) padding\n suffix-inner = suffix slot's left (text-facing) padding\n suffix-outer = suffix slot's right (border-facing) padding\n Text variants override only the INNER side because <mat-icon> has\n ~4-6px optical padding inside its glyph box (so it looks \"padded\"\n even with a small CSS value) while text glyphs sit flush against\n their bounding box and need the extra room to match. */\n :host {\n --df-mat-addon-prefix-outer-padding: 0.75em;\n --df-mat-addon-prefix-inner-padding: 0.5em;\n --df-mat-addon-suffix-inner-padding: 0.5em;\n --df-mat-addon-suffix-outer-padding: 0.75em;\n --df-mat-addon-prefix-text-outer-padding: 1em;\n --df-mat-addon-prefix-text-inner-padding: 1em;\n --df-mat-addon-suffix-text-inner-padding: 1em;\n --df-mat-addon-suffix-text-outer-padding: 1em;\n }\n df-addon-slot[matprefix] {\n padding-left: var(--df-mat-addon-prefix-outer-padding);\n padding-right: var(--df-mat-addon-prefix-inner-padding);\n }\n df-addon-slot[matsuffix] {\n padding-left: var(--df-mat-addon-suffix-inner-padding);\n padding-right: var(--df-mat-addon-suffix-outer-padding);\n }\n df-addon-slot[matprefix].df-mat-addon-text {\n padding-left: var(--df-mat-addon-prefix-text-outer-padding);\n padding-right: var(--df-mat-addon-prefix-text-inner-padding);\n }\n df-addon-slot[matsuffix].df-mat-addon-text {\n padding-left: var(--df-mat-addon-suffix-text-inner-padding);\n padding-right: var(--df-mat-addon-suffix-text-outer-padding);\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: MAT_INPUT_TYPE_OVERRIDE,\n useFactory: () => signal<string | undefined>(undefined),\n },\n {\n // Adapter-specific preset semantics for `mat-button` addons (clear /\n // reset / paste / copy / toggle-password-visibility). The directive\n // (`NgForgeAddonAction`) delegates here when an addon configures a\n // `preset`. Per-mat-input-instance so the `typeOverride` signal is\n // scoped to one field.\n provide: ADDON_PRESET_HANDLER,\n useFactory: (): AddonPresetHandler => {\n const typeOverride = inject(MAT_INPUT_TYPE_OVERRIDE);\n const fsc = inject(FIELD_SIGNAL_CONTEXT, { optional: true });\n const logger = inject(DynamicFormLogger);\n // forwardRef for baselineType only — host.props()?.type gates toggle-password-visibility.\n const host = inject(forwardRef(() => MatInputFieldComponent));\n return {\n run: (preset: string, ctx: AddonActionContext) => {\n const fieldKey = ctx.field.key;\n return runMatPresetAction(preset as AddonActionPreset, ctx, {\n typeOverride,\n fieldValueSetter: ctx.setValue,\n fieldDefaultValueGetter:\n fsc && fieldKey ? () => (fsc.defaultValues() as Record<string, unknown> | undefined)?.[fieldKey] : undefined,\n baselineType: () => host.props()?.type,\n logger,\n });\n },\n };\n },\n },\n ],\n})\nexport default class MatInputFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<string>();\n protected readonly ngfa = injectNgForgeAddons<MatInputAddon>();\n\n readonly props = input<MatInputProps>();\n\n /**\n * Wrapper-style host bag pushed by `DfFieldOutlet`. Declared at the\n * component level so `setInputIfDeclared` (which uses\n * `reflectComponentType`) can write it.\n */\n readonly fieldInputs = input<WrapperFieldInputs | undefined>();\n\n /** Per-instance type override populated by `toggle-password-visibility` preset. */\n private readonly typeOverride = inject(MAT_INPUT_TYPE_OVERRIDE);\n\n readonly appearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline');\n\n readonly subscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic');\n\n readonly floatLabel = computed(() => this.props()?.floatLabel ?? this.materialConfig?.floatLabel ?? 'auto');\n\n readonly hideRequiredMarker = computed(() => this.props()?.hideRequiredMarker ?? this.materialConfig?.hideRequiredMarker ?? false);\n\n /** Override (set by `toggle-password-visibility` preset) wins over `props().type`. */\n protected readonly type = computed(() => this.typeOverride() ?? this.props()?.type ?? 'text');\n}\n","import { ChangeDetectionStrategy, Component, computed, input, linkedSignal } from '@angular/core';\nimport { MatCheckbox } from '@angular/material/checkbox';\nimport { FieldOption, ValueType } from '@ng-forge/dynamic-forms';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { injectNgForgeField, NgForgeFieldHost, isEqual, NgForgeControl } from '@ng-forge/dynamic-forms/integration';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport { MatMultiCheckboxProps } from './mat-multi-checkbox.type';\nimport { MatError } from '@angular/material/input';\nimport { AsyncPipe } from '@angular/common';\n\n@Component({\n selector: 'df-mat-multi-checkbox',\n imports: [MatCheckbox, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let checkboxGroupId = ngf.key() + '-checkbox-group';\n @let checked = checkedValuesMap();\n\n @if (ngf.label(); as label) {\n <div class=\"checkbox-group-label\">{{ label | dynamicText | async }}</div>\n }\n\n <div\n [id]=\"checkboxGroupId\"\n class=\"checkbox-group\"\n role=\"group\"\n [attr.aria-invalid]=\"ngf.ariaInvalid()\"\n [attr.aria-required]=\"ngf.ariaRequired()\"\n [attr.aria-describedby]=\"ngf.ariaDescribedBy()\"\n >\n @for (option of options(); track option.value) {\n <mat-checkbox\n ngForgeControl=\"input[type='checkbox']\"\n [checked]=\"checked['' + option.value]\"\n [disabled]=\"f().disabled() || option.disabled\"\n [color]=\"props()?.color || 'primary'\"\n [labelPosition]=\"props()?.labelPosition || 'after'\"\n (change)=\"onCheckboxChange(option, $event.checked)\"\n >\n {{ option.label | dynamicText | async }}\n </mat-checkbox>\n }\n </div>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <div class=\"mat-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</div>\n }\n `,\n styleUrl: '../../styles/_form-field.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatMultiCheckboxFieldComponent {\n protected readonly ngf = injectNgForgeField<ValueType[]>();\n\n readonly options = input<FieldOption<ValueType>[]>([]);\n readonly props = input<MatMultiCheckboxProps>();\n\n valueViewModel = linkedSignal<FieldOption<ValueType>[]>(\n () => {\n const currentValues = this.ngf.field()().value();\n return this.options().filter((option) => currentValues.includes(option.value));\n },\n { equal: isEqual },\n );\n\n /** Computed map of checked option values for O(1) lookup in template */\n readonly checkedValuesMap = computed(() => {\n const map: Record<string, boolean> = {};\n for (const opt of this.valueViewModel()) {\n map[String(opt.value)] = true;\n }\n return map;\n });\n\n constructor() {\n explicitEffect([this.valueViewModel], ([selectedOptions]) => {\n const selectedValues = selectedOptions.map((option) => option.value);\n\n if (!isEqual(selectedValues, this.ngf.field()().value())) {\n this.ngf.field()().value.set(selectedValues);\n }\n });\n\n explicitEffect([this.options], ([options]) => {\n const values = options.map((option) => option.value);\n const uniqueValues = new Set(values);\n\n if (values.length !== uniqueValues.size) {\n const duplicates = values.filter((value, index) => values.indexOf(value) !== index);\n throw new Error(`Duplicate option values detected in mat-multi-checkbox: ${duplicates.join(', ')}`);\n }\n });\n }\n\n onCheckboxChange(option: FieldOption<ValueType>, checked: boolean): void {\n this.valueViewModel.update((currentOptions) => {\n if (checked) {\n return currentOptions.some((opt) => opt.value === option.value) ? currentOptions : [...currentOptions, option];\n } else {\n return currentOptions.filter((opt) => opt.value !== option.value);\n }\n });\n }\n}\n","import { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatRadioButton, MatRadioGroup } from '@angular/material/radio';\nimport { FieldOption, ValueType } from '@ng-forge/dynamic-forms';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatRadioProps } from './mat-radio.type';\nimport { MatError } from '@angular/material/input';\nimport { AsyncPipe } from '@angular/common';\n\n@Component({\n selector: 'df-mat-radio',\n imports: [MatRadioGroup, MatRadioButton, FormField, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let radioGroupId = ngf.key() + '-radio-group';\n\n @if (ngf.label()) {\n <div class=\"radio-label\">{{ ngf.label() | dynamicText | async }}</div>\n }\n\n <mat-radio-group\n [id]=\"radioGroupId\"\n [formField]=\"f\"\n [attr.aria-invalid]=\"ngf.ariaInvalid()\"\n [attr.aria-required]=\"ngf.ariaRequired()\"\n [attr.aria-describedby]=\"ngf.ariaDescribedBy()\"\n >\n @for (option of options(); track option.value) {\n <mat-radio-button\n ngForgeControl=\"input[type='radio']\"\n [value]=\"option.value\"\n [disabled]=\"option.disabled || false\"\n [color]=\"props()?.color || 'primary'\"\n [labelPosition]=\"props()?.labelPosition || 'after'\"\n >\n {{ option.label | dynamicText | async }}\n </mat-radio-button>\n }\n </mat-radio-group>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <div class=\"mat-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</div>\n }\n `,\n styleUrl: '../../styles/_form-field.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatRadioFieldComponent {\n protected readonly ngf = injectNgForgeField<ValueType>();\n\n readonly options = input<FieldOption<ValueType>[]>([]);\n readonly props = input<MatRadioProps>();\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatError, MatFormField, MatLabel } from '@angular/material/form-field';\nimport { MatOption, MatSelect } from '@angular/material/select';\nimport { MatHint } from '@angular/material/input';\nimport { FieldOption, ValueType } from '@ng-forge/dynamic-forms';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatSelectProps } from './mat-select.type';\nimport { AsyncPipe } from '@angular/common';\nimport { MATERIAL_CONFIG } from '@ng-forge/dynamic-forms-material/shared';\n\n@Component({\n selector: 'df-mat-select',\n imports: [MatFormField, MatLabel, MatSelect, MatOption, MatHint, FormField, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let selectId = ngf.key() + '-select';\n\n <mat-form-field\n [appearance]=\"appearance()\"\n [subscriptSizing]=\"subscriptSizing()\"\n [floatLabel]=\"floatLabel()\"\n [hideRequiredMarker]=\"hideRequiredMarker()\"\n >\n @if (ngf.label(); as label) {\n <mat-label>{{ label | dynamicText | async }}</mat-label>\n }\n\n <mat-select\n ngForgeControl\n [id]=\"selectId\"\n [formField]=\"ngf.field()\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [multiple]=\"props()?.multiple || false\"\n [compareWith]=\"props()?.compareWith || defaultCompare\"\n >\n @for (option of options(); track option.value) {\n <mat-option [value]=\"option.value\" [disabled]=\"option.disabled || false\">\n {{ option.label | dynamicText | async }}\n </mat-option>\n }\n </mat-select>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <mat-hint [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</mat-hint>\n }\n </mat-form-field>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n mat-form-field {\n width: 100%;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatSelectFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<ValueType>();\n\n readonly options = input<FieldOption<ValueType>[]>([]);\n readonly props = input<MatSelectProps>();\n\n readonly appearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline');\n\n readonly subscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic');\n\n readonly floatLabel = computed(() => this.props()?.floatLabel ?? this.materialConfig?.floatLabel ?? 'auto');\n\n readonly hideRequiredMarker = computed(() => this.props()?.hideRequiredMarker ?? this.materialConfig?.hideRequiredMarker ?? false);\n\n defaultCompare = Object.is;\n}\n","import { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatSlider, MatSliderThumb } from '@angular/material/slider';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatSliderProps } from './mat-slider.type';\nimport { MatError } from '@angular/material/input';\nimport { AsyncPipe } from '@angular/common';\n\n@Component({\n selector: 'df-mat-slider',\n imports: [MatSlider, MatSliderThumb, MatError, DynamicTextPipe, AsyncPipe, FormField, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let inputId = ngf.key() + '-input';\n\n @if (ngf.label(); as label) {\n <label class=\"slider-label\" [for]=\"inputId\">{{ label | dynamicText | async }}</label>\n }\n\n <mat-slider\n [min]=\"f().min?.() ?? 0\"\n [max]=\"f().max?.() ?? 100\"\n [step]=\"step() ?? props()?.step ?? 1\"\n [discrete]=\"props()?.thumbLabel || props()?.showThumbLabel\"\n [showTickMarks]=\"props()?.tickInterval !== undefined\"\n [color]=\"props()?.color || 'primary'\"\n class=\"slider-container\"\n >\n <input matSliderThumb ngForgeControl [id]=\"inputId\" [formField]=\"f\" [attr.tabindex]=\"ngf.tabIndex()\" />\n </mat-slider>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <div class=\"mat-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</div>\n }\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n .slider-container {\n width: 100%;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatSliderFieldComponent {\n protected readonly ngf = injectNgForgeField<number>();\n\n readonly step = input<number>();\n\n readonly props = input<MatSliderProps>();\n}\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport { MatButton } from '@angular/material/button';\nimport { AsyncPipe } from '@angular/common';\nimport { FormEvent } from '@ng-forge/dynamic-forms';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { injectNgForgeAction, NgForgeActionHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatButtonProps } from './mat-button.type';\n\n@Component({\n selector: 'df-mat-button',\n imports: [MatButton, DynamicTextPipe, AsyncPipe],\n hostDirectives: [NgForgeActionHost],\n template: `\n @let buttonId = action.key() + '-button';\n <button\n mat-raised-button\n [id]=\"buttonId\"\n [type]=\"buttonType()\"\n [color]=\"props()?.color || 'primary'\"\n [disabled]=\"action.disabled()\"\n [attr.tabindex]=\"action.tabIndex()\"\n [attr.data-testid]=\"buttonTestId()\"\n (click)=\"onClick()\"\n >\n {{ action.label() | dynamicText | async }}\n </button>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n button {\n min-width: fit-content;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatButtonFieldComponent<TEvent extends FormEvent> {\n protected readonly action = injectNgForgeAction<TEvent>();\n\n readonly props = input<MatButtonProps>();\n\n readonly buttonType = computed(() => this.props()?.type ?? 'button');\n\n readonly buttonTestId = computed(() => `${this.buttonType()}-${this.action.key()}`);\n\n onClick(): void {\n if (this.buttonType() === 'submit') return;\n this.action.dispatch();\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatError, MatFormField, MatLabel } from '@angular/material/form-field';\nimport { MatHint, MatInput } from '@angular/material/input';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { MatTextareaProps } from './mat-textarea.type';\nimport { AsyncPipe } from '@angular/common';\nimport { MATERIAL_CONFIG } from '@ng-forge/dynamic-forms-material/shared';\n\n@Component({\n selector: 'df-mat-textarea',\n imports: [MatFormField, MatLabel, MatInput, MatHint, FormField, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let textareaId = ngf.key() + '-textarea';\n\n <mat-form-field\n [appearance]=\"appearance()\"\n [subscriptSizing]=\"subscriptSizing()\"\n [floatLabel]=\"floatLabel()\"\n [hideRequiredMarker]=\"hideRequiredMarker()\"\n >\n @if (ngf.label()) {\n <mat-label>{{ ngf.label() | dynamicText | async }}</mat-label>\n }\n\n <textarea\n ngForgeControl\n matInput\n [id]=\"textareaId\"\n [formField]=\"ngf.field()\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n [style.resize]=\"props()?.resize || 'vertical'\"\n ></textarea>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <mat-hint [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</mat-hint>\n }\n </mat-form-field>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n mat-form-field {\n width: 100%;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatTextareaFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<string>();\n\n readonly props = input<MatTextareaProps>();\n\n readonly appearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline');\n readonly subscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic');\n\n readonly floatLabel = computed(() => this.props()?.floatLabel ?? this.materialConfig?.floatLabel ?? 'auto');\n readonly hideRequiredMarker = computed(() => this.props()?.hideRequiredMarker ?? this.materialConfig?.hideRequiredMarker ?? false);\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { MatSlideToggle } from '@angular/material/slide-toggle';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\n\nimport { MatToggleProps } from './mat-toggle.type';\nimport { MatError } from '@angular/material/input';\nimport { AsyncPipe } from '@angular/common';\nimport { MATERIAL_CONFIG } from '@ng-forge/dynamic-forms-material/shared';\n\n@Component({\n selector: 'df-mat-toggle',\n imports: [MatSlideToggle, FormField, MatError, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let toggleId = ngf.key() + '-toggle';\n\n <mat-slide-toggle\n ngForgeControl=\"button[role='switch']\"\n [id]=\"toggleId\"\n [formField]=\"f\"\n [color]=\"props()?.color || 'primary'\"\n [labelPosition]=\"props()?.labelPosition || 'after'\"\n [hideIcon]=\"props()?.hideIcon || false\"\n [disableRipple]=\"disableRipple()\"\n [required]=\"!!f().required()\"\n [tabIndex]=\"ngf.tabIndex() ?? 0\"\n class=\"toggle-container\"\n >\n {{ ngf.label() | dynamicText | async }}\n </mat-slide-toggle>\n\n @if (ngf.errorsToDisplay()[0]; as error) {\n <mat-error [id]=\"ngf.errorId()\">{{ error.message }}</mat-error>\n } @else if (props()?.hint; as hint) {\n <div class=\"mat-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</div>\n }\n `,\n styleUrl: '../../styles/_form-field.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class MatToggleFieldComponent {\n private materialConfig = inject(MATERIAL_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<boolean>();\n\n readonly props = input<MatToggleProps>();\n\n readonly disableRipple = computed(() => this.props()?.disableRipple ?? this.materialConfig?.disableRipple ?? false);\n}\n","/**\n * Material Design field type constants\n * Based on available field components in the /fields folder\n */\nexport const MatField = {\n Input: 'input',\n Select: 'select',\n Checkbox: 'checkbox',\n Button: 'button',\n Submit: 'submit',\n Next: 'next',\n Previous: 'previous',\n AddArrayItem: 'add-array-item',\n PrependArrayItem: 'prepend-array-item',\n InsertArrayItem: 'insert-array-item',\n RemoveArrayItem: 'remove-array-item',\n PopArrayItem: 'pop-array-item',\n ShiftArrayItem: 'shift-array-item',\n Textarea: 'textarea',\n Radio: 'radio',\n MultiCheckbox: 'multi-checkbox',\n Datepicker: 'datepicker',\n Slider: 'slider',\n Toggle: 'toggle',\n} as const;\n\nexport type MatFieldType = (typeof MatField)[keyof typeof MatField];\n","import { computed, inject, isSignal, Signal } from '@angular/core';\nimport { FieldDef } from '@ng-forge/dynamic-forms';\nimport { ARRAY_CONTEXT, buildBaseInputs, DEFAULT_PROPS, injectNonFieldLogicResolver } from '@ng-forge/dynamic-forms/integration';\n\n/**\n * Generic button mapper for custom events or basic buttons.\n * For specific button types (submit, next, prev, add/remove array items),\n * use the dedicated field types and their specific mappers.\n *\n * @param fieldDef The button field definition\n * @returns Signal containing Record of input names to values for ngComponentOutlet\n */\nexport function buttonFieldMapper(fieldDef: FieldDef<Record<string, unknown>>): Signal<Record<string, unknown>> {\n const defaultProps = inject(DEFAULT_PROPS);\n const arrayContext = inject(ARRAY_CONTEXT, { optional: true });\n const resolveLogic = injectNonFieldLogicResolver(fieldDef);\n\n return computed(() => {\n const baseInputs = buildBaseInputs(fieldDef, defaultProps());\n\n const inputs: Record<string, unknown> = {\n ...baseInputs,\n ...resolveLogic(),\n };\n\n // Add event binding for button events\n if ('event' in fieldDef && fieldDef.event !== undefined) {\n inputs['event'] = fieldDef.event;\n }\n\n // Add eventArgs binding if provided\n if ('eventArgs' in fieldDef && fieldDef.eventArgs !== undefined) {\n inputs['eventArgs'] = fieldDef.eventArgs;\n }\n\n // Add eventContext for token resolution (supports $template, $arrayKey, $index, etc.)\n const template = 'template' in fieldDef ? fieldDef.template : undefined;\n if (template || arrayContext) {\n // Read signal value if index is a signal (supports differential updates)\n const getIndex = () => {\n if (!arrayContext) return -1;\n return isSignal(arrayContext.index) ? arrayContext.index() : arrayContext.index;\n };\n\n inputs['eventContext'] = {\n key: fieldDef.key,\n index: getIndex(),\n arrayKey: arrayContext?.arrayKey ?? '',\n get formValue() {\n return arrayContext?.formValue ?? {};\n },\n template,\n };\n }\n\n return inputs;\n });\n}\n","/* eslint-disable @nx/enforce-module-boundaries -- Package self-imports preserve ng-packagr secondary entry points. */\nimport { FieldTypeDefinition } from '@ng-forge/dynamic-forms/integration';\nimport {\n addArrayItemButtonMapper,\n checkboxFieldMapper,\n datepickerFieldMapper,\n insertArrayItemButtonMapper,\n optionsFieldMapper,\n popArrayItemButtonMapper,\n prependArrayItemButtonMapper,\n removeArrayItemButtonMapper,\n shiftArrayItemButtonMapper,\n valueFieldMapper,\n} from '@ng-forge/dynamic-forms/integration';\nimport { MatField } from '../types/types';\nimport { buttonFieldMapper } from '../fields/button/mat-button.mapper';\nimport { nextButtonFieldMapper, previousButtonFieldMapper, submitButtonFieldMapper } from '../fields/button/mat-specific-button.mapper';\n\n/**\n * Base for value-bearing field types — waits for the mapper to emit the `field`\n * input before instantiating the component (matches NgForgeField's\n * `input.required<FieldTree<T>>()` contract).\n */\nconst VALUE_FIELD_TYPES_BASE = {\n renderReadyWhen: ['field'],\n} as const;\n\n/**\n * Base for action/button field types that don't bind to a form value.\n * Renders immediately, opted out of form-value collection.\n */\nconst BUTTON_FIELD_TYPES_BASE = {\n renderReadyWhen: [],\n valueHandling: 'exclude',\n} as const;\n\nconst loadInputComponent = () =>\n import('@ng-forge/dynamic-forms-material/lazy/input').then(({ MatInputFieldComponent }) => MatInputFieldComponent);\nconst loadSelectComponent = () =>\n import('@ng-forge/dynamic-forms-material/lazy/select').then(({ MatSelectFieldComponent }) => MatSelectFieldComponent);\nconst loadCheckboxComponent = () =>\n import('@ng-forge/dynamic-forms-material/lazy/checkbox').then(({ MatCheckboxFieldComponent }) => MatCheckboxFieldComponent);\nconst loadButtonComponent = () =>\n import('@ng-forge/dynamic-forms-material/lazy/button').then(({ MatButtonFieldComponent }) => MatButtonFieldComponent);\nconst loadTextareaComponent = () =>\n import('@ng-forge/dynamic-forms-material/lazy/textarea').then(({ MatTextareaFieldComponent }) => MatTextareaFieldComponent);\nconst loadRadioComponent = () =>\n import('@ng-forge/dynamic-forms-material/lazy/radio').then(({ MatRadioFieldComponent }) => MatRadioFieldComponent);\nconst loadMultiCheckboxComponent = () =>\n import('@ng-forge/dynamic-forms-material/lazy/multi-checkbox').then(\n ({ MatMultiCheckboxFieldComponent }) => MatMultiCheckboxFieldComponent,\n );\nconst loadDatepickerComponent = () =>\n import('@ng-forge/dynamic-forms-material/lazy/datepicker').then(({ MatDatepickerFieldComponent }) => MatDatepickerFieldComponent);\nconst loadSliderComponent = () =>\n import('@ng-forge/dynamic-forms-material/lazy/slider').then(({ MatSliderFieldComponent }) => MatSliderFieldComponent);\nconst loadToggleComponent = () =>\n import('@ng-forge/dynamic-forms-material/lazy/toggle').then(({ MatToggleFieldComponent }) => MatToggleFieldComponent);\n\n/**\n * Material Design field type definitions\n * Follows the FieldTypeDefinition interface for proper registry integration\n */\nexport const MATERIAL_FIELD_TYPES: FieldTypeDefinition[] = [\n {\n name: MatField.Input,\n loadComponent: loadInputComponent,\n mapper: valueFieldMapper,\n propsToMeta: ['type'],\n scope: ['text-input', 'numeric'],\n addons: {\n slots: ['prefix', 'suffix'],\n },\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Select,\n loadComponent: loadSelectComponent,\n mapper: optionsFieldMapper,\n scope: 'single-select',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Checkbox,\n loadComponent: loadCheckboxComponent,\n mapper: checkboxFieldMapper,\n scope: 'boolean',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Button,\n loadComponent: loadButtonComponent,\n mapper: buttonFieldMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Submit,\n loadComponent: loadButtonComponent,\n mapper: submitButtonFieldMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Next,\n loadComponent: loadButtonComponent,\n mapper: nextButtonFieldMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Previous,\n loadComponent: loadButtonComponent,\n mapper: previousButtonFieldMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.AddArrayItem,\n loadComponent: loadButtonComponent,\n mapper: addArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.PrependArrayItem,\n loadComponent: loadButtonComponent,\n mapper: prependArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.InsertArrayItem,\n loadComponent: loadButtonComponent,\n mapper: insertArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.RemoveArrayItem,\n loadComponent: loadButtonComponent,\n mapper: removeArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.PopArrayItem,\n loadComponent: loadButtonComponent,\n mapper: popArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.ShiftArrayItem,\n loadComponent: loadButtonComponent,\n mapper: shiftArrayItemButtonMapper,\n ...BUTTON_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Textarea,\n loadComponent: loadTextareaComponent,\n mapper: valueFieldMapper,\n propsToMeta: ['rows', 'cols'],\n scope: 'text-input',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Radio,\n loadComponent: loadRadioComponent,\n mapper: optionsFieldMapper,\n scope: 'single-select',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.MultiCheckbox,\n loadComponent: loadMultiCheckboxComponent,\n mapper: optionsFieldMapper,\n scope: 'multi-select',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Datepicker,\n loadComponent: loadDatepickerComponent,\n mapper: datepickerFieldMapper,\n scope: 'date',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Slider,\n loadComponent: loadSliderComponent,\n mapper: valueFieldMapper,\n scope: 'numeric',\n ...VALUE_FIELD_TYPES_BASE,\n },\n {\n name: MatField.Toggle,\n loadComponent: loadToggleComponent,\n mapper: checkboxFieldMapper,\n scope: 'boolean',\n ...VALUE_FIELD_TYPES_BASE,\n },\n];\n","/* eslint-disable @nx/enforce-module-boundaries -- Package self-imports preserve ng-packagr secondary entry points. */\nimport type { Provider } from '@angular/core';\nimport { DynamicFormError, type AddonTypeDefinition } from '@ng-forge/dynamic-forms';\nimport { ADDON_TYPE_DEFINITIONS, type FieldTypeDefinition, type WrapperTypeDefinition } from '@ng-forge/dynamic-forms/integration';\nimport { MATERIAL_CONFIG, type MaterialConfig, type MatButtonAddon, type MatIconAddon } from '@ng-forge/dynamic-forms-material/shared';\nimport { MATERIAL_FIELD_TYPES } from '../config/material-field-config';\n\n/** Field type definitions for Material Design components. */\nexport type MaterialFieldTypes = FieldTypeDefinition[];\n\ntype MaterialConfigFeature = {\n ɵkind: 'material-config';\n ɵproviders: Provider[];\n};\n\n/**\n * Default `withMaterialFields()` shape — field defs + the auto-included\n * addons feature so `mat-icon` / `mat-button` work out of the box.\n */\ntype MaterialFieldsWithAddons = [...MaterialFieldTypes, MaterialAddonsFeature, WrapperTypeDefinition];\n\ntype MaterialFieldsWithConfig = [...MaterialFieldTypes, MaterialAddonsFeature, WrapperTypeDefinition, MaterialConfigFeature];\n\n/**\n * Replaces the neutral core `field-errors` wrapper with the Material one, so\n * a container-level validation message renders like a field-level one.\n * Registered under the same name, so the later registration wins.\n */\nconst MATERIAL_FIELD_ERRORS_WRAPPER: WrapperTypeDefinition = {\n wrapperName: 'field-errors',\n loadComponent: () => import('../wrappers/field-errors/mat-field-errors-wrapper.component'),\n rendersFieldErrors: true,\n};\n\n/**\n * Configure dynamic forms with Material Design field types, with\n * Material-shipped addon types (`mat-icon`, `mat-button`) auto-included so\n * addons work out of the box.\n *\n * @param config - Optional global configuration for Material form fields\n * @returns Tuple of field type definitions, the addons feature, and\n * optionally a config feature.\n */\nexport function withMaterialFields(): MaterialFieldsWithAddons;\nexport function withMaterialFields(config: MaterialConfig): MaterialFieldsWithConfig;\nexport function withMaterialFields(config: MaterialConfig | undefined): MaterialFieldsWithAddons | MaterialFieldsWithConfig;\nexport function withMaterialFields(config?: MaterialConfig): MaterialFieldsWithAddons | MaterialFieldsWithConfig {\n // Always include the addons feature — mat-icon / mat-button are part of\n // the canonical Material surface.\n const base: unknown[] = [...MATERIAL_FIELD_TYPES, withMaterialAddons(), MATERIAL_FIELD_ERRORS_WRAPPER];\n\n if (config) {\n base.push({\n ɵkind: 'material-config',\n ɵproviders: [{ provide: MATERIAL_CONFIG, useValue: config }],\n } satisfies MaterialConfigFeature);\n return base as MaterialFieldsWithConfig;\n }\n\n return base as MaterialFieldsWithAddons;\n}\n\n/* -- Material addon types ----------------------------------------------- */\n\nconst MAT_ICON_KIND: AddonTypeDefinition<MatIconAddon> = {\n type: 'mat-icon',\n loadComponent: () => import('@ng-forge/dynamic-forms-material/lazy/addon-icon').then((m) => m.MatIconAddonComponent),\n validate: (addon, fieldKey) => {\n if (typeof addon.icon !== 'string' || addon.icon.length === 0) {\n throw new DynamicFormError(`Addon type 'mat-icon' requires a non-empty 'icon' string (field: '${fieldKey}').`);\n }\n },\n};\n\nconst MAT_BUTTON_KIND: AddonTypeDefinition<MatButtonAddon> = {\n type: 'mat-button',\n loadComponent: () => import('@ng-forge/dynamic-forms-material/lazy/addon-button').then((m) => m.MatButtonAddonComponent),\n validate: (addon, fieldKey) => {\n // Exactly one of preset / actionRef / action — validator drops the addon\n // (with warning) if the rule is violated.\n const set = [addon.preset, addon.actionRef, addon.action].filter((v) => v !== undefined);\n if (set.length > 1) {\n throw new DynamicFormError(\n `Addon type 'mat-button' on field '${fieldKey}' has more than one of preset/actionRef/action — exactly one allowed.`,\n );\n }\n // Icon-only buttons require ariaLabel for screen readers.\n if (addon.icon && !addon.label && !addon.ariaLabel) {\n throw new DynamicFormError(`Addon type 'mat-button' on field '${fieldKey}' is icon-only — provide 'ariaLabel' for accessibility.`);\n }\n },\n};\n\n/**\n * Feature type discriminant for the Material addons feature. Matches core's\n * `'addons'` type so providers flow through the standard addon-type pipeline\n * in `provideDynamicForm`.\n */\ntype MaterialAddonsFeature = {\n ɵkind: 'addons';\n ɵproviders: Provider[];\n};\n\n/** Register Material-shipped addon types (`mat-icon`, `mat-button`) standalone. */\nexport function withMaterialAddons(): MaterialAddonsFeature {\n return {\n ɵkind: 'addons',\n ɵproviders: [\n { provide: ADDON_TYPE_DEFINITIONS, useValue: MAT_ICON_KIND, multi: true },\n { provide: ADDON_TYPE_DEFINITIONS, useValue: MAT_BUTTON_KIND, multi: true },\n ],\n };\n}\n","import { AsyncPipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport { MatIcon } from '@angular/material/icon';\nimport { WrapperFieldInputs } from '@ng-forge/dynamic-forms/integration';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport type { MatIconAddon } from '@ng-forge/dynamic-forms-material/shared';\n\n/** Renderer for the `mat-icon` addon type. */\n@Component({\n selector: 'df-mat-icon-addon',\n imports: [MatIcon, AsyncPipe, DynamicTextPipe],\n template: `<mat-icon [attr.aria-label]=\"(ariaLabel() | dynamicText | async) ?? null\">{{ addon().icon }}</mat-icon>`,\n host: {\n '[attr.aria-hidden]': 'hasAriaLabel() ? null : \"true\"',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MatIconAddonComponent {\n readonly addon = input.required<MatIconAddon>();\n /** Accepted for contract uniformity — `NgComponentOutlet` setInput is strict; every type must declare it. */\n readonly fieldInputs = input<WrapperFieldInputs | undefined>();\n\n protected readonly ariaLabel = computed(() => this.addon().ariaLabel);\n protected readonly hasAriaLabel = computed(() => this.addon().ariaLabel !== undefined);\n}\n","import { AsyncPipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\nimport { MatButton, MatIconButton } from '@angular/material/button';\nimport { MatIcon } from '@angular/material/icon';\nimport { MatProgressSpinner } from '@angular/material/progress-spinner';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { injectNgForgeAddonAction, NgForgeAddonAction } from '@ng-forge/dynamic-forms/integration';\nimport type { MatButtonAddon } from '@ng-forge/dynamic-forms-material/shared';\n\n/** Renderer for the `mat-button` addon type. */\n@Component({\n selector: 'df-mat-button-addon',\n imports: [MatButton, MatIconButton, MatIcon, MatProgressSpinner, DynamicTextPipe, AsyncPipe],\n hostDirectives: [NgForgeAddonAction],\n template: `\n @if (isIconOnly()) {\n <button\n mat-icon-button\n type=\"button\"\n [color]=\"addon().color ?? null\"\n [disabled]=\"action.disabled() || action.loading()\"\n [attr.aria-label]=\"(ariaLabel() | dynamicText | async) ?? null\"\n [attr.aria-busy]=\"action.loading() || null\"\n (click)=\"action.dispatch()\"\n >\n @if (action.loading()) {\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"18\" aria-hidden=\"true\" />\n <span class=\"df-mat-sr-only\" role=\"status\">Loading…</span>\n } @else {\n <mat-icon aria-hidden=\"true\">{{ addon().icon }}</mat-icon>\n }\n </button>\n } @else {\n <button\n mat-button\n type=\"button\"\n [color]=\"addon().color ?? null\"\n [disabled]=\"action.disabled() || action.loading()\"\n [attr.aria-label]=\"(ariaLabel() | dynamicText | async) ?? null\"\n [attr.aria-busy]=\"action.loading() || null\"\n (click)=\"action.dispatch()\"\n >\n @if (action.loading()) {\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"18\" aria-hidden=\"true\" />\n <span class=\"df-mat-sr-only\" role=\"status\">Loading…</span>\n } @else if (addon().icon; as icon) {\n <mat-icon aria-hidden=\"true\">{{ icon }}</mat-icon>\n }\n {{ label() | dynamicText | async }}\n </button>\n }\n `,\n styles: [\n `\n .df-mat-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MatButtonAddonComponent {\n protected readonly action = injectNgForgeAddonAction<MatButtonAddon>();\n\n /** Re-exposed for template binding — same signal stored on the directive. */\n protected readonly addon = this.action.addon;\n\n protected readonly label = computed(() => this.addon().label);\n protected readonly ariaLabel = computed(() => this.addon().ariaLabel);\n protected readonly isIconOnly = computed(() => {\n const a = this.addon();\n return !!a.icon && !a.label;\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-forge/dynamic-forms-material",
3
- "version": "1.2.0-next.6",
3
+ "version": "1.2.0-next.7",
4
4
  "description": "Angular Material integration for @ng-forge/dynamic-forms. Pre-built Material Design form components.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,7 +23,7 @@
23
23
  "form-builder",
24
24
  "ng-forge"
25
25
  ],
26
- "sideEffects": true,
26
+ "sideEffects": false,
27
27
  "exports": {
28
28
  ".": {
29
29
  "types": "./types/ng-forge-dynamic-forms-material.d.ts",
@@ -32,6 +32,58 @@
32
32
  "./styles/defaults": "./styles/_defaults.scss",
33
33
  "./package.json": {
34
34
  "default": "./package.json"
35
+ },
36
+ "./lazy/addon-button": {
37
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-addon-button.d.ts",
38
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-addon-button.mjs"
39
+ },
40
+ "./lazy/addon-icon": {
41
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-addon-icon.d.ts",
42
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-addon-icon.mjs"
43
+ },
44
+ "./lazy/button": {
45
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-button.d.ts",
46
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-button.mjs"
47
+ },
48
+ "./lazy/checkbox": {
49
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-checkbox.d.ts",
50
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-checkbox.mjs"
51
+ },
52
+ "./lazy/datepicker": {
53
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-datepicker.d.ts",
54
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-datepicker.mjs"
55
+ },
56
+ "./lazy/input": {
57
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-input.d.ts",
58
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-input.mjs"
59
+ },
60
+ "./lazy/multi-checkbox": {
61
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-multi-checkbox.d.ts",
62
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-multi-checkbox.mjs"
63
+ },
64
+ "./lazy/radio": {
65
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-radio.d.ts",
66
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-radio.mjs"
67
+ },
68
+ "./lazy/select": {
69
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-select.d.ts",
70
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-select.mjs"
71
+ },
72
+ "./lazy/slider": {
73
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-slider.d.ts",
74
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-slider.mjs"
75
+ },
76
+ "./lazy/textarea": {
77
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-textarea.d.ts",
78
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-textarea.mjs"
79
+ },
80
+ "./lazy/toggle": {
81
+ "types": "./types/ng-forge-dynamic-forms-material-lazy-toggle.d.ts",
82
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-lazy-toggle.mjs"
83
+ },
84
+ "./shared": {
85
+ "types": "./types/ng-forge-dynamic-forms-material-shared.d.ts",
86
+ "default": "./fesm2022/ng-forge-dynamic-forms-material-shared.mjs"
35
87
  }
36
88
  },
37
89
  "engines": {
@@ -42,7 +94,7 @@
42
94
  "@angular/core": "^22.0.0",
43
95
  "@angular/forms": "^22.0.0",
44
96
  "@angular/material": "^22.0.0",
45
- "@ng-forge/dynamic-forms": "~1.2.0-next.6",
97
+ "@ng-forge/dynamic-forms": "~1.2.0-next.7",
46
98
  "rxjs": ">=7.0.0"
47
99
  },
48
100
  "dependencies": {
@@ -0,0 +1,18 @@
1
+ import * as _ng_forge_dynamic_forms from '@ng-forge/dynamic-forms';
2
+ import * as _angular_core from '@angular/core';
3
+ import * as _ng_forge_dynamic_forms_integration from '@ng-forge/dynamic-forms/integration';
4
+ import { MatButtonAddon } from '@ng-forge/dynamic-forms-material/shared';
5
+
6
+ /** Renderer for the `mat-button` addon type. */
7
+ declare class MatButtonAddonComponent {
8
+ protected readonly action: _ng_forge_dynamic_forms_integration.TypedNgForgeAddonAction<MatButtonAddon>;
9
+ /** Re-exposed for template binding — same signal stored on the directive. */
10
+ protected readonly addon: _angular_core.Signal<MatButtonAddon>;
11
+ protected readonly label: _angular_core.Signal<_ng_forge_dynamic_forms.DynamicText | undefined>;
12
+ protected readonly ariaLabel: _angular_core.Signal<_ng_forge_dynamic_forms.DynamicText | undefined>;
13
+ protected readonly isIconOnly: _angular_core.Signal<boolean>;
14
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MatButtonAddonComponent, never>;
15
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MatButtonAddonComponent, "df-mat-button-addon", never, {}, {}, never, never, true, [{ directive: typeof _ng_forge_dynamic_forms_integration.NgForgeAddonAction; inputs: {}; outputs: {}; }]>;
16
+ }
17
+
18
+ export { MatButtonAddonComponent };
@@ -0,0 +1,17 @@
1
+ import * as _ng_forge_dynamic_forms from '@ng-forge/dynamic-forms';
2
+ import * as _angular_core from '@angular/core';
3
+ import { WrapperFieldInputs } from '@ng-forge/dynamic-forms/integration';
4
+ import { MatIconAddon } from '@ng-forge/dynamic-forms-material/shared';
5
+
6
+ /** Renderer for the `mat-icon` addon type. */
7
+ declare class MatIconAddonComponent {
8
+ readonly addon: _angular_core.InputSignal<MatIconAddon>;
9
+ /** Accepted for contract uniformity — `NgComponentOutlet` setInput is strict; every type must declare it. */
10
+ readonly fieldInputs: _angular_core.InputSignal<WrapperFieldInputs | undefined>;
11
+ protected readonly ariaLabel: _angular_core.Signal<_ng_forge_dynamic_forms.DynamicText | undefined>;
12
+ protected readonly hasAriaLabel: _angular_core.Signal<boolean>;
13
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MatIconAddonComponent, never>;
14
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MatIconAddonComponent, "df-mat-icon-addon", never, { "addon": { "alias": "addon"; "required": true; "isSignal": true; }; "fieldInputs": { "alias": "fieldInputs"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
15
+ }
16
+
17
+ export { MatIconAddonComponent };
@@ -0,0 +1,114 @@
1
+ import { FormEvent, AppendArrayItemEvent, ArrayAllowedChildren, InsertArrayItemEvent, NextPageEvent, PopArrayItemEvent, PrependArrayItemEvent, PreviousPageEvent, RemoveAtIndexEvent, ShiftArrayItemEvent, FormSubmitEvent } from '@ng-forge/dynamic-forms';
2
+ import * as _ng_forge_dynamic_forms_integration from '@ng-forge/dynamic-forms/integration';
3
+ import { ButtonField } from '@ng-forge/dynamic-forms/integration';
4
+ import * as _angular_core from '@angular/core';
5
+
6
+ interface MatButtonProps {
7
+ color?: 'primary' | 'accent' | 'warn';
8
+ type?: 'button' | 'submit' | 'reset';
9
+ }
10
+ type MatButtonField<TEvent extends FormEvent> = ButtonField<MatButtonProps, TEvent>;
11
+ /** Specific button field types with preconfigured events */
12
+ /** Submit button field - automatically disabled when form is invalid */
13
+ type MatSubmitButtonField = Omit<MatButtonField<FormSubmitEvent>, 'event' | 'type' | 'eventArgs'> & {
14
+ type: 'submit';
15
+ };
16
+ /** Next page button field - with preconfigured NextPageEvent */
17
+ type MatNextButtonField = Omit<MatButtonField<NextPageEvent>, 'event' | 'type' | 'eventArgs'> & {
18
+ type: 'next';
19
+ };
20
+ /** Previous page button field - with preconfigured PreviousPageEvent */
21
+ type MatPreviousButtonField = Omit<MatButtonField<PreviousPageEvent>, 'event' | 'type' | 'eventArgs'> & {
22
+ type: 'previous';
23
+ };
24
+ /** Add array item button field - dispatches AppendArrayItemEvent */
25
+ type MatAddArrayItemButtonField = Omit<MatButtonField<AppendArrayItemEvent>, 'event' | 'type' | 'eventArgs'> & {
26
+ type: 'add-array-item' | 'addArrayItem';
27
+ /**
28
+ * The key of the array field to add items to.
29
+ * Required when the button is placed outside the array.
30
+ * When inside an array, this is automatically determined from context.
31
+ */
32
+ arrayKey?: string;
33
+ /**
34
+ * Template for the new array item. REQUIRED.
35
+ * - Single field (ArrayAllowedChildren): Creates a primitive item (field's value is extracted directly)
36
+ * - Array of fields (ArrayAllowedChildren[]): Creates an object item (fields merged into object)
37
+ */
38
+ template: ArrayAllowedChildren | readonly ArrayAllowedChildren[];
39
+ };
40
+ /** Prepend array item button field - dispatches PrependArrayItemEvent (adds at beginning) */
41
+ type MatPrependArrayItemButtonField = Omit<MatButtonField<PrependArrayItemEvent>, 'event' | 'type' | 'eventArgs'> & {
42
+ type: 'prepend-array-item' | 'prependArrayItem';
43
+ /**
44
+ * The key of the array field to prepend items to.
45
+ * Required when the button is placed outside the array.
46
+ * When inside an array, this is automatically determined from context.
47
+ */
48
+ arrayKey?: string;
49
+ /**
50
+ * Template for the new array item. REQUIRED.
51
+ * - Single field (ArrayAllowedChildren): Creates a primitive item (field's value is extracted directly)
52
+ * - Array of fields (ArrayAllowedChildren[]): Creates an object item (fields merged into object)
53
+ */
54
+ template: ArrayAllowedChildren | readonly ArrayAllowedChildren[];
55
+ };
56
+ /** Insert array item button field - dispatches InsertArrayItemEvent (adds at specific index) */
57
+ type MatInsertArrayItemButtonField = Omit<MatButtonField<InsertArrayItemEvent>, 'event' | 'type' | 'eventArgs'> & {
58
+ type: 'insert-array-item' | 'insertArrayItem';
59
+ /**
60
+ * The key of the array field to insert items into.
61
+ * Required when the button is placed outside the array.
62
+ * When inside an array, this is automatically determined from context.
63
+ */
64
+ arrayKey?: string;
65
+ /** The index at which to insert the new item. */
66
+ index: number;
67
+ /**
68
+ * Template for the new array item. REQUIRED.
69
+ * - Single field (ArrayAllowedChildren): Creates a primitive item (field's value is extracted directly)
70
+ * - Array of fields (ArrayAllowedChildren[]): Creates an object item (fields merged into object)
71
+ */
72
+ template: ArrayAllowedChildren | readonly ArrayAllowedChildren[];
73
+ };
74
+ /** Remove array item button field - dispatches RemoveAtIndexEvent or PopArrayItemEvent */
75
+ type MatRemoveArrayItemButtonField = Omit<MatButtonField<RemoveAtIndexEvent>, 'event' | 'type' | 'eventArgs'> & {
76
+ type: 'remove-array-item' | 'removeArrayItem';
77
+ /**
78
+ * The key of the array field to remove items from.
79
+ * Required when the button is placed outside the array.
80
+ * When inside an array, this is automatically determined from context.
81
+ */
82
+ arrayKey?: string;
83
+ };
84
+ /** Pop array item button field - dispatches PopArrayItemEvent (removes last item) */
85
+ type MatPopArrayItemButtonField = Omit<MatButtonField<PopArrayItemEvent>, 'event' | 'type' | 'eventArgs'> & {
86
+ type: 'pop-array-item' | 'popArrayItem';
87
+ /**
88
+ * The key of the array field to remove the last item from.
89
+ * REQUIRED - must specify which array to pop from.
90
+ */
91
+ arrayKey: string;
92
+ };
93
+ /** Shift array item button field - dispatches ShiftArrayItemEvent (removes first item) */
94
+ type MatShiftArrayItemButtonField = Omit<MatButtonField<ShiftArrayItemEvent>, 'event' | 'type' | 'eventArgs'> & {
95
+ type: 'shift-array-item' | 'shiftArrayItem';
96
+ /**
97
+ * The key of the array field to remove the first item from.
98
+ * REQUIRED - must specify which array to shift from.
99
+ */
100
+ arrayKey: string;
101
+ };
102
+
103
+ declare class MatButtonFieldComponent<TEvent extends FormEvent> {
104
+ protected readonly action: _ng_forge_dynamic_forms_integration.NgForgeAction<TEvent>;
105
+ readonly props: _angular_core.InputSignal<MatButtonProps | undefined>;
106
+ readonly buttonType: _angular_core.Signal<"button" | "submit" | "reset">;
107
+ readonly buttonTestId: _angular_core.Signal<string>;
108
+ onClick(): void;
109
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MatButtonFieldComponent<any>, never>;
110
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MatButtonFieldComponent<any>, "df-mat-button", never, { "props": { "alias": "props"; "required": false; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof _ng_forge_dynamic_forms_integration.NgForgeActionHost; inputs: {}; outputs: {}; }]>;
111
+ }
112
+
113
+ export { MatButtonFieldComponent };
114
+ export type { MatAddArrayItemButtonField, MatButtonField, MatButtonProps, MatInsertArrayItemButtonField, MatNextButtonField, MatPopArrayItemButtonField, MatPrependArrayItemButtonField, MatPreviousButtonField, MatRemoveArrayItemButtonField, MatShiftArrayItemButtonField, MatSubmitButtonField };
@@ -0,0 +1,26 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import * as _ng_forge_dynamic_forms_integration from '@ng-forge/dynamic-forms/integration';
3
+ import { CheckboxField } from '@ng-forge/dynamic-forms/integration';
4
+ import { DynamicText } from '@ng-forge/dynamic-forms';
5
+ import { ThemePalette } from '@angular/material/core';
6
+
7
+ interface MatCheckboxProps {
8
+ color?: ThemePalette;
9
+ disableRipple?: boolean;
10
+ labelPosition?: 'before' | 'after';
11
+ hint?: DynamicText;
12
+ indeterminate?: boolean;
13
+ }
14
+ type MatCheckboxField = CheckboxField<MatCheckboxProps>;
15
+
16
+ declare class MatCheckboxFieldComponent {
17
+ private materialConfig;
18
+ protected readonly ngf: _ng_forge_dynamic_forms_integration.TypedNgForgeField<boolean>;
19
+ readonly props: _angular_core.InputSignal<MatCheckboxProps | undefined>;
20
+ readonly disableRipple: _angular_core.Signal<boolean>;
21
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MatCheckboxFieldComponent, never>;
22
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MatCheckboxFieldComponent, "df-mat-checkbox", never, { "props": { "alias": "props"; "required": false; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof _ng_forge_dynamic_forms_integration.NgForgeFieldHost; inputs: {}; outputs: {}; }]>;
23
+ }
24
+
25
+ export { MatCheckboxFieldComponent };
26
+ export type { MatCheckboxField, MatCheckboxProps };
@@ -0,0 +1,37 @@
1
+ import * as _angular_material_form_field from '@angular/material/form-field';
2
+ import { MatFormFieldAppearance, SubscriptSizing, FloatLabelType } from '@angular/material/form-field';
3
+ import * as _angular_core from '@angular/core';
4
+ import * as _ng_forge_dynamic_forms_integration from '@ng-forge/dynamic-forms/integration';
5
+ import { DatepickerField, DatepickerProps } from '@ng-forge/dynamic-forms/integration';
6
+ import { DynamicText } from '@ng-forge/dynamic-forms';
7
+
8
+ interface MatDatepickerProps extends DatepickerProps {
9
+ appearance?: MatFormFieldAppearance;
10
+ color?: 'primary' | 'accent' | 'warn';
11
+ disableRipple?: boolean;
12
+ subscriptSizing?: SubscriptSizing;
13
+ floatLabel?: FloatLabelType;
14
+ hideRequiredMarker?: boolean;
15
+ startView?: 'month' | 'year' | 'multi-year';
16
+ touchUi?: boolean;
17
+ hint?: DynamicText;
18
+ }
19
+ type MatDatepickerField = DatepickerField<MatDatepickerProps>;
20
+
21
+ declare class MatDatepickerFieldComponent {
22
+ private materialConfig;
23
+ protected readonly ngf: _ng_forge_dynamic_forms_integration.TypedNgForgeField<string>;
24
+ readonly minDate: _angular_core.InputSignal<Date | null>;
25
+ readonly maxDate: _angular_core.InputSignal<Date | null>;
26
+ readonly startAt: _angular_core.InputSignal<Date | null>;
27
+ readonly props: _angular_core.InputSignal<MatDatepickerProps | undefined>;
28
+ readonly appearance: _angular_core.Signal<_angular_material_form_field.MatFormFieldAppearance>;
29
+ readonly subscriptSizing: _angular_core.Signal<_angular_material_form_field.SubscriptSizing>;
30
+ readonly floatLabel: _angular_core.Signal<_angular_material_form_field.FloatLabelType>;
31
+ readonly hideRequiredMarker: _angular_core.Signal<boolean>;
32
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MatDatepickerFieldComponent, never>;
33
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MatDatepickerFieldComponent, "df-mat-datepicker", never, { "minDate": { "alias": "minDate"; "required": false; "isSignal": true; }; "maxDate": { "alias": "maxDate"; "required": false; "isSignal": true; }; "startAt": { "alias": "startAt"; "required": false; "isSignal": true; }; "props": { "alias": "props"; "required": false; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof _ng_forge_dynamic_forms_integration.NgForgeFieldHost; inputs: {}; outputs: {}; }]>;
34
+ }
35
+
36
+ export { MatDatepickerFieldComponent };
37
+ export type { MatDatepickerField, MatDatepickerProps };