|
| 1 | +import { |
| 2 | + ChangeDetectionStrategy, |
| 3 | + ChangeDetectorRef, |
| 4 | + Component, |
| 5 | + ElementRef, |
| 6 | + EventEmitter, |
| 7 | + HostListener, |
| 8 | + Injector, |
| 9 | + NgZone, |
| 10 | + forwardRef, |
| 11 | +} from '@angular/core'; |
| 12 | +import { NG_VALUE_ACCESSOR } from '@angular/forms'; |
| 13 | +import { ValueAccessor } from '@ionic/angular/common'; |
| 14 | +import type { |
| 15 | + InputOtpInputEventDetail as IIonInputOtpInputEventDetail, |
| 16 | + InputOtpChangeEventDetail as IIonInputOtpChangeEventDetail, |
| 17 | + InputOtpCompleteEventDetail as IIonInputOtpCompleteEventDetail, |
| 18 | + Components, |
| 19 | +} from '@ionic/core/components'; |
| 20 | +import { defineCustomElement } from '@ionic/core/components/ion-input-otp.js'; |
| 21 | + |
| 22 | +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; |
| 23 | + |
| 24 | +const INPUT_OTP_INPUTS = [ |
| 25 | + 'autocapitalize', |
| 26 | + 'color', |
| 27 | + 'disabled', |
| 28 | + 'fill', |
| 29 | + 'inputmode', |
| 30 | + 'length', |
| 31 | + 'pattern', |
| 32 | + 'readonly', |
| 33 | + 'separators', |
| 34 | + 'shape', |
| 35 | + 'size', |
| 36 | + 'type', |
| 37 | + 'value', |
| 38 | +]; |
| 39 | + |
| 40 | +/** |
| 41 | + * Pulling the provider into an object and using PURE works |
| 42 | + * around an ng-packagr issue that causes |
| 43 | + * components with multiple decorators and |
| 44 | + * a provider to be re-assigned. This re-assignment |
| 45 | + * is not supported by Webpack and causes treeshaking |
| 46 | + * to not work on these kinds of components. |
| 47 | + */ |
| 48 | +const accessorProvider = { |
| 49 | + provide: NG_VALUE_ACCESSOR, |
| 50 | + useExisting: /*@__PURE__*/ forwardRef(() => IonInputOtp), |
| 51 | + multi: true, |
| 52 | +}; |
| 53 | + |
| 54 | +@ProxyCmp({ |
| 55 | + defineCustomElementFn: defineCustomElement, |
| 56 | + inputs: INPUT_OTP_INPUTS, |
| 57 | + methods: ['reset', 'setFocus'], |
| 58 | +}) |
| 59 | +@Component({ |
| 60 | + selector: 'ion-input-otp', |
| 61 | + changeDetection: ChangeDetectionStrategy.OnPush, |
| 62 | + template: '<ng-content></ng-content>', |
| 63 | + // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property |
| 64 | + inputs: INPUT_OTP_INPUTS, |
| 65 | + providers: [accessorProvider], |
| 66 | + standalone: true, |
| 67 | +}) |
| 68 | +export class IonInputOtp extends ValueAccessor { |
| 69 | + protected el: HTMLElement; |
| 70 | + constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { |
| 71 | + super(injector, r); |
| 72 | + c.detach(); |
| 73 | + this.el = r.nativeElement; |
| 74 | + proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionComplete', 'ionBlur', 'ionFocus']); |
| 75 | + } |
| 76 | + |
| 77 | + @HostListener('ionInput', ['$event.target']) |
| 78 | + handleIonInput(el: HTMLIonInputOtpElement): void { |
| 79 | + this.handleValueChange(el, el.value); |
| 80 | + } |
| 81 | + |
| 82 | + registerOnChange(fn: (_: any) => void): void { |
| 83 | + super.registerOnChange((value: string) => { |
| 84 | + if (this.type === 'number') { |
| 85 | + /** |
| 86 | + * If the input type is `number`, we need to convert the value to a number |
| 87 | + * when the value is not empty. If the value is empty, we want to treat |
| 88 | + * the value as null. |
| 89 | + */ |
| 90 | + fn(value === '' ? null : parseFloat(value)); |
| 91 | + } else { |
| 92 | + fn(value); |
| 93 | + } |
| 94 | + }); |
| 95 | + } |
| 96 | +} |
| 97 | + |
| 98 | +export declare interface IonInputOtp extends Components.IonInputOtp { |
| 99 | + /** |
| 100 | + * The `ionInput` event is fired each time the user modifies the input's value. |
| 101 | + * Unlike the `ionChange` event, the `ionInput` event is fired for each alteration |
| 102 | + * to the input's value. This typically happens for each keystroke as the user types. |
| 103 | + * |
| 104 | + * For elements that accept text input (`type=text`, `type=tel`, etc.), the interface |
| 105 | + * is [`InputEvent`](https://developer.mozilla.org/en-US/docs/Web/API/InputEvent); for others, |
| 106 | + * the interface is [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event). If |
| 107 | + * the input is cleared on edit, the type is `null`. |
| 108 | + */ |
| 109 | + ionInput: EventEmitter<CustomEvent<IIonInputOtpInputEventDetail>>; |
| 110 | + /** |
| 111 | + * The `ionChange` event is fired when the user modifies the input's value. |
| 112 | + * Unlike the `ionInput` event, the `ionChange` event is only fired when changes |
| 113 | + * are committed, not as the user types. |
| 114 | + * |
| 115 | + * The `ionChange` event fires when the `<ion-input-otp>` component loses |
| 116 | + * focus after its value has changed. |
| 117 | + * |
| 118 | + * This event will not emit when programmatically setting the `value` property. |
| 119 | + */ |
| 120 | + ionChange: EventEmitter<CustomEvent<IIonInputOtpChangeEventDetail>>; |
| 121 | + /** |
| 122 | + * Emitted when all input boxes have been filled with valid values. |
| 123 | + */ |
| 124 | + ionComplete: EventEmitter<CustomEvent<IIonInputOtpCompleteEventDetail>>; |
| 125 | + /** |
| 126 | + * Emitted when the input group loses focus. |
| 127 | + */ |
| 128 | + ionBlur: EventEmitter<CustomEvent<FocusEvent>>; |
| 129 | + /** |
| 130 | + * Emitted when the input group has focus. |
| 131 | + */ |
| 132 | + ionFocus: EventEmitter<CustomEvent<FocusEvent>>; |
| 133 | +} |
0 commit comments