ng-zorro-antd
Version:
An enterprise-class UI components based on Ant Design and Angular
1 lines • 102 kB
Source Map (JSON)
{"version":3,"file":"ng-zorro-antd-input.mjs","sources":["../../components/input/autosize.directive.ts","../../components/input/input-addon.directive.ts","../../components/input/input-affix.directive.ts","../../components/input/input-group-slot.component.ts","../../components/input/input-password.directive.ts","../../components/input/tokens.ts","../../components/input/input.directive.ts","../../components/input/input-group.component.ts","../../components/input/input-otp.component.ts","../../components/input/input-search.directive.ts","../../components/input/input-wrapper.component.ts","../../components/input/textarea-count.component.ts","../../components/input/input.module.ts","../../components/input/public-api.ts","../../components/input/ng-zorro-antd-input.ts"],"sourcesContent":["/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { AfterViewInit, DestroyRef, Directive, DoCheck, ElementRef, inject, Input, NgZone } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzResizeService } from 'ng-zorro-antd/core/services';\n\nexport interface AutoSizeType {\n minRows?: number;\n maxRows?: number;\n}\n\n@Directive({\n selector: 'textarea[nzAutosize]',\n exportAs: 'nzAutosize',\n host: {\n // Textarea elements that have the directive applied should have a single row by default.\n // Browsers normally show two rows by default and therefore this limits the minRows binding.\n rows: '1',\n '(input)': 'noopInputHandler()'\n }\n})\nexport class NzAutosizeDirective implements AfterViewInit, DoCheck {\n private ngZone = inject(NgZone);\n private platform = inject(Platform);\n private destroyRef = inject(DestroyRef);\n private resizeService = inject(NzResizeService);\n private el: HTMLTextAreaElement | HTMLInputElement = inject(ElementRef).nativeElement;\n\n private autosize: boolean = false;\n private cachedLineHeight!: number;\n private previousValue!: string;\n private previousMinRows: number | undefined;\n private minRows: number | undefined;\n private maxRows: number | undefined;\n private maxHeight: number | null = null;\n private minHeight: number | null = null;\n private inputGap = 10;\n private destroyed = false;\n\n constructor() {\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n });\n }\n\n @Input()\n set nzAutosize(value: string | boolean | AutoSizeType) {\n const isAutoSizeType = (data: string | boolean | AutoSizeType): data is AutoSizeType =>\n typeof data !== 'string' && typeof data !== 'boolean' && (!!data.maxRows || !!data.minRows);\n if (typeof value === 'string' || value === true) {\n this.autosize = true;\n } else if (isAutoSizeType(value)) {\n this.autosize = true;\n this.minRows = value.minRows;\n this.maxRows = value.maxRows;\n this.maxHeight = this.setMaxHeight();\n this.minHeight = this.setMinHeight();\n }\n }\n\n resizeToFitContent(force: boolean = false): void {\n this.cacheTextareaLineHeight();\n\n // If we haven't determined the line-height yet, we know we're still hidden and there's no point\n // in checking the height of the textarea.\n if (!this.cachedLineHeight) {\n return;\n }\n\n const textarea = this.el as HTMLTextAreaElement;\n const value = textarea.value;\n\n // Only resize if the value or minRows have changed since these calculations can be expensive.\n if (!force && this.minRows === this.previousMinRows && value === this.previousValue) {\n return;\n }\n const placeholderText = textarea.placeholder;\n\n // Reset the textarea height to auto in order to shrink back to its default size.\n // Also temporarily force overflow:hidden, so scroll bars do not interfere with calculations.\n // Long placeholders that are wider than the textarea width may lead to a bigger scrollHeight\n // value. To ensure that the scrollHeight is not bigger than the content, the placeholders\n // need to be removed temporarily.\n textarea.classList.add('nz-textarea-autosize-measuring');\n textarea.placeholder = '';\n let height =\n Math.round((textarea.scrollHeight - this.inputGap) / this.cachedLineHeight) * this.cachedLineHeight +\n this.inputGap;\n if (this.maxHeight !== null && height > this.maxHeight) {\n height = this.maxHeight!;\n }\n if (this.minHeight !== null && height < this.minHeight) {\n height = this.minHeight!;\n }\n // Use the scrollHeight to know how large the textarea *would* be if fit its entire value.\n textarea.style.height = `${height}px`;\n textarea.classList.remove('nz-textarea-autosize-measuring');\n textarea.placeholder = placeholderText;\n\n // On Firefox resizing the textarea will prevent it from scrolling to the caret position.\n // We need to re-set the selection in order for it to scroll to the proper position.\n if (typeof requestAnimationFrame !== 'undefined') {\n this.ngZone.runOutsideAngular(() =>\n requestAnimationFrame(() => {\n const { selectionStart, selectionEnd } = textarea;\n\n // IE will throw an \"Unspecified error\" if we try to set the selection range after the\n // element has been removed from the DOM. Assert that the directive hasn't been destroyed\n // between the time we requested the animation frame and when it was executed.\n // Also note that we have to assert that the textarea is focused before we set the\n // selection range. Setting the selection range on a non-focused textarea will cause\n // it to receive focus on IE and Edge.\n if (!this.destroyed && document.activeElement === textarea) {\n textarea.setSelectionRange(selectionStart, selectionEnd);\n }\n })\n );\n }\n\n this.previousValue = value;\n this.previousMinRows = this.minRows;\n }\n\n private cacheTextareaLineHeight(): void {\n if (this.cachedLineHeight >= 0 || !this.el.parentNode) {\n return;\n }\n\n // Use a clone element because we have to override some styles.\n const textareaClone = this.el.cloneNode(false) as HTMLTextAreaElement;\n textareaClone.rows = 1;\n\n // Use `position: absolute` so that this doesn't cause a browser layout and use\n // `visibility: hidden` so that nothing is rendered. Clear any other styles that\n // would affect the height.\n textareaClone.style.position = 'absolute';\n textareaClone.style.visibility = 'hidden';\n textareaClone.style.border = 'none';\n textareaClone.style.padding = '0';\n textareaClone.style.height = '';\n textareaClone.style.minHeight = '';\n textareaClone.style.maxHeight = '';\n\n // In Firefox it happens that textarea elements are always bigger than the specified amount\n // of rows. This is because Firefox tries to add extra space for the horizontal scrollbar.\n // As a workaround that removes the extra space for the scrollbar, we can just set overflow\n // to hidden. This ensures that there is no invalid calculation of the line height.\n // See Firefox bug report: https://bugzilla.mozilla.org/show_bug.cgi?id=33654\n textareaClone.style.overflow = 'hidden';\n\n this.el.parentNode!.appendChild(textareaClone);\n this.cachedLineHeight = textareaClone.clientHeight - this.inputGap;\n this.el.parentNode!.removeChild(textareaClone);\n\n // Min and max heights have to be re-calculated if the cached line height changes\n this.maxHeight = this.setMaxHeight();\n this.minHeight = this.setMinHeight();\n }\n\n setMinHeight(): number | null {\n const minHeight =\n this.minRows && this.cachedLineHeight ? this.minRows * this.cachedLineHeight + this.inputGap : null;\n\n if (minHeight !== null) {\n this.el.style.minHeight = `${minHeight}px`;\n }\n return minHeight;\n }\n\n setMaxHeight(): number | null {\n const maxHeight =\n this.maxRows && this.cachedLineHeight ? this.maxRows * this.cachedLineHeight + this.inputGap : null;\n if (maxHeight !== null) {\n this.el.style.maxHeight = `${maxHeight}px`;\n }\n return maxHeight;\n }\n\n noopInputHandler(): void {\n // no-op handler that ensures we're running change detection on input events.\n }\n\n ngAfterViewInit(): void {\n if (this.autosize && this.platform.isBrowser) {\n this.resizeToFitContent();\n this.resizeService\n .connect()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => this.resizeToFitContent(true));\n }\n }\n\n ngDoCheck(): void {\n if (this.autosize && this.platform.isBrowser) {\n this.resizeToFitContent();\n }\n }\n}\n","/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n selector: '[nzInputAddonBefore]'\n})\nexport class NzInputAddonBeforeDirective {}\n\n@Directive({\n selector: '[nzInputAddonAfter]'\n})\nexport class NzInputAddonAfterDirective {}\n","/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n selector: '[nzInputPrefix]'\n})\nexport class NzInputPrefixDirective {}\n\n@Directive({\n selector: '[nzInputSuffix]'\n})\nexport class NzInputSuffixDirective {}\n","/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n/**\n * @deprecated Will be removed in v22.0.0. This component will be removed along with input-group.\n */\n@Component({\n selector: '[nz-input-group-slot]',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (icon) {\n <nz-icon [nzType]=\"icon\" />\n }\n <ng-container *nzStringTemplateOutlet=\"template\">{{ template }}</ng-container>\n <ng-content></ng-content>\n `,\n host: {\n '[class.ant-input-group-addon]': `type === 'addon'`,\n '[class.ant-input-prefix]': `type === 'prefix'`,\n '[class.ant-input-suffix]': `type === 'suffix'`\n },\n imports: [NzIconModule, NzOutletModule]\n})\nexport class NzInputGroupSlotComponent {\n @Input() icon?: string | null = null;\n @Input() type: 'addon' | 'prefix' | 'suffix' | null = null;\n @Input() template?: string | TemplateRef<void> | null = null;\n}\n","/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, input, model } from '@angular/core';\n\n@Directive({\n selector: 'nz-input-password',\n exportAs: 'nzInputPassword',\n host: {\n class: 'ant-input-password'\n }\n})\nexport class NzInputPasswordDirective {\n readonly nzVisibilityToggle = input(true);\n readonly nzVisible = model(false);\n\n toggleVisible(): void {\n this.nzVisible.update(value => !value);\n }\n}\n\n@Directive({\n selector: '[nzInputPasswordIcon]'\n})\nexport class NzInputPasswordIconDirective {\n /**\n * @internal\n */\n static ngTemplateContextGuard(_: NzInputPasswordIconDirective, context: unknown): context is { $implicit: boolean } {\n return true;\n }\n}\n","/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport { NzInputSearchDirective } from './input-search.directive';\nimport type { NzInputWrapperComponent } from './input-wrapper.component';\n\nexport const NZ_INPUT_WRAPPER = new InjectionToken<NzInputWrapperComponent>(\n typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-input-wrapper' : ''\n);\n\nexport const NZ_INPUT_SEARCH = new InjectionToken<NzInputSearchDirective>(\n typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-input-search' : ''\n);\n","/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n booleanAttribute,\n ComponentRef,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n linkedSignal,\n OnInit,\n signal,\n ViewContainerRef\n} from '@angular/core';\nimport { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop';\nimport { NgControl } from '@angular/forms';\nimport { EMPTY } from 'rxjs';\nimport { map, startWith } from 'rxjs/operators';\n\nimport { NzFormItemFeedbackIconComponent, NzFormNoStatusService, NzFormStatusService } from 'ng-zorro-antd/core/form';\nimport { NzSizeLDSType, NzStatus, NzVariant } from 'ng-zorro-antd/core/types';\nimport { getStatusClassNames } from 'ng-zorro-antd/core/util';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nimport { NzInputPasswordDirective } from './input-password.directive';\nimport { NZ_INPUT_SEARCH, NZ_INPUT_WRAPPER } from './tokens';\n\nconst PREFIX_CLS = 'ant-input';\n\n@Directive({\n selector: 'input[nz-input],textarea[nz-input]',\n exportAs: 'nzInput',\n host: {\n class: 'ant-input',\n '[attr.type]': 'type()',\n '[class]': 'classes()',\n '[class.ant-input-disabled]': 'finalDisabled()',\n '[class.ant-input-borderless]': `nzVariant() === 'borderless' || (nzVariant() === 'outlined' && nzBorderless())`,\n '[class.ant-input-filled]': `nzVariant() === 'filled'`,\n '[class.ant-input-underlined]': `nzVariant() === 'underlined'`,\n '[class.ant-input-lg]': `finalSize() === 'large'`,\n '[class.ant-input-sm]': `finalSize() === 'small'`,\n '[attr.disabled]': 'finalDisabled() || null',\n '[attr.readonly]': 'readonly() || null',\n '[class.ant-input-rtl]': `dir() === 'rtl'`,\n '[class.ant-input-stepperless]': `nzStepperless()`,\n '[class.ant-input-focused]': 'focused()'\n },\n hostDirectives: [NzSpaceCompactItemDirective],\n providers: [{ provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'input' }]\n})\nexport class NzInputDirective implements OnInit {\n private elementRef = inject(ElementRef);\n private compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n private destroyRef = inject(DestroyRef);\n private nzFormStatusService = inject(NzFormStatusService, { optional: true });\n private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n private inputWrapper = inject(NZ_INPUT_WRAPPER, { host: true, optional: true });\n private focusMonitor = inject(FocusMonitor);\n private hostView = inject(ViewContainerRef);\n private readonly inputPasswordDir = inject(NzInputPasswordDirective, { host: true, optional: true });\n private readonly inputSearchDir = inject(NZ_INPUT_SEARCH, { host: true, optional: true });\n\n readonly ngControl = inject(NgControl, { self: true, optional: true });\n readonly value = signal<string>(this.elementRef.nativeElement.value);\n\n /**\n * @deprecated Will be removed in v21. It is recommended to use `nzVariant` instead.\n */\n readonly nzBorderless = input(false, { transform: booleanAttribute });\n readonly nzVariant = input<NzVariant>('outlined');\n readonly nzSize = input<NzSizeLDSType>('default');\n /**\n * @deprecated Will be removed in v22.\n */\n readonly nzStepperless = input(true, { transform: booleanAttribute });\n readonly nzStatus = input<NzStatus>('');\n readonly disabled = input(false, { transform: booleanAttribute });\n readonly readonly = input(false, { transform: booleanAttribute });\n\n readonly controlDisabled = signal(false);\n readonly finalDisabled = this.ngControl ? this.controlDisabled : this.disabled;\n readonly dir = inject(Directionality).valueSignal;\n // TODO: When the input group is removed, we can remove this.\n readonly size = linkedSignal(this.nzSize);\n\n readonly status = this.nzFormStatusService\n ? toSignal(this.nzFormStatusService.formStatusChanges.pipe(map(value => value.status)), { initialValue: '' })\n : this.nzStatus;\n readonly hasFeedback = toSignal(\n this.nzFormStatusService?.formStatusChanges.pipe(map(value => value.hasFeedback)) ?? EMPTY,\n { initialValue: false }\n );\n readonly classes = computed(() => getStatusClassNames(PREFIX_CLS, this.status(), this.hasFeedback()));\n readonly type = computed(() => {\n if (this.inputPasswordDir) {\n return this.inputPasswordDir.nzVisible() ? 'text' : 'password';\n }\n if (this.inputSearchDir) {\n return 'search';\n }\n return this.elementRef.nativeElement.getAttribute('type') || 'text';\n });\n\n protected readonly focused = signal<boolean>(false);\n protected readonly finalSize = computed(() => {\n if (this.compactSize) {\n return this.compactSize();\n }\n return this.size();\n });\n\n feedbackRef: ComponentRef<NzFormItemFeedbackIconComponent> | null = null;\n // TODO: When the input group is removed, we can remove this.\n disabled$ = toObservable(this.finalDisabled);\n\n constructor() {\n this.destroyRef.onDestroy(() => {\n this.focusMonitor.stopMonitoring(this.elementRef);\n });\n\n this.focusMonitor\n .monitor(this.elementRef, false)\n .pipe(takeUntilDestroyed())\n .subscribe(origin => this.focused.set(!!origin));\n\n effect(() => {\n this.renderFeedbackIcon();\n });\n }\n\n ngOnInit(): void {\n // statusChanges is only accessible in onInit\n this.ngControl?.statusChanges?.pipe(startWith(null), takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n this.controlDisabled.set(!!this.ngControl!.disabled);\n });\n\n this.ngControl?.valueChanges?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => {\n this.value.set(value);\n });\n }\n\n private renderFeedbackIcon(): void {\n if (!this.status() || !this.hasFeedback() || this.inputWrapper || !!this.nzFormNoStatusService) {\n // remove feedback\n this.hostView.clear();\n this.feedbackRef = null;\n return;\n }\n\n this.feedbackRef = this.feedbackRef || this.hostView.createComponent(NzFormItemFeedbackIconComponent);\n this.feedbackRef.location.nativeElement.classList.add('ant-input-suffix');\n this.feedbackRef.instance.status = this.status();\n this.feedbackRef.instance.updateIcon();\n }\n}\n","/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n AfterContentInit,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ContentChildren,\n DestroyRef,\n Directive,\n ElementRef,\n Input,\n OnChanges,\n OnInit,\n QueryList,\n Renderer2,\n SimpleChanges,\n TemplateRef,\n ViewEncapsulation,\n booleanAttribute,\n inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { merge } from 'rxjs';\nimport { distinctUntilChanged, map, mergeMap, startWith, switchMap } from 'rxjs/operators';\n\nimport { NzFormItemFeedbackIconComponent, NzFormNoStatusService, NzFormStatusService } from 'ng-zorro-antd/core/form';\nimport { NgClassInterface, NzSizeLDSType, NzStatus, NzValidateStatus } from 'ng-zorro-antd/core/types';\nimport { getStatusClassNames } from 'ng-zorro-antd/core/util';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nimport { NzInputGroupSlotComponent } from './input-group-slot.component';\nimport { NzInputDirective } from './input.directive';\n\n/**\n * @deprecated Will be removed in v22.0.0. This component will be removed along with input-group.\n */\n@Directive({\n selector: `nz-input-group[nzSuffix], nz-input-group[nzPrefix]`\n})\nexport class NzInputGroupWhitSuffixOrPrefixDirective {\n public readonly elementRef = inject(ElementRef);\n}\n\n/**\n * @deprecated Will be removed in v22. It is recommended to use `<nz-input-wrapper>` instead.\n */\n@Component({\n selector: 'nz-input-group',\n exportAs: 'nzInputGroup',\n imports: [NzInputGroupSlotComponent, NgTemplateOutlet, NzFormItemFeedbackIconComponent],\n encapsulation: ViewEncapsulation.None,\n providers: [NzFormNoStatusService, { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'input' }],\n template: `\n @if (isAddOn) {\n <span class=\"ant-input-wrapper ant-input-group\">\n @if (nzAddOnBefore || nzAddOnBeforeIcon) {\n <span nz-input-group-slot type=\"addon\" [icon]=\"nzAddOnBeforeIcon\" [template]=\"nzAddOnBefore\"></span>\n }\n\n @if (isAffix || hasFeedback) {\n <span\n class=\"ant-input-affix-wrapper\"\n [class.ant-input-affix-wrapper-disabled]=\"disabled\"\n [class.ant-input-affix-wrapper-sm]=\"isSmall\"\n [class.ant-input-affix-wrapper-lg]=\"isLarge\"\n [class.ant-input-affix-wrapper-focused]=\"focused\"\n [class]=\"affixInGroupStatusCls\"\n >\n <ng-template [ngTemplateOutlet]=\"affixTemplate\"></ng-template>\n </span>\n } @else {\n <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n }\n @if (nzAddOnAfter || nzAddOnAfterIcon) {\n <span nz-input-group-slot type=\"addon\" [icon]=\"nzAddOnAfterIcon\" [template]=\"nzAddOnAfter\"></span>\n }\n </span>\n } @else {\n @if (isAffix) {\n <ng-template [ngTemplateOutlet]=\"affixTemplate\" />\n } @else {\n <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n }\n }\n\n <!-- affix template -->\n <ng-template #affixTemplate>\n @if (nzPrefix || nzPrefixIcon) {\n <span nz-input-group-slot type=\"prefix\" [icon]=\"nzPrefixIcon\" [template]=\"nzPrefix\"></span>\n }\n <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n @if (nzSuffix || nzSuffixIcon || isFeedback) {\n <span nz-input-group-slot type=\"suffix\" [icon]=\"nzSuffixIcon\" [template]=\"nzSuffix\">\n @if (isFeedback) {\n <nz-form-item-feedback-icon [status]=\"status\" />\n }\n </span>\n }\n </ng-template>\n\n <!-- content template -->\n <ng-template #contentTemplate>\n <ng-content></ng-content>\n @if (!isAddOn && !isAffix && isFeedback) {\n <span nz-input-group-slot type=\"suffix\">\n <nz-form-item-feedback-icon [status]=\"status\" />\n </span>\n }\n </ng-template>\n `,\n host: {\n '[class.ant-input-search-enter-button]': `nzSearch`,\n '[class.ant-input-search]': `nzSearch`,\n '[class.ant-input-search-rtl]': `dir === 'rtl'`,\n '[class.ant-input-search-sm]': `nzSearch && isSmall`,\n '[class.ant-input-search-large]': `nzSearch && isLarge`,\n '[class.ant-input-group-wrapper]': `isAddOn`,\n '[class.ant-input-group-wrapper-rtl]': `dir === 'rtl'`,\n '[class.ant-input-group-wrapper-lg]': `isAddOn && isLarge`,\n '[class.ant-input-group-wrapper-sm]': `isAddOn && isSmall`,\n '[class.ant-input-affix-wrapper]': `isAffix && !isAddOn`,\n '[class.ant-input-affix-wrapper-rtl]': `dir === 'rtl'`,\n '[class.ant-input-affix-wrapper-focused]': `isAffix && focused`,\n '[class.ant-input-affix-wrapper-disabled]': `isAffix && disabled`,\n '[class.ant-input-affix-wrapper-lg]': `isAffix && !isAddOn && isLarge`,\n '[class.ant-input-affix-wrapper-sm]': `isAffix && !isAddOn && isSmall`,\n '[class.ant-input-group]': `!isAffix && !isAddOn`,\n '[class.ant-input-group-rtl]': `dir === 'rtl'`,\n '[class.ant-input-group-lg]': `!isAffix && !isAddOn && isLarge`,\n '[class.ant-input-group-sm]': `!isAffix && !isAddOn && isSmall`\n },\n hostDirectives: [NzSpaceCompactItemDirective],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzInputGroupComponent implements AfterContentInit, OnChanges, OnInit {\n private focusMonitor = inject(FocusMonitor);\n private elementRef = inject(ElementRef);\n private renderer = inject(Renderer2);\n private cdr = inject(ChangeDetectorRef);\n private directionality = inject(Directionality);\n private destroyRef = inject(DestroyRef);\n private nzFormStatusService = inject(NzFormStatusService, { optional: true });\n private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n\n @ContentChildren(NzInputDirective) listOfNzInputDirective!: QueryList<NzInputDirective>;\n @Input() nzAddOnBeforeIcon?: string | null = null;\n @Input() nzAddOnAfterIcon?: string | null = null;\n @Input() nzPrefixIcon?: string | null = null;\n @Input() nzSuffixIcon?: string | null = null;\n @Input() nzAddOnBefore?: string | TemplateRef<void>;\n @Input() nzAddOnAfter?: string | TemplateRef<void>;\n @Input() nzPrefix?: string | TemplateRef<void>;\n @Input() nzStatus: NzStatus = '';\n @Input() nzSuffix?: string | TemplateRef<void>;\n @Input() nzSize: NzSizeLDSType = 'default';\n @Input({ transform: booleanAttribute }) nzSearch = false;\n isLarge = false;\n isSmall = false;\n isAffix = false;\n isAddOn = false;\n isFeedback = false;\n focused = false;\n disabled = false;\n dir: Direction = 'ltr';\n // status\n prefixCls: string = 'ant-input';\n affixStatusCls: NgClassInterface = {};\n groupStatusCls: NgClassInterface = {};\n affixInGroupStatusCls: NgClassInterface = {};\n status: NzValidateStatus = '';\n hasFeedback: boolean = false;\n\n constructor() {\n this.destroyRef.onDestroy(() => this.focusMonitor.stopMonitoring(this.elementRef));\n }\n\n updateChildrenInputSize(): void {\n if (this.listOfNzInputDirective) {\n this.listOfNzInputDirective.forEach(item => item['size'].set(this.nzSize));\n }\n }\n\n ngOnInit(): void {\n this.nzFormStatusService?.formStatusChanges\n .pipe(\n distinctUntilChanged((pre, cur) => pre.status === cur.status && pre.hasFeedback === cur.hasFeedback),\n takeUntilDestroyed(this.destroyRef)\n )\n .subscribe(({ status, hasFeedback }) => {\n this.setStatusStyles(status, hasFeedback);\n });\n\n this.focusMonitor\n .monitor(this.elementRef, true)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(focusOrigin => {\n this.focused = !!focusOrigin;\n this.cdr.markForCheck();\n });\n\n this.dir = this.directionality.value;\n this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n this.dir = direction;\n });\n }\n\n ngAfterContentInit(): void {\n this.updateChildrenInputSize();\n const listOfInputChange$ = this.listOfNzInputDirective.changes.pipe(startWith(this.listOfNzInputDirective));\n listOfInputChange$\n .pipe(\n switchMap(list => merge(...[listOfInputChange$, ...list.map((input: NzInputDirective) => input.disabled$)])),\n mergeMap(() => listOfInputChange$),\n map(list => list.some((input: NzInputDirective) => input.finalDisabled())),\n takeUntilDestroyed(this.destroyRef)\n )\n .subscribe(disabled => {\n this.disabled = disabled;\n this.cdr.markForCheck();\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n const {\n nzSize,\n nzSuffix,\n nzPrefix,\n nzPrefixIcon,\n nzSuffixIcon,\n nzAddOnAfter,\n nzAddOnBefore,\n nzAddOnAfterIcon,\n nzAddOnBeforeIcon,\n nzStatus\n } = changes;\n if (nzSize) {\n this.updateChildrenInputSize();\n this.isLarge = this.nzSize === 'large';\n this.isSmall = this.nzSize === 'small';\n }\n if (nzSuffix || nzPrefix || nzPrefixIcon || nzSuffixIcon) {\n this.isAffix = !!(this.nzSuffix || this.nzPrefix || this.nzPrefixIcon || this.nzSuffixIcon);\n }\n if (nzAddOnAfter || nzAddOnBefore || nzAddOnAfterIcon || nzAddOnBeforeIcon) {\n this.isAddOn = !!(this.nzAddOnAfter || this.nzAddOnBefore || this.nzAddOnAfterIcon || this.nzAddOnBeforeIcon);\n this.nzFormNoStatusService?.noFormStatus?.next(this.isAddOn);\n }\n if (nzStatus) {\n this.setStatusStyles(this.nzStatus, this.hasFeedback);\n }\n }\n\n private setStatusStyles(status: NzValidateStatus, hasFeedback: boolean): void {\n // set inner status\n this.status = status;\n this.hasFeedback = hasFeedback;\n this.isFeedback = !!status && hasFeedback;\n const baseAffix = !!(this.nzSuffix || this.nzPrefix || this.nzPrefixIcon || this.nzSuffixIcon);\n this.isAffix = baseAffix || (!this.isAddOn && hasFeedback);\n this.affixInGroupStatusCls =\n this.isAffix || this.isFeedback\n ? (this.affixStatusCls = getStatusClassNames(`${this.prefixCls}-affix-wrapper`, status, hasFeedback))\n : {};\n this.cdr.markForCheck();\n // render status if nzStatus is set\n this.affixStatusCls = getStatusClassNames(\n `${this.prefixCls}-affix-wrapper`,\n this.isAddOn ? '' : status,\n this.isAddOn ? false : hasFeedback\n );\n this.groupStatusCls = getStatusClassNames(\n `${this.prefixCls}-group-wrapper`,\n this.isAddOn ? status : '',\n this.isAddOn ? hasFeedback : false\n );\n const statusCls = {\n ...this.affixStatusCls,\n ...this.groupStatusCls\n };\n Object.keys(statusCls).forEach(status => {\n if (statusCls[status]) {\n this.renderer.addClass(this.elementRef.nativeElement, status);\n } else {\n this.renderer.removeClass(this.elementRef.nativeElement, status);\n }\n });\n }\n}\n","/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BACKSPACE, LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n forwardRef,\n inject,\n Input,\n numberAttribute,\n OnChanges,\n QueryList,\n SimpleChanges,\n ViewChildren,\n ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport {\n ControlValueAccessor,\n FormArray,\n FormBuilder,\n FormControl,\n NG_VALUE_ACCESSOR,\n ReactiveFormsModule,\n Validators\n} from '@angular/forms';\nimport { tap } from 'rxjs/operators';\n\nimport { NzSafeAny, NzSizeLDSType, NzStatus, OnTouchedType } from 'ng-zorro-antd/core/types';\n\nimport { NzInputDirective } from './input.directive';\n\n@Component({\n selector: 'nz-input-otp',\n exportAs: 'nzInputOtp',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @for (item of otpArray.controls; track $index) {\n <input\n nz-input\n class=\"ant-otp-input\"\n type=\"text\"\n maxlength=\"1\"\n size=\"1\"\n [nzSize]=\"nzSize\"\n [formControl]=\"item\"\n [nzStatus]=\"nzStatus\"\n (input)=\"onInput($index, $event)\"\n (focus)=\"onFocus($event)\"\n (keydown)=\"onKeyDown($index, $event)\"\n (paste)=\"onPaste($index, $event)\"\n #otpInput\n />\n }\n `,\n host: {\n class: 'ant-otp'\n },\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => NzInputOtpComponent),\n multi: true\n }\n ],\n imports: [NzInputDirective, ReactiveFormsModule]\n})\nexport class NzInputOtpComponent implements ControlValueAccessor, OnChanges {\n private formBuilder = inject(FormBuilder);\n private destroyRef = inject(DestroyRef);\n\n @ViewChildren('otpInput') otpInputs!: QueryList<ElementRef>;\n\n @Input({ transform: numberAttribute }) nzLength: number = 6;\n @Input() nzSize: NzSizeLDSType = 'default';\n @Input({ transform: booleanAttribute }) disabled = false;\n @Input() nzStatus: NzStatus = '';\n @Input() nzFormatter: (value: string) => string = value => value;\n @Input() nzMask: string | null = null;\n\n protected otpArray!: FormArray<FormControl<string>>;\n private internalValue: string[] = [];\n private onChangeCallback?: (_: NzSafeAny) => void;\n onTouched: OnTouchedType = () => {};\n\n constructor() {\n this.createFormArray();\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['nzLength']?.currentValue) {\n this.createFormArray();\n }\n\n if (changes['disabled']) {\n this.setDisabledState(this.disabled);\n }\n }\n\n onInput(index: number, event: Event): void {\n const inputElement = event.target as HTMLInputElement;\n const nextInput = this.otpInputs.toArray()[index + 1];\n\n if (inputElement.value && nextInput) {\n nextInput.nativeElement.focus();\n } else if (!nextInput) {\n this.selectInputBox(index);\n }\n }\n\n onFocus(event: FocusEvent): void {\n const inputElement = event.target as HTMLInputElement;\n inputElement.select();\n }\n\n onKeyDown(index: number, event: KeyboardEvent): void {\n const previousInput = this.otpInputs.toArray()[index - 1];\n\n if (event.keyCode === BACKSPACE) {\n event.preventDefault();\n\n this.internalValue[index] = '';\n this.otpArray.at(index).setValue('', { emitEvent: false });\n\n if (previousInput) {\n this.selectInputBox(index - 1);\n }\n\n this.emitValue();\n } else if (event.keyCode === LEFT_ARROW) {\n event.preventDefault();\n this.selectInputBox(index - 1);\n } else if (event.keyCode === RIGHT_ARROW) {\n event.preventDefault();\n this.selectInputBox(index + 1);\n }\n }\n\n writeValue(value: string): void {\n if (!value) {\n this.otpArray.reset();\n return;\n }\n\n const controlValues = value.split('');\n this.internalValue = controlValues;\n\n controlValues.forEach((val, i) => {\n const formattedValue = this.nzFormatter(val);\n const value = this.nzMask ? this.nzMask : formattedValue;\n this.otpArray.at(i).setValue(value, { emitEvent: false });\n });\n }\n\n registerOnChange(fn: (value: string) => void): void {\n this.onChangeCallback = fn;\n }\n\n registerOnTouched(fn: () => {}): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n if (isDisabled) {\n this.otpArray.disable();\n } else {\n this.otpArray.enable();\n }\n }\n\n onPaste(index: number, event: ClipboardEvent): void {\n const pastedText = event.clipboardData?.getData('text') || '';\n if (!pastedText) return;\n\n let currentIndex = index;\n for (const char of pastedText.split('')) {\n if (currentIndex < this.nzLength) {\n const formattedChar = this.nzFormatter(char);\n this.internalValue[currentIndex] = char;\n const maskedValue = this.nzMask ? this.nzMask : formattedChar;\n this.otpArray.at(currentIndex).setValue(maskedValue, { emitEvent: false });\n currentIndex++;\n } else {\n break;\n }\n }\n\n event.preventDefault(); // this line is needed, otherwise the last index that is going to be selected will also be filled (in the next line).\n this.selectInputBox(currentIndex);\n this.emitValue();\n }\n\n private createFormArray(): void {\n this.otpArray = this.formBuilder.array<FormControl<string>>([]);\n this.internalValue = new Array(this.nzLength).fill('');\n\n for (let i = 0; i < this.nzLength; i++) {\n const control = this.formBuilder.nonNullable.control('', [Validators.required]);\n\n control.valueChanges\n .pipe(\n tap(value => {\n const unmaskedValue = this.nzFormatter(value);\n this.internalValue[i] = unmaskedValue;\n\n control.setValue(this.nzMask ?? unmaskedValue, { emitEvent: false });\n\n this.emitValue();\n }),\n takeUntilDestroyed(this.destroyRef)\n )\n .subscribe();\n\n this.otpArray.push(control);\n }\n }\n\n private emitValue(): void {\n const result = this.internalValue.join('');\n if (this.onChangeCallback) {\n this.onChangeCallback(result);\n }\n }\n\n private selectInputBox(index: number): void {\n const otpInputArray = this.otpInputs.toArray();\n if (index <= 0) index = 0;\n if (index >= otpInputArray.length) index = otpInputArray.length - 1;\n\n otpInputArray[index].nativeElement.select();\n }\n}\n","/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n booleanAttribute,\n computed,\n contentChild,\n Directive,\n ElementRef,\n forwardRef,\n input,\n output\n} from '@angular/core';\n\nimport { NzInputDirective } from './input.directive';\nimport { NZ_INPUT_SEARCH } from './tokens';\n\n@Directive({\n selector: 'nz-input-search',\n exportAs: 'nzInputSearch',\n providers: [{ provide: NZ_INPUT_SEARCH, useExisting: forwardRef(() => NzInputSearchDirective) }],\n host: {\n class: 'ant-input-search',\n '[class.ant-input-search-large]': `size() === 'large'`,\n '[class.ant-input-search-small]': `size() === 'small'`,\n '[class.ant-input-search-with-button]': 'nzEnterButton() !== false',\n '(keydown.enter)': 'onEnter($any($event))'\n }\n})\nexport class NzInputSearchDirective {\n private readonly inputDir = contentChild.required(NzInputDirective);\n private readonly inputRef = contentChild.required(NzInputDirective, { read: ElementRef });\n\n readonly nzEnterButton = input<boolean | string>(false);\n readonly nzLoading = input(false, { transform: booleanAttribute });\n\n readonly nzSearch = output<NzInputSearchEvent>();\n\n readonly size = computed(() => this.inputDir().nzSize());\n\n search(event: Event, source: 'input' | 'clear' = 'input'): void {\n if (!this.nzLoading()) {\n this.nzSearch.emit({ value: this.inputRef().nativeElement.value, event, source });\n }\n }\n\n onEnter(event: KeyboardEvent): void {\n if (event.target === this.inputRef().nativeElement) {\n this.search(event);\n }\n }\n}\n\n@Directive({\n selector: '[nzInputSearchEnterButton]'\n})\nexport class NzInputSearchEnterButtonDirective {}\n\nexport interface NzInputSearchEvent {\n value: string;\n event: Event;\n source: 'clear' | 'input';\n}\n","/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n afterNextRender,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n DestroyRef,\n ElementRef,\n forwardRef,\n inject,\n input,\n output,\n signal,\n TemplateRef,\n ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormItemFeedbackIconComponent } from 'ng-zorro-antd/core/form';\nimport { getStatusClassNames, getVariantClassNames } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nimport { NzInputAddonAfterDirective, NzInputAddonBeforeDirective } from './input-addon.directive';\nimport { NzInputPrefixDirective, NzInputSuffixDirective } from './input-affix.directive';\nimport { NzInputPasswordDirective, NzInputPasswordIconDirective } from './input-password.directive';\nimport { NzInputSearchDirective, NzInputSearchEnterButtonDirective } from './input-search.directive';\nimport { NzInputDirective } from './input.directive';\nimport { NZ_INPUT_WRAPPER } from './tokens';\n\n@Component({\n selector: 'nz-input-wrapper,nz-input-password,nz-input-search',\n exportAs: 'nzInputWrapper',\n imports: [NzIconModule, NzButtonModule, NzFormItemFeedbackIconComponent, NgTemplateOutlet],\n template: `\n @if (hasAddon()) {\n <ng-template [ngTemplateOutlet]=\"inputWithAddonInner\" />\n } @else if (hasAffix()) {\n <ng-template [ngTemplateOutlet]=\"inputWithAffixInner\" />\n } @else {\n <ng-template [ngTemplateOutlet]=\"input\" />\n }\n\n <ng-template #inputWithAddonInner>\n <span class=\"ant-input-wrapper ant-input-group\">\n @if (hasAddonBefore()) {\n <span class=\"ant-input-group-addon\">\n <ng-content select=\"[nzInputAddonBefore]\">{{ nzAddonBefore() }}</ng-content>\n </span>\n }\n\n @if (hasAffix()) {\n <ng-template [ngTemplateOutlet]=\"inputWithAffix\" />\n } @else {\n <ng-template [ngTemplateOutlet]=\"input\" />\n }\n\n @if (hasAddonAfter()) {\n <span class=\"ant-input-group-addon\">\n @if (inputSearchDir) {\n @let nzEnterButton = inputSearchDir.nzEnterButton();\n @let hasEnterButton = inputSearchEnterButton() ?? nzEnterButton !== false;\n <button\n nz-button\n [nzType]=\"hasEnterButton ? 'primary' : 'default'\"\n [nzSize]=\"size()\"\n [nzLoading]=\"inputSearchDir.nzLoading()\"\n type=\"button\"\n class=\"ant-input-search-button\"\n (click)=\"inputSearchDir.search($event)\"\n >\n <ng-content select=\"[nzInputSearchEnterButton]\">\n @if (nzEnterButton && typeof nzEnterButton === 'string') {\n {{ nzEnterButton }}\n } @else {\n <nz-icon nzType=\"search\" nzTheme=\"outline\" />\n }\n </ng-content>\n </button>\n }\n <ng-content select=\"[nzInputAddonAfter]\">{{ nzAddonAfter() }}</ng-content>\n </span>\n }\n </span>\n </ng-template>\n\n <ng-template #inputWithAffix>\n <span [class]=\"affixWrapperClass()\">\n <ng-template [ngTemplateOutlet]=\"inputWithAffixInner\" />\n </span>\n </ng-template>\n\n <ng-template #inputWithAffixInner>\n @if (hasPrefix()) {\n <span class=\"ant-input-prefix\">\n <ng-content select=\"[nzInputPrefix]\">{{ nzPrefix() }}</ng-content>\n </span>\n }\n <ng-template [ngTemplateOutlet]=\"input\" />\n @if (hasSuffix()) {\n <span class=\"ant-input-suffix\">\n @if (nzAllowClear()) {\n <span\n class=\"ant-input-clear-icon\"\n [class.ant-input-clear-icon-has-suffix]=\"\n nzSuffix() || suffix() || hasFeedback() || inputPasswordDir?.nzVisibilityToggle()\n \"\n [class.ant-input-clear-icon-hidden]=\"!inputDir().value() || disabled() || readOnly()\"\n role=\"button\"\n tabindex=\"-1\"\n (click)=\"clear(); inputSearchDir?.search($event, 'clear')\"\n >\n <ng-content select=\"[nzInputClearIcon]\">\n <nz-icon nzType=\"close-circle\" nzTheme=\"fill\" />\n </ng-content>\n </span>\n }\n @if (inputPasswordDir && inputPasswordDir.nzVisibilityToggle()) {\n <span\n class=\"ant-input-password-icon\"\n role=\"button\"\n tabindex=\"-1\"\n (click)=\"inputPasswordDir.toggleVisible()\"\n >\n @if (inputPasswordIconTmpl(); as tmpl) {\n <ng-template\n [ngTemplateOutlet]=\"tmpl\"\n [ngTemplateOutletContext]=\"{ $implicit: inputPasswordDir.nzVisible() }\"\n />\n } @else {\n <nz-icon [nzType]=\"inputPasswordDir.nzVisible() ? 'eye' : 'eye-invisible'\" nzTheme=\"outline\" />\n }\n </span>\n }\n <ng-content select=\"[nzInputSuffix]\">{{ nzSuffix() }}</ng-content>\n @if (hasFeedback() && status()) {\n <nz-form-item-feedback-icon [status]=\"status()\" />\n }\n </span>\n }\n </ng-template>\n\n <ng-template #input>\n <ng-content select=\"[nz-input]\" />\n </ng-template>\n `,\n providers: [\n { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'input' },\n { provide: NZ_INPUT_WRAPPER, useExisting: forwardRef(() => NzInputWrapperComponent) }\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n hostDirectives: [NzSpaceCompactItemDirective],\n host: {\n '[class]': 'class()',\n '[class.ant-input-disabled]': 'disabled()',\n '[class.ant-input-affix-wrapper-textarea-with-clear-btn]': 'nzAllowClear() && isTextarea()'\n }\n})\nexport class NzInputWrapperComponent {\n private readonly focusMonitor = inject(FocusMonitor);\n\n protected readonly inputPasswordDir = inject(NzInputPasswordDirective, { self: true, optional: true });\n protected readonly inputSearchDir = inject(NzInputSearchDirective, { self: true, optional: true });\n\n protected readonly inputRef = contentChild.required(NzInputDirective, { read: ElementRef });\n protected readonly inputDir = contentChild.required(NzInputDirective);\n\n protected readonly prefix = contentChild(NzInputPrefixDirective);\n protected readonly suffix = contentChild(NzInputSuffixDirective);\n protected readonly addonBefore = contentChild(NzInputAddonBeforeDirective);\n protected readonly addonAfter = contentChild(NzInputAddonAfterDirective);\n protected readonly inputPasswordIconTmpl = contentChild(NzInputPasswordIconDirective, { read: TemplateRef });\n protected readonly inputSearchEnterButton = contentChild(NzInputSearchEnterButtonDirective);\n\n readonly nzAllowClear = input(false, { transform: booleanAttribute });\n readonly nzPrefix = input<string>();\n readonly nzSuffix = input<string>();\n readonly nzAddonBefore = input<string>();\n readonly nzAddonAfter = input<string>();\n\n readonly nzClear = output<void>();\n\n readonly size = computed(() => this.inputDir().nzSize());\n readonly variant = computed(() => this.inputDir().nzVariant());\n readonly disabled = computed(() => this.inputDir().finalDisabled());\n readonly readOnly = computed(() => this.inputDir().readonly());\n readonly status = computed(() => this.inputDir().status());\n readonly hasFeedback = computed(() => this.inputDir().hasFeedback());\n\n protected readonly hasPrefix = computed(() => !!this.nzPrefix() || !!this.prefix());\n protected readonly hasSuffix = computed(\n () => !!this.nzSuffix() || !!this.suffix() || this.nzAllowClear() || this.hasFeedback() || this.inputPasswordDir\n );\n protected readonly hasAffix = computed(() => this.hasPrefix() || this.hasSuffix());\n protected readonly hasAddonBefore = computed(() => !!this.nzAddonBefore() || !!this.addonBefore());\n protected readonly hasAddonAfter = computed(\n () => !!this.nzAddonAfter() || !!this.addonAfter() || !!this.inputSearchDir\n );\n protected readonly hasAddon = computed(() => this.hasAddonBefore() || this.hasAddonAfter());\n\n private readonly compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n protected readonly dir = inject(Directionality).valueSignal;\n protected readonly focused = signal(false);\n protected readonly isTextarea = computed(() => this.inputRef().nativeElement instanceof HTMLTextAreaElement);\n\n protected readonly finalSize = computed(() => {\n if (this.compactSize) {\n return this.compactSize();\n }\n return this.size();\n });\n\n protected readonly class = computed(() => {\n if (this.hasAddon()) {\n return this.groupWrapperClass();\n }\n if (this.hasAffix()) {\n return this.affixWrapperClass();\n }\n return null;\n });\n protected readonly affixWrapperClass = computed(() => {\n return {\n 'ant-input-affix-wrapper': true,\n 'ant-input-affix-wrapper-lg': this.finalSize() === 'large',\n 'ant-input-affix-wrapper-sm': this.finalSize() === 'small',\n 'ant-input-affix-wrapper-disabled': this.disabled(),\n 'ant-input-affix-wrapper-readonly': this.readOnly(),\n 'ant-input-affix-wrapper-focused': this.focused(),\n 'ant-input-affix-wrapper-rtl': this.dir() === 'rtl',\n ...getStatusClassNames('ant-input-affix-wrapper', this.status(), this.hasFeedback()),\n ...getVariantClassNames('ant-input-affix-wrapper', this.variant())\n };\n });\n protected readonly groupWrapperClass = computed(() => {\n return {\n 'ant-input-group-wrapper': true,\n 'ant-input-group-wrapper-sm': this.finalSize() === 'small',\n 'ant-input-group-wrapper-lg': this.finalSize() === 'large',\n 'ant-input-group-wrapper-rtl': this.dir() === 'rtl',\n ...getStatusClassNames('ant-input-group-wrapper', this.status(), this.hasFeedback()),\n ...getVariantClassNames('ant-input-group-wrapper', this.variant())\n };\n });\n\n constructor() {\n const destroyRef = inj