diff --git a/src/app/components/inputotp/inputotp.css b/src/app/components/inputotp/inputotp.css new file mode 100755 index 00000000000..1fda5f61a8c --- /dev/null +++ b/src/app/components/inputotp/inputotp.css @@ -0,0 +1,3 @@ +@layer primeng { + +} diff --git a/src/app/components/inputotp/inputotp.interface.ts b/src/app/components/inputotp/inputotp.interface.ts new file mode 100644 index 00000000000..8bd6c254d55 --- /dev/null +++ b/src/app/components/inputotp/inputotp.interface.ts @@ -0,0 +1,65 @@ +import { TemplateRef } from '@angular/core'; + +/** + * Defines the custom events used by the component's emit. + * @group Events + */ +export interface InputOtpTemplateEvents { + /** + * Input event. + */ + input: Function; + /** + * Keydown event. + */ + keydown: Function; + /** + * Focus event. + */ + focus: Function; + /** + * Blur event. + */ + blur: Function; + /** + * Paste event. + */ + paste: Function; +} + +/** + * Defines valid templates in InputOtp. + * @group Templates + */ +export interface InputOtpTemplates { + /** + * Custom template of input. + * @param {Object} context + */ + input(context: { + /** + * Input value. + */ + $implicit: any; + /** + * Events of the component + */ + events: InputOtpTemplateEvents; + }): TemplateRef<{ $implicit: any; events: InputOtpTemplateEvents }>; +} + +/** + * Custom change event. + * @see {@link InputOtp.onChange} + * @group Events + */ +export interface InputOtpChangeEvent { + /** + * Browser event. + */ + originalEvent: Event; + /** + * Selected value. + */ + value: any; +} diff --git a/src/app/components/inputotp/inputotp.ts b/src/app/components/inputotp/inputotp.ts new file mode 100644 index 00000000000..d73be201639 --- /dev/null +++ b/src/app/components/inputotp/inputotp.ts @@ -0,0 +1,334 @@ +import { CommonModule } from '@angular/common'; +import { AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, EventEmitter, Input, NgModule, Output, QueryList, TemplateRef, ViewEncapsulation, forwardRef } from '@angular/core'; +import { PrimeTemplate, SharedModule } from 'primeng/api'; +import { InputTextModule } from 'primeng/inputtext'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Nullable } from 'primeng/ts-helpers'; +import { InputOtpChangeEvent } from './inputotp.interface'; + +export const INPUT_OTP_VALUE_ACCESSOR: any = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => InputOtp), + multi: true +}; +/** + * Input Otp is used to enter one time passwords. + * @group Components + */ +@Component({ + selector: 'p-inputOtp', + template: ` + + + + + + + + + `, + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + host: { + class: 'p-inputotp p-component' + }, + providers: [INPUT_OTP_VALUE_ACCESSOR] +}) +export class InputOtp implements AfterContentInit { + /** + * When present, it specifies that the component should have invalid state style. + * @group Props + */ + @Input() invalid: boolean = false; + /** + * When present, it specifies that the component should be disabled. + * @group Props + */ + + @Input() disabled: boolean = false; + /** + * When present, it specifies that an input field is read-only. + * @group Props + */ + @Input() readonly: boolean = false; + /** + * Specifies the input variant of the component. + * @group Props + */ + @Input() variant: string | null = null; + /** + * Index of the element in tabbing order. + * @group Props + */ + @Input() tabindex: number | null = null; + /** + * Number of characters to initiate. + * @group Props + */ + @Input() length: number = 4; + /** + * Mask pattern. + * @group Props + */ + @Input() mask: boolean = false; + /** + * When present, it specifies that an input field is integer-only. + * @group Props + */ + @Input() integerOnly: boolean = false; + /** + * Callback to invoke on value change. + * @group Emits + */ + @Output() onChange: EventEmitter = new EventEmitter(); + /** + * Callback to invoke when the component receives focus. + * @param {Event} event - Browser event. + * @group Emits + */ + @Output() onFocus: EventEmitter = new EventEmitter(); + /** + * Callback to invoke when the component loses focus. + * @param {Event} event - Browser event. + * @group Emits + */ + @Output() onBlur: EventEmitter = new EventEmitter(); + + @ContentChildren(PrimeTemplate) templates: Nullable>; + + inputTemplate: Nullable>; + + tokens: any = []; + + onModelChange: Function = () => {}; + + onModelTouched: Function = () => {}; + + value: any; + + get inputMode(): string { + return this.integerOnly ? 'number' : 'text'; + } + + get inputType(): string { + return this.mask ? 'password' : 'text'; + } + + constructor(public cd: ChangeDetectorRef) {} + + ngAfterContentInit() { + (this.templates as QueryList).forEach((item) => { + switch (item.getType()) { + case 'input': + this.inputTemplate = item.template; + break; + default: + this.inputTemplate = item.template; + break; + } + }); + } + + getToken(index) { + return this.tokens[index]; + } + + getTemplateEvents(index) { + return { + input: (event) => this.onInput(event, index), + keydown: (event) => this.onKeyDown(event), + focus: (event) => this.onFocus.emit(event), + blur: (event) => this.onBlur.emit(event), + paste: (event) => this.onPaste(event) + }; + } + + onInput(event, index) { + this.tokens[index] = event.target.value; + this.updateModel(event); + + if (event.inputType === 'deleteContentBackward') { + this.moveToPrev(event); + } else if (event.inputType === 'insertText' || event.inputType === 'deleteContentForward') { + this.moveToNext(event); + } + } + + updateModel(event: any) { + const newValue = this.tokens.join(''); + this.onModelChange(newValue); + + this.onChange.emit({ + originalEvent: event, + value: newValue + }); + } + + writeValue(value: any): void { + if (value) { + if (Array.isArray(value) && value.length > 0) { + this.value = value.slice(0, this.length); + } else { + this.value = value.toString().split('').slice(0, this.length); + } + } else { + this.value = value; + } + this.updateTokens(); + this.cd.markForCheck(); + } + + updateTokens() { + if (this.value !== null && this.value !== undefined) { + if (Array.isArray(this.value)) { + this.tokens = [...this.value]; + } else { + this.tokens = this.value.toString().split(''); + } + } else { + this.tokens = []; + } + } + + getModelValue(i: number) { + return this.tokens[i - 1] || ''; + } + + registerOnChange(fn: Function): void { + this.onModelChange = fn; + } + + registerOnTouched(fn: Function): void { + this.onModelTouched = fn; + } + + moveToPrev(event) { + let prevInput = this.findPrevInput(event.target); + + if (prevInput) { + prevInput.focus(); + prevInput.select(); + } + } + + moveToNext(event) { + let nextInput = this.findNextInput(event.target); + + if (nextInput) { + nextInput.focus(); + nextInput.select(); + } + } + + findNextInput(element) { + let nextElement = element.nextElementSibling; + + if (!nextElement) return; + + return nextElement.nodeName === 'INPUT' ? nextElement : this.findNextInput(nextElement); + } + + findPrevInput(element) { + let prevElement = element.previousElementSibling; + + if (!prevElement) return; + + return prevElement.nodeName === 'INPUT' ? prevElement : this.findPrevInput(prevElement); + } + + onInputFocus(event) { + event.target.select(); + this.onFocus.emit(event); + } + + onInputBlur(event) { + this.onBlur.emit(event); + } + + onKeyDown(event) { + const keyCode = event.keyCode; + + switch (keyCode) { + case 37: + this.moveToPrev(event); + event.preventDefault(); + + break; + + case 38: + case 40: + event.preventDefault(); + + break; + + case 8: + if (event.target.value.length === 0) { + this.moveToPrev(event); + event.preventDefault(); + } + + break; + + case 39: + this.moveToNext(event); + event.preventDefault(); + + break; + + default: + if (this.integerOnly && !(event.keyCode >= 48 && event.keyCode <= 57)) { + event.preventDefault(); + } + + break; + } + } + onPaste(event) { + let paste = event.clipboardData.getData('text'); + + if (paste.length) { + let pastedCode = paste.substring(0, this.length + 1); + + if (!this.integerOnly || !isNaN(pastedCode)) { + this.tokens = pastedCode.split(''); + this.updateModel(event); + } + } + + event.preventDefault(); + } + + getRange(n: number): number[] { + return Array.from({ length: n }, (_, index) => index + 1); + } + + trackByFn(index: number) { + return index; + } +} + +@NgModule({ + imports: [CommonModule, SharedModule, InputTextModule], + exports: [InputOtp, SharedModule], + declarations: [InputOtp] +}) +export class InputOtpModule {} diff --git a/src/app/components/inputotp/ng-package.json b/src/app/components/inputotp/ng-package.json new file mode 100644 index 00000000000..ab5467eb7e4 --- /dev/null +++ b/src/app/components/inputotp/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public_api.ts" + } + } \ No newline at end of file diff --git a/src/app/components/inputotp/public_api.ts b/src/app/components/inputotp/public_api.ts new file mode 100644 index 00000000000..870efe9ad12 --- /dev/null +++ b/src/app/components/inputotp/public_api.ts @@ -0,0 +1,2 @@ +export * from './inputotp'; +export * from './inputotp.interface'; diff --git a/src/app/showcase/doc/apidoc/index.json b/src/app/showcase/doc/apidoc/index.json index ccbc0004ee2..b610789cdd0 100644 --- a/src/app/showcase/doc/apidoc/index.json +++ b/src/app/showcase/doc/apidoc/index.json @@ -13438,6 +13438,203 @@ } } }, + "inputotp": { + "components": { + "InputOtp": { + "description": "Input Otp is used to enter one time passwords.", + "props": { + "description": "Defines the input properties of the component.", + "values": [ + { + "name": "invalid", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "When present, it specifies that the component should have invalid state style." + }, + { + "name": "disabled", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "When present, it specifies that the component should be disabled." + }, + { + "name": "readonly", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "When present, it specifies that an input field is read-only." + }, + { + "name": "variant", + "optional": false, + "readonly": false, + "type": "string", + "default": "null", + "description": "Specifies the input variant of the component." + }, + { + "name": "tabindex", + "optional": false, + "readonly": false, + "type": "number", + "default": "null", + "description": "Index of the element in tabbing order." + }, + { + "name": "length", + "optional": false, + "readonly": false, + "type": "number", + "default": "4", + "description": "Number of characters to initiate." + }, + { + "name": "mask", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Mask pattern." + }, + { + "name": "integerOnly", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "When present, it specifies that an input field is integer-only." + } + ] + }, + "emits": { + "description": "Defines emit that determine the behavior of the component based on a given condition or report the actions that the component takes.", + "values": [ + { + "name": "onChange", + "parameters": [ + { + "name": "event", + "type": "InputOtpChangeEvent" + } + ], + "description": "Callback to invoke on value change." + }, + { + "name": "onFocus", + "parameters": [ + { + "name": "event", + "type": "Event" + } + ], + "description": "Callback to invoke when the component receives focus." + }, + { + "name": "onBlur", + "parameters": [ + { + "name": "event", + "type": "Event" + } + ], + "description": "Callback to invoke when the component loses focus." + } + ] + } + } + }, + "interfaces": { + "components": {}, + "events": { + "description": "Defines the custom events used by the component's emitters.", + "values": [ + { + "name": "InputOtpTemplateEvents", + "description": "Defines the custom events used by the component's emit.", + "props": [ + { + "name": "input", + "optional": false, + "readonly": false, + "type": "Function", + "description": "Input event." + }, + { + "name": "keydown", + "optional": false, + "readonly": false, + "type": "Function", + "description": "Keydown event." + }, + { + "name": "focus", + "optional": false, + "readonly": false, + "type": "Function", + "description": "Focus event." + }, + { + "name": "blur", + "optional": false, + "readonly": false, + "type": "Function", + "description": "Blur event." + }, + { + "name": "paste", + "optional": false, + "readonly": false, + "type": "Function", + "description": "Paste event." + } + ] + }, + { + "name": "InputOtpChangeEvent", + "description": "Custom change event.", + "props": [ + { + "name": "originalEvent", + "optional": false, + "readonly": false, + "type": "Event", + "description": "Browser event." + }, + { + "name": "value", + "optional": false, + "readonly": false, + "type": "any", + "description": "Selected value." + } + ] + } + ] + }, + "templates": { + "description": "Defines the templates used by the component.", + "values": [ + { + "parent": "inputotp", + "name": "input", + "parameters": [ + { + "name": "context", + "type": "{\n \t $implicit: any, // Input value.\n \t events: InputOtpTemplateEvents, // Events of the component\n }", + "description": "" + } + ], + "description": "Custom template of input." + } + ] + } + } + }, "inputswitch": { "components": { "InputSwitch": { diff --git a/src/app/showcase/doc/inputotp/accessibilitydoc.ts b/src/app/showcase/doc/inputotp/accessibilitydoc.ts new file mode 100644 index 00000000000..e6734c9ef50 --- /dev/null +++ b/src/app/showcase/doc/inputotp/accessibilitydoc.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'accessibility-doc', + template: `
+ +

Screen Reader

+

Input OTP uses a set of InputText components, refer to the InputText component for more information about the screen reader support.

+
+ +

Keyboard Support

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
tabMoves focus to the input otp.
right arrowMoves focus to the next input element.
left arrowMoves focus to the previous input element.
backspaceDeletes the input and moves focus to the previous input element.
+
+
` +}) +export class AccessibilityDoc {} diff --git a/src/app/showcase/doc/inputotp/basicdoc.ts b/src/app/showcase/doc/inputotp/basicdoc.ts new file mode 100644 index 00000000000..b556e9fc926 --- /dev/null +++ b/src/app/showcase/doc/inputotp/basicdoc.ts @@ -0,0 +1,37 @@ +import { Component } from '@angular/core'; +import { Code } from '../../domain/code'; + +@Component({ + selector: 'basic-doc', + template: ` + +

Two-way value binding is defined using ngModel. The number of characters is defined with the length property, which is set to 4 by default.

+
+
+ +
+ + ` +}) +export class BasicDoc { + value: any; + + code: Code = { + basic: ``, + + html: `
+ +
`, + + typescript: ` +import { Component } from '@angular/core'; + +@Component({ + selector: 'input-otp-basic-demo', + templateUrl: './input-otp-basic-demo.html' +}) +export class InputOtpBasicDemo { + value : any +}` + }; +} diff --git a/src/app/showcase/doc/inputotp/importdoc.ts b/src/app/showcase/doc/inputotp/importdoc.ts new file mode 100644 index 00000000000..ebe22dc7afd --- /dev/null +++ b/src/app/showcase/doc/inputotp/importdoc.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { Code } from '../../domain/code'; + +@Component({ + selector: 'import-doc', + template: ` ` +}) +export class ImportDoc { + code: Code = { + typescript: `import { InputOtpModule } from 'primeng/inputotp';` + }; +} diff --git a/src/app/showcase/doc/inputotp/inputotpdoc.module.ts b/src/app/showcase/doc/inputotp/inputotpdoc.module.ts new file mode 100644 index 00000000000..a7fde5cdb9e --- /dev/null +++ b/src/app/showcase/doc/inputotp/inputotpdoc.module.ts @@ -0,0 +1,24 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; +import { AppDocModule } from '../../layout/doc/app.doc.module'; +import { AppCodeModule } from '../../layout/doc/app.code.component'; +import { InputOtpModule } from 'primeng/inputotp'; +import { ImportDoc } from './importdoc'; +import { BasicDoc } from './basicdoc'; +import { MaskDoc } from './maskdoc'; +import { IntegerOnlyDoc } from './integeronlydoc'; +import { TemplateDoc } from './templatedoc'; +import { InputTextModule } from 'primeng/inputtext'; +import { SampleDoc } from './sampledoc'; +import { ButtonModule } from 'primeng/button'; +import { AccessibilityDoc } from './accessibilitydoc'; + + +@NgModule({ + imports: [CommonModule, RouterModule, AppCodeModule, AppDocModule, FormsModule, ReactiveFormsModule, InputOtpModule, InputTextModule, ButtonModule], + exports: [AppDocModule], + declarations: [ImportDoc, BasicDoc, MaskDoc, IntegerOnlyDoc, TemplateDoc, SampleDoc, AccessibilityDoc] +}) +export class InputOtpDocModule {} diff --git a/src/app/showcase/doc/inputotp/integeronlydoc.ts b/src/app/showcase/doc/inputotp/integeronlydoc.ts new file mode 100644 index 00000000000..06ebc6520f2 --- /dev/null +++ b/src/app/showcase/doc/inputotp/integeronlydoc.ts @@ -0,0 +1,38 @@ +import { Component } from '@angular/core'; +import { Code } from '../../domain/code'; + +@Component({ + selector: 'integer-only-doc', + template: ` + +

When integerOnly is present, only integers can be accepted as input.

+
+
+ +
+ + ` +}) +export class IntegerOnlyDoc { + value: any; + + code: Code = { + basic: ``, + + html: ` +
+ +
`, + + typescript: ` +import { Component } from '@angular/core'; + +@Component({ + selector: 'input-otp-integer-only-demo', + templateUrl: './input-otp-integer-only-demo.html' +}) +export class InputOtpIntegerOnlyDemo { + value : any +}` + }; +} diff --git a/src/app/showcase/doc/inputotp/maskdoc.ts b/src/app/showcase/doc/inputotp/maskdoc.ts new file mode 100644 index 00000000000..94862b5db54 --- /dev/null +++ b/src/app/showcase/doc/inputotp/maskdoc.ts @@ -0,0 +1,37 @@ +import { Component } from '@angular/core'; +import { Code } from '../../domain/code'; + +@Component({ + selector: 'mask-doc', + template: ` + +

Enable the mask option to hide the values in the input fields.

+
+
+ +
+ + ` +}) +export class MaskDoc { + value: any; + + code: Code = { + basic: ``, + + html: `
+ +
`, + + typescript: ` +import { Component } from '@angular/core'; + +@Component({ + selector: 'input-otp-mask-demo', + templateUrl: './input-otp-mask-demo.html' +}) +export class InputOtpMaskDemo { + value: any; +}` + }; +} diff --git a/src/app/showcase/doc/inputotp/sampledoc.ts b/src/app/showcase/doc/inputotp/sampledoc.ts new file mode 100644 index 00000000000..03dedfd1808 --- /dev/null +++ b/src/app/showcase/doc/inputotp/sampledoc.ts @@ -0,0 +1,160 @@ +import { Component } from '@angular/core'; +import { Code } from '../../domain/code'; + +@Component({ + selector: 'sample-doc', + template: ` + +

A sample UI implementation with templating and additional elements.

+
+
+
+
Authenticate Your Account
+

Please enter the code sent to your phone.

+ + + +
+ +
+
+
+
+ + +
+
+
+ + `, + styles: [ + ` + .custom-otp-input { + width: 48px; + height: 48px; + font-size: 24px; + appearance: none; + text-align: center; + transition: all 0.2s; + border-radius: 0; + border: 1px solid var(--surface-400); + background: transparent; + outline-offset: -2px; + outline-color: transparent; + border-right: 0 none; + transition: outline-color 0.3s; + color: var(--text-color); + } + + .custom-otp-input:focus { + outline: 2px solid var(--primary-color); + } + + .custom-otp-input:first-child, + .custom-otp-input:nth-child(5) { + border-top-left-radius: 12px; + border-bottom-left-radius: 12px; + } + + .custom-otp-input:nth-child(3), + .custom-otp-input:last-child { + border-top-right-radius: 12px; + border-bottom-right-radius: 12px; + border-right-width: 1px; + border-right-style: solid; + border-color: var(--surface-400); + } + ` + ] +}) +export class SampleDoc { + value: any; + + code: Code = { + basic: `
+
Authenticate Your Account
+

Please enter the code sent to your phone.

+ + + +
+ +
+
+
+
+ + +
+
`, + + html: `
+
+
Authenticate Your Account
+

Please enter the code sent to your phone.

+ + + +
+ +
+
+
+
+ + +
+
+
`, + + typescript: ` +import { Component } from '@angular/core'; + +@Component({ + selector: 'input-otp-sample-demo', + templateUrl: './input-otp-sample-demo.html', + styles: [ + \` + .custom-otp-input { + width: 48px; + height: 48px; + font-size: 24px; + appearance: none; + text-align: center; + transition: all 0.2s; + border-radius: 0; + border: 1px solid var(--surface-400); + background: transparent; + outline-offset: -2px; + outline-color: transparent; + border-right: 0 none; + transition: outline-color 0.3s; + color: var(--text-color); + } + + .custom-otp-input:focus { + outline: 2px solid var(--primary-color); + } + + .custom-otp-input:first-child, + .custom-otp-input:nth-child(5) { + border-top-left-radius: 12px; + border-bottom-left-radius: 12px; + } + + .custom-otp-input:nth-child(3), + .custom-otp-input:last-child { + border-top-right-radius: 12px; + border-bottom-right-radius: 12px; + border-right-width: 1px; + border-right-style: solid; + border-color: var(--surface-400); + } + \` + ], +}) +export class InputOtpSampleDemo { + value: any; +}` + }; +} diff --git a/src/app/showcase/doc/inputotp/templatedoc.ts b/src/app/showcase/doc/inputotp/templatedoc.ts new file mode 100644 index 00000000000..8aeef441ba4 --- /dev/null +++ b/src/app/showcase/doc/inputotp/templatedoc.ts @@ -0,0 +1,94 @@ +import { Component } from '@angular/core'; +import { Code } from '../../domain/code'; + +@Component({ + selector: 'template-doc', + template: ` + +

Define a template with your own UI elements with bindings to the provided events and attributes to replace the default design.

+
+
+ + + + + +
+ , + `, + styles: [ + ` + .custom-otp-input { + width: 45px; + font-size: 36px; + border: 0 none; + appearance: none; + text-align: center; + transition: all 0.2s; + background: transparent; + border-bottom: 2px solid var(--surface-500); + border-radius: 0px; + margin: 0 0.2rem; + } + + .custom-otp-input:focus { + outline: 0 none; + box-shadow: none; + border-bottom-color: var(--primary-color); + } + ` + ] +}) +export class TemplateDoc { + value: any; + + code: Code = { + basic: ` + + + +`, + + html: `
+ + + + + +
`, + + typescript: ` +import { Component } from '@angular/core'; + +@Component({ + selector: 'input-otp-template-demo', + templateUrl: './input-otp-template-demo.html', + styles: [ + \` + .custom-otp-input { + width: 45px; + font-size: 36px; + border: 0 none; + appearance: none; + text-align: center; + transition: all 0.2s; + background: transparent; + border-bottom: 2px solid var(--surface-500); + border-radius: 0px; + margin: 0 0.2rem; + } + + .custom-otp-input:focus { + outline: 0 none; + box-shadow: none; + border-bottom-color: var(--primary-color); + } + \` + ], +}) + +export class InputOtpTemplateDemo { + value: any; +}` + }; +} diff --git a/src/app/showcase/layout/app.routes.ts b/src/app/showcase/layout/app.routes.ts index 1b5b3acefdf..2411f8ee7ea 100644 --- a/src/app/showcase/layout/app.routes.ts +++ b/src/app/showcase/layout/app.routes.ts @@ -60,6 +60,7 @@ export const routes: Routes = [ { path: 'metergroup', loadChildren: () => import('../pages/metergroup/metergroupdemo.module').then((m) => m.MeterGroupDemoModule) }, { path: 'inputmask', loadChildren: () => import('../pages/inputmask/inputmaskdemo.module').then((m) => m.InputMaskDemoModule) }, { path: 'inputnumber', loadChildren: () => import('../pages/inputnumber/inputnumberdemo.module').then((m) => m.InputNumberDemoModule) }, + { path: 'inputotp', loadChildren: () => import('../pages/inputotp/inputotpdemo.module').then((m) => m.InputOtpDemoModule) }, { path: 'inputswitch', loadChildren: () => import('../pages/inputswitch/inputswitchdemo.module').then((m) => m.InputSwitchDemoModule) }, { path: 'inputtext', loadChildren: () => import('../pages/inputtext/inputtextdemo.module').then((m) => m.InputTextDemoModule) }, { path: 'inputgroup', loadChildren: () => import('../pages/inputgroup/inputgroupdemo.module').then((m) => m.InputGroupDemoModule) }, diff --git a/src/app/showcase/layout/doc/codeeditor/templates.ts b/src/app/showcase/layout/doc/codeeditor/templates.ts index 1f26d8a8be6..d21f8c37891 100644 --- a/src/app/showcase/layout/doc/codeeditor/templates.ts +++ b/src/app/showcase/layout/doc/codeeditor/templates.ts @@ -538,6 +538,7 @@ import { InputNumberModule } from 'primeng/inputnumber'; import { InputTextareaModule } from 'primeng/inputtextarea'; import { InputGroupAddonModule } from 'primeng/inputgroupaddon'; import { InputGroupModule } from 'primeng/inputgroup' +import { InputOtpModule } from 'primeng/inputotp' import { ImageModule } from 'primeng/image'; import { KnobModule } from 'primeng/knob'; import { ListboxModule } from 'primeng/listbox'; @@ -643,6 +644,7 @@ ${serviceImports} InputNumberModule, InputGroupModule, InputGroupAddonModule, + InputOtpModule, ImageModule, KnobModule, ListboxModule, diff --git a/src/app/showcase/pages/inputotp/inputotp.html b/src/app/showcase/pages/inputotp/inputotp.html new file mode 100755 index 00000000000..4b6d041c960 --- /dev/null +++ b/src/app/showcase/pages/inputotp/inputotp.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/showcase/pages/inputotp/inputotpdemo-routing.module.ts b/src/app/showcase/pages/inputotp/inputotpdemo-routing.module.ts new file mode 100755 index 00000000000..bd3f74e0cc0 --- /dev/null +++ b/src/app/showcase/pages/inputotp/inputotpdemo-routing.module.ts @@ -0,0 +1,9 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { InputOtpDemo } from './inputotpdemo'; + +@NgModule({ + imports: [RouterModule.forChild([{ path: '', component: InputOtpDemo }])], + exports: [RouterModule] +}) +export class InputOtpDemoRoutingModule {} diff --git a/src/app/showcase/pages/inputotp/inputotpdemo.module.ts b/src/app/showcase/pages/inputotp/inputotpdemo.module.ts new file mode 100755 index 00000000000..30841cc2b65 --- /dev/null +++ b/src/app/showcase/pages/inputotp/inputotpdemo.module.ts @@ -0,0 +1,11 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { InputOtpDemo } from './inputotpdemo'; +import { InputOtpDemoRoutingModule } from './inputotpdemo-routing.module'; +import { InputOtpDocModule } from '../../doc/inputotp/inputotpdoc.module'; + +@NgModule({ + imports: [CommonModule, InputOtpDemoRoutingModule, InputOtpDocModule], + declarations: [InputOtpDemo] +}) +export class InputOtpDemoModule {} diff --git a/src/app/showcase/pages/inputotp/inputotpdemo.ts b/src/app/showcase/pages/inputotp/inputotpdemo.ts new file mode 100755 index 00000000000..093d7d0b67b --- /dev/null +++ b/src/app/showcase/pages/inputotp/inputotpdemo.ts @@ -0,0 +1,56 @@ +import { Component, ViewEncapsulation } from '@angular/core'; +import { ImportDoc } from '../../doc/inputotp/importdoc'; +import { BasicDoc } from '../../doc/inputotp/basicdoc'; +import { MaskDoc } from '../../doc/inputotp/maskdoc'; +import { IntegerOnlyDoc } from '../../doc/inputotp/integeronlydoc'; +import { TemplateDoc } from '../../doc/inputotp/templatedoc'; +import { SampleDoc } from '../../doc/inputotp/sampledoc'; +import { AccessibilityDoc } from '../../doc/inputotp/accessibilitydoc'; + +@Component({ + templateUrl: './inputotp.html', + encapsulation: ViewEncapsulation.None +}) +export class InputOtpDemo { + docs = [ + { + id: 'import', + label: 'Import', + component: ImportDoc + }, + { + id: 'basic', + label: 'Basic', + component: BasicDoc + }, + { + id: 'mask', + label: 'Mask', + component: MaskDoc + }, + { + id: 'integeronly', + label: 'Integer Only', + component: IntegerOnlyDoc + }, + { + id: 'template', + label: 'Template', + component: TemplateDoc + }, + { + id: 'sample', + label: 'Sample', + component: SampleDoc + }, + { + id: 'accessibility', + label: 'Accessibility', + component: AccessibilityDoc + }, + + + + + ]; +} diff --git a/src/assets/showcase/data/menu.json b/src/assets/showcase/data/menu.json index 3f744d3967e..9850c90a284 100644 --- a/src/assets/showcase/data/menu.json +++ b/src/assets/showcase/data/menu.json @@ -89,6 +89,10 @@ "name": "InputNumber", "routerLink": "/inputnumber" }, + { + "name": "InputOtp", + "routerLink": "/inputotp" + }, { "name": "Knob", "routerLink": "/knob"