ng-primitives 0.87.0 → 0.89.0
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.
- package/breadcrumbs/README.md +3 -0
- package/breadcrumbs/breadcrumb-ellipsis/breadcrumb-ellipsis.d.ts +8 -0
- package/breadcrumbs/breadcrumb-item/breadcrumb-item.d.ts +8 -0
- package/breadcrumbs/breadcrumb-link/breadcrumb-link.d.ts +9 -0
- package/breadcrumbs/breadcrumb-list/breadcrumb-list.d.ts +8 -0
- package/breadcrumbs/breadcrumb-page/breadcrumb-page.d.ts +8 -0
- package/breadcrumbs/breadcrumb-separator/breadcrumb-separator.d.ts +8 -0
- package/breadcrumbs/breadcrumbs/breadcrumbs.d.ts +8 -0
- package/breadcrumbs/index.d.ts +7 -0
- package/date-picker/date-picker/date-picker.d.ts +2 -1
- package/date-picker/date-range-picker/date-range-picker.d.ts +3 -1
- package/fesm2022/ng-primitives-breadcrumbs.mjs +138 -0
- package/fesm2022/ng-primitives-breadcrumbs.mjs.map +1 -0
- package/fesm2022/ng-primitives-combobox.mjs +6 -0
- package/fesm2022/ng-primitives-combobox.mjs.map +1 -1
- package/fesm2022/ng-primitives-date-picker.mjs +46 -15
- package/fesm2022/ng-primitives-date-picker.mjs.map +1 -1
- package/fesm2022/ng-primitives-input-otp.mjs +514 -0
- package/fesm2022/ng-primitives-input-otp.mjs.map +1 -0
- package/input-otp/README.md +3 -0
- package/input-otp/index.d.ts +4 -0
- package/input-otp/input-otp/input-otp-state.d.ts +17 -0
- package/input-otp/input-otp/input-otp.d.ts +133 -0
- package/input-otp/input-otp-input/input-otp-input.d.ts +57 -0
- package/input-otp/input-otp-slot/input-otp-slot.d.ts +45 -0
- package/package.json +32 -24
- package/schematics/ng-generate/schema.d.ts +2 -1
- package/schematics/ng-generate/schema.json +2 -1
- package/schematics/ng-generate/templates/input-otp/input-otp.__fileSuffix@dasherize__.ts.template +197 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { BooleanInput } from '@angular/cdk/coercion';
|
|
2
|
+
import type { NgpInputOtpInput } from '../input-otp-input/input-otp-input';
|
|
3
|
+
import type { NgpInputOtpSlot } from '../input-otp-slot/input-otp-slot';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export type NgpInputOtpInputMode = 'numeric' | 'text' | 'decimal' | 'tel' | 'search' | 'email' | 'url';
|
|
6
|
+
export declare class NgpInputOtp {
|
|
7
|
+
/**
|
|
8
|
+
* Access the element reference.
|
|
9
|
+
*/
|
|
10
|
+
readonly elementRef: import("@angular/core").ElementRef<HTMLElement>;
|
|
11
|
+
/**
|
|
12
|
+
* The id of the input-otp.
|
|
13
|
+
*/
|
|
14
|
+
readonly id: import("@angular/core").InputSignal<string>;
|
|
15
|
+
/**
|
|
16
|
+
* The current value of the OTP.
|
|
17
|
+
*/
|
|
18
|
+
readonly value: import("@angular/core").InputSignal<string>;
|
|
19
|
+
/**
|
|
20
|
+
* The regex pattern for allowed characters.
|
|
21
|
+
*/
|
|
22
|
+
readonly pattern: import("@angular/core").InputSignal<string>;
|
|
23
|
+
/**
|
|
24
|
+
* The input mode for the hidden input.
|
|
25
|
+
*/
|
|
26
|
+
readonly inputMode: import("@angular/core").InputSignal<NgpInputOtpInputMode>;
|
|
27
|
+
/**
|
|
28
|
+
* Function to transform pasted text.
|
|
29
|
+
*/
|
|
30
|
+
readonly pasteTransformer: import("@angular/core").InputSignal<((text: string) => string) | undefined>;
|
|
31
|
+
/**
|
|
32
|
+
* Whether the input-otp is disabled.
|
|
33
|
+
*/
|
|
34
|
+
readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, BooleanInput>;
|
|
35
|
+
/**
|
|
36
|
+
* The placeholder character to display when a slot is empty.
|
|
37
|
+
*/
|
|
38
|
+
readonly placeholder: import("@angular/core").InputSignal<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Event emitted when the value changes.
|
|
41
|
+
*/
|
|
42
|
+
readonly valueChange: import("@angular/core").OutputEmitterRef<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Event emitted when the OTP is complete (maxLength characters entered).
|
|
45
|
+
*/
|
|
46
|
+
readonly complete: import("@angular/core").OutputEmitterRef<string>;
|
|
47
|
+
/**
|
|
48
|
+
* Store the input element reference.
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
private readonly inputElement;
|
|
52
|
+
/**
|
|
53
|
+
* Store registered slots in order.
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
private readonly slots;
|
|
57
|
+
/**
|
|
58
|
+
* The number of characters in the OTP, derived from registered slots.
|
|
59
|
+
*/
|
|
60
|
+
readonly maxLength: import("@angular/core").Signal<number>;
|
|
61
|
+
/**
|
|
62
|
+
* The focus state of the input.
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
readonly isFocused: import("@angular/core").WritableSignal<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* The selection start position.
|
|
68
|
+
* @internal
|
|
69
|
+
*/
|
|
70
|
+
readonly selectionStart: import("@angular/core").WritableSignal<number>;
|
|
71
|
+
/**
|
|
72
|
+
* The selection end position.
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
readonly selectionEnd: import("@angular/core").WritableSignal<number>;
|
|
76
|
+
/**
|
|
77
|
+
* The state of the input-otp.
|
|
78
|
+
*/
|
|
79
|
+
protected readonly state: import("ng-primitives/state").CreatedState<NgpInputOtp>;
|
|
80
|
+
constructor();
|
|
81
|
+
/**
|
|
82
|
+
* Register an input element with the input-otp.
|
|
83
|
+
* @param input The input element to register.
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
registerInput(input: NgpInputOtpInput): void;
|
|
87
|
+
/**
|
|
88
|
+
* Register a slot with the input-otp.
|
|
89
|
+
* @param slot The slot to register.
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
registerSlot(slot: NgpInputOtpSlot): void;
|
|
93
|
+
/**
|
|
94
|
+
* Unregister a slot from the input-otp.
|
|
95
|
+
* @param slot The slot to unregister.
|
|
96
|
+
* @internal
|
|
97
|
+
*/
|
|
98
|
+
unregisterSlot(slot: NgpInputOtpSlot): void;
|
|
99
|
+
/**
|
|
100
|
+
* Get the index of a registered slot.
|
|
101
|
+
* @param slot The slot to get the index for.
|
|
102
|
+
* @returns The index of the slot, or -1 if not found.
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
getSlotIndex(slot: NgpInputOtpSlot): number;
|
|
106
|
+
/**
|
|
107
|
+
* Update the value and emit change events.
|
|
108
|
+
* @param newValue The new value.
|
|
109
|
+
* @internal
|
|
110
|
+
*/
|
|
111
|
+
updateValue(newValue: string): void;
|
|
112
|
+
/**
|
|
113
|
+
* Update focus state.
|
|
114
|
+
* @param focused Whether the input is focused.
|
|
115
|
+
* @internal
|
|
116
|
+
*/
|
|
117
|
+
updateFocus(focused: boolean): void;
|
|
118
|
+
/**
|
|
119
|
+
* Update selection state.
|
|
120
|
+
* @param start Selection start position.
|
|
121
|
+
* @param end Selection end position.
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
124
|
+
updateSelection(start: number, end: number): void;
|
|
125
|
+
/**
|
|
126
|
+
* Focus the input and set caret to the specified position.
|
|
127
|
+
* @param position The position to set the caret to.
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
focusAtPosition(position: number): void;
|
|
131
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NgpInputOtp, never>;
|
|
132
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<NgpInputOtp, "[ngpInputOtp]", ["ngpInputOtp"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "ngpInputOtpValue"; "required": false; "isSignal": true; }; "pattern": { "alias": "ngpInputOtpPattern"; "required": false; "isSignal": true; }; "inputMode": { "alias": "ngpInputOtpInputMode"; "required": false; "isSignal": true; }; "pasteTransformer": { "alias": "ngpInputOtpPasteTransformer"; "required": false; "isSignal": true; }; "disabled": { "alias": "ngpInputOtpDisabled"; "required": false; "isSignal": true; }; "placeholder": { "alias": "ngpInputOtpPlaceholder"; "required": false; "isSignal": true; }; }, { "valueChange": "ngpInputOtpValueChange"; "complete": "ngpInputOtpComplete"; }, never, never, true, never>;
|
|
133
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { AfterViewInit } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import * as i1 from "ng-primitives/a11y";
|
|
4
|
+
export declare class NgpInputOtpInput implements AfterViewInit {
|
|
5
|
+
/**
|
|
6
|
+
* Access the element reference.
|
|
7
|
+
*/
|
|
8
|
+
readonly elementRef: import("@angular/core").ElementRef<HTMLInputElement>;
|
|
9
|
+
/**
|
|
10
|
+
* Access the input-otp state.
|
|
11
|
+
*/
|
|
12
|
+
protected readonly state: import("@angular/core").Signal<import("ng-primitives/state").State<import("ng-primitives/input-otp").NgpInputOtp>>;
|
|
13
|
+
constructor();
|
|
14
|
+
ngAfterViewInit(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Focus the input.
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
focus(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Set selection range.
|
|
22
|
+
* @param start Start position
|
|
23
|
+
* @param end End position
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
setSelectionRange(start: number, end: number): void;
|
|
27
|
+
/**
|
|
28
|
+
* Handle input events (typing).
|
|
29
|
+
*/
|
|
30
|
+
protected onInput(event: Event): void;
|
|
31
|
+
/**
|
|
32
|
+
* Handle paste events.
|
|
33
|
+
*/
|
|
34
|
+
protected onPaste(event: ClipboardEvent): void;
|
|
35
|
+
/**
|
|
36
|
+
* Handle focus events.
|
|
37
|
+
*/
|
|
38
|
+
protected onFocus(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Handle blur events.
|
|
41
|
+
*/
|
|
42
|
+
protected onBlur(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Handle keyup events to update selection.
|
|
45
|
+
*/
|
|
46
|
+
protected onKeyup(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Handle selection change events.
|
|
49
|
+
*/
|
|
50
|
+
protected onSelect(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Update the selection state.
|
|
53
|
+
*/
|
|
54
|
+
private updateSelection;
|
|
55
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NgpInputOtpInput, never>;
|
|
56
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<NgpInputOtpInput, "input[ngpInputOtpInput]", ["ngpInputOtpInput"], {}, {}, never, never, true, [{ directive: typeof i1.NgpVisuallyHidden; inputs: {}; outputs: {}; }]>;
|
|
57
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { OnDestroy } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare class NgpInputOtpSlot implements OnDestroy {
|
|
4
|
+
/**
|
|
5
|
+
* Access the input-otp state.
|
|
6
|
+
*/
|
|
7
|
+
protected readonly state: import("@angular/core").Signal<import("ng-primitives/state").State<import("ng-primitives/input-otp").NgpInputOtp>>;
|
|
8
|
+
/**
|
|
9
|
+
* The computed index of this slot based on registration order.
|
|
10
|
+
*/
|
|
11
|
+
readonly index: import("@angular/core").Signal<number>;
|
|
12
|
+
/**
|
|
13
|
+
* The character for this slot from the value string.
|
|
14
|
+
*/
|
|
15
|
+
private readonly char;
|
|
16
|
+
/**
|
|
17
|
+
* Whether this slot is focused (active).
|
|
18
|
+
*/
|
|
19
|
+
protected readonly focused: import("@angular/core").Signal<boolean>;
|
|
20
|
+
/**
|
|
21
|
+
* Whether this slot should show the caret.
|
|
22
|
+
*/
|
|
23
|
+
protected readonly caret: import("@angular/core").Signal<boolean>;
|
|
24
|
+
/**
|
|
25
|
+
* Whether this slot is filled with a character.
|
|
26
|
+
*/
|
|
27
|
+
protected readonly filled: import("@angular/core").Signal<boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* Whether to show placeholder for this slot.
|
|
30
|
+
*/
|
|
31
|
+
protected readonly showPlaceholder: import("@angular/core").Signal<boolean>;
|
|
32
|
+
/**
|
|
33
|
+
* The display character for this slot (character or placeholder).
|
|
34
|
+
*/
|
|
35
|
+
protected readonly displayChar: import("@angular/core").Signal<string>;
|
|
36
|
+
constructor();
|
|
37
|
+
ngOnDestroy(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Handle click events on the slot.
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
protected onClick(event: Event): void;
|
|
43
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NgpInputOtpSlot, never>;
|
|
44
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<NgpInputOtpSlot, "[ngpInputOtpSlot]", ["ngpInputOtpSlot"], {}, {}, never, never, true, never>;
|
|
45
|
+
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "ng-primitives",
|
|
3
3
|
"description": "Angular Primitives is a low-level headless UI component library with a focus on accessibility, customization, and developer experience. ",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.89.0",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"angular",
|
|
8
8
|
"primitives",
|
|
@@ -71,10 +71,6 @@
|
|
|
71
71
|
"types": "./accordion/index.d.ts",
|
|
72
72
|
"default": "./fesm2022/ng-primitives-accordion.mjs"
|
|
73
73
|
},
|
|
74
|
-
"./ai": {
|
|
75
|
-
"types": "./ai/index.d.ts",
|
|
76
|
-
"default": "./fesm2022/ng-primitives-ai.mjs"
|
|
77
|
-
},
|
|
78
74
|
"./avatar": {
|
|
79
75
|
"types": "./avatar/index.d.ts",
|
|
80
76
|
"default": "./fesm2022/ng-primitives-avatar.mjs"
|
|
@@ -83,6 +79,14 @@
|
|
|
83
79
|
"types": "./autofill/index.d.ts",
|
|
84
80
|
"default": "./fesm2022/ng-primitives-autofill.mjs"
|
|
85
81
|
},
|
|
82
|
+
"./breadcrumbs": {
|
|
83
|
+
"types": "./breadcrumbs/index.d.ts",
|
|
84
|
+
"default": "./fesm2022/ng-primitives-breadcrumbs.mjs"
|
|
85
|
+
},
|
|
86
|
+
"./ai": {
|
|
87
|
+
"types": "./ai/index.d.ts",
|
|
88
|
+
"default": "./fesm2022/ng-primitives-ai.mjs"
|
|
89
|
+
},
|
|
86
90
|
"./button": {
|
|
87
91
|
"types": "./button/index.d.ts",
|
|
88
92
|
"default": "./fesm2022/ng-primitives-button.mjs"
|
|
@@ -95,22 +99,22 @@
|
|
|
95
99
|
"types": "./combobox/index.d.ts",
|
|
96
100
|
"default": "./fesm2022/ng-primitives-combobox.mjs"
|
|
97
101
|
},
|
|
98
|
-
"./common": {
|
|
99
|
-
"types": "./common/index.d.ts",
|
|
100
|
-
"default": "./fesm2022/ng-primitives-common.mjs"
|
|
101
|
-
},
|
|
102
102
|
"./date-picker": {
|
|
103
103
|
"types": "./date-picker/index.d.ts",
|
|
104
104
|
"default": "./fesm2022/ng-primitives-date-picker.mjs"
|
|
105
105
|
},
|
|
106
|
-
"./
|
|
107
|
-
"types": "./
|
|
108
|
-
"default": "./fesm2022/ng-primitives-
|
|
106
|
+
"./common": {
|
|
107
|
+
"types": "./common/index.d.ts",
|
|
108
|
+
"default": "./fesm2022/ng-primitives-common.mjs"
|
|
109
109
|
},
|
|
110
110
|
"./date-time": {
|
|
111
111
|
"types": "./date-time/index.d.ts",
|
|
112
112
|
"default": "./fesm2022/ng-primitives-date-time.mjs"
|
|
113
113
|
},
|
|
114
|
+
"./date-time-luxon": {
|
|
115
|
+
"types": "./date-time-luxon/index.d.ts",
|
|
116
|
+
"default": "./fesm2022/ng-primitives-date-time-luxon.mjs"
|
|
117
|
+
},
|
|
114
118
|
"./dialog": {
|
|
115
119
|
"types": "./dialog/index.d.ts",
|
|
116
120
|
"default": "./fesm2022/ng-primitives-dialog.mjs"
|
|
@@ -131,6 +135,10 @@
|
|
|
131
135
|
"types": "./input/index.d.ts",
|
|
132
136
|
"default": "./fesm2022/ng-primitives-input.mjs"
|
|
133
137
|
},
|
|
138
|
+
"./input-otp": {
|
|
139
|
+
"types": "./input-otp/index.d.ts",
|
|
140
|
+
"default": "./fesm2022/ng-primitives-input-otp.mjs"
|
|
141
|
+
},
|
|
134
142
|
"./interactions": {
|
|
135
143
|
"types": "./interactions/index.d.ts",
|
|
136
144
|
"default": "./fesm2022/ng-primitives-interactions.mjs"
|
|
@@ -147,14 +155,14 @@
|
|
|
147
155
|
"types": "./menu/index.d.ts",
|
|
148
156
|
"default": "./fesm2022/ng-primitives-menu.mjs"
|
|
149
157
|
},
|
|
150
|
-
"./meter": {
|
|
151
|
-
"types": "./meter/index.d.ts",
|
|
152
|
-
"default": "./fesm2022/ng-primitives-meter.mjs"
|
|
153
|
-
},
|
|
154
158
|
"./pagination": {
|
|
155
159
|
"types": "./pagination/index.d.ts",
|
|
156
160
|
"default": "./fesm2022/ng-primitives-pagination.mjs"
|
|
157
161
|
},
|
|
162
|
+
"./meter": {
|
|
163
|
+
"types": "./meter/index.d.ts",
|
|
164
|
+
"default": "./fesm2022/ng-primitives-meter.mjs"
|
|
165
|
+
},
|
|
158
166
|
"./popover": {
|
|
159
167
|
"types": "./popover/index.d.ts",
|
|
160
168
|
"default": "./fesm2022/ng-primitives-popover.mjs"
|
|
@@ -171,14 +179,14 @@
|
|
|
171
179
|
"types": "./radio/index.d.ts",
|
|
172
180
|
"default": "./fesm2022/ng-primitives-radio.mjs"
|
|
173
181
|
},
|
|
174
|
-
"./resize": {
|
|
175
|
-
"types": "./resize/index.d.ts",
|
|
176
|
-
"default": "./fesm2022/ng-primitives-resize.mjs"
|
|
177
|
-
},
|
|
178
182
|
"./roving-focus": {
|
|
179
183
|
"types": "./roving-focus/index.d.ts",
|
|
180
184
|
"default": "./fesm2022/ng-primitives-roving-focus.mjs"
|
|
181
185
|
},
|
|
186
|
+
"./resize": {
|
|
187
|
+
"types": "./resize/index.d.ts",
|
|
188
|
+
"default": "./fesm2022/ng-primitives-resize.mjs"
|
|
189
|
+
},
|
|
182
190
|
"./search": {
|
|
183
191
|
"types": "./search/index.d.ts",
|
|
184
192
|
"default": "./fesm2022/ng-primitives-search.mjs"
|
|
@@ -211,10 +219,6 @@
|
|
|
211
219
|
"types": "./textarea/index.d.ts",
|
|
212
220
|
"default": "./fesm2022/ng-primitives-textarea.mjs"
|
|
213
221
|
},
|
|
214
|
-
"./toast": {
|
|
215
|
-
"types": "./toast/index.d.ts",
|
|
216
|
-
"default": "./fesm2022/ng-primitives-toast.mjs"
|
|
217
|
-
},
|
|
218
222
|
"./toggle": {
|
|
219
223
|
"types": "./toggle/index.d.ts",
|
|
220
224
|
"default": "./fesm2022/ng-primitives-toggle.mjs"
|
|
@@ -223,6 +227,10 @@
|
|
|
223
227
|
"types": "./toggle-group/index.d.ts",
|
|
224
228
|
"default": "./fesm2022/ng-primitives-toggle-group.mjs"
|
|
225
229
|
},
|
|
230
|
+
"./toast": {
|
|
231
|
+
"types": "./toast/index.d.ts",
|
|
232
|
+
"default": "./fesm2022/ng-primitives-toast.mjs"
|
|
233
|
+
},
|
|
226
234
|
"./toolbar": {
|
|
227
235
|
"types": "./toolbar/index.d.ts",
|
|
228
236
|
"default": "./fesm2022/ng-primitives-toolbar.mjs"
|
|
@@ -30,7 +30,8 @@ export interface AngularPrimitivesComponentSchema {
|
|
|
30
30
|
| 'popover'
|
|
31
31
|
| 'combobox'
|
|
32
32
|
| 'select'
|
|
33
|
-
| 'native-select'
|
|
33
|
+
| 'native-select'
|
|
34
|
+
| 'input-otp';
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* The path where the component files should be created, relative to the current workspace.
|
|
@@ -20,16 +20,17 @@
|
|
|
20
20
|
"file-upload",
|
|
21
21
|
"form-field",
|
|
22
22
|
"input",
|
|
23
|
+
"input-otp",
|
|
23
24
|
"listbox",
|
|
24
25
|
"menu",
|
|
25
26
|
"meter",
|
|
27
|
+
"native-select",
|
|
26
28
|
"pagination",
|
|
27
29
|
"popover",
|
|
28
30
|
"progress",
|
|
29
31
|
"radio",
|
|
30
32
|
"search",
|
|
31
33
|
"select",
|
|
32
|
-
"native-select",
|
|
33
34
|
"separator",
|
|
34
35
|
"slider",
|
|
35
36
|
"switch",
|
package/schematics/ng-generate/templates/input-otp/input-otp.__fileSuffix@dasherize__.ts.template
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { BooleanInput, NumberInput } from '@angular/cdk/coercion';
|
|
2
|
+
import {
|
|
3
|
+
booleanAttribute,
|
|
4
|
+
Component,
|
|
5
|
+
computed,
|
|
6
|
+
forwardRef,
|
|
7
|
+
input,
|
|
8
|
+
model,
|
|
9
|
+
numberAttribute,
|
|
10
|
+
signal,
|
|
11
|
+
} from '@angular/core';
|
|
12
|
+
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
13
|
+
import { NgpInputOtp, NgpInputOtpInput, NgpInputOtpSlot } from 'ng-primitives/input-otp';
|
|
14
|
+
import { ChangeFn, TouchedFn } from 'ng-primitives/utils';
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
selector: '<%= prefix %>-input-otp',
|
|
18
|
+
imports: [NgpInputOtp, NgpInputOtpInput, NgpInputOtpSlot],
|
|
19
|
+
providers: [
|
|
20
|
+
{
|
|
21
|
+
provide: NG_VALUE_ACCESSOR,
|
|
22
|
+
useExisting: forwardRef(() => InputOtp<%= componentSuffix %>),
|
|
23
|
+
multi: true,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
template: `
|
|
27
|
+
<div
|
|
28
|
+
[ngpInputOtpValue]="value()"
|
|
29
|
+
[ngpInputOtpDisabled]="disabled() || formDisabled()"
|
|
30
|
+
[ngpInputOtpPattern]="pattern()"
|
|
31
|
+
[ngpInputOtpPlaceholder]="placeholder()"
|
|
32
|
+
[ngpInputOtpInputMode]="inputMode()"
|
|
33
|
+
(ngpInputOtpValueChange)="onValueChange($event)"
|
|
34
|
+
(ngpInputOtpComplete)="onComplete()"
|
|
35
|
+
ngpInputOtp
|
|
36
|
+
>
|
|
37
|
+
<input ngpInputOtpInput />
|
|
38
|
+
<div class="slots">
|
|
39
|
+
@for (_ of slots(); track $index) {
|
|
40
|
+
<div class="slot" ngpInputOtpSlot></div>
|
|
41
|
+
}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
`,
|
|
45
|
+
styles: `
|
|
46
|
+
/* These styles rely on CSS variables that can be imported from ng-primitives/example-theme/index.css in your global styles */
|
|
47
|
+
|
|
48
|
+
:host {
|
|
49
|
+
display: inline-flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
gap: 12px;
|
|
52
|
+
max-width: 100%;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.slots {
|
|
56
|
+
display: flex;
|
|
57
|
+
gap: 8px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.slot {
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
justify-content: center;
|
|
64
|
+
width: 48px;
|
|
65
|
+
height: 48px;
|
|
66
|
+
border: 2px solid var(--ngp-border);
|
|
67
|
+
border-radius: 8px;
|
|
68
|
+
background: var(--ngp-background);
|
|
69
|
+
font-size: 18px;
|
|
70
|
+
font-weight: 600;
|
|
71
|
+
color: var(--ngp-text-primary);
|
|
72
|
+
transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
position: relative;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.slot[data-filled] {
|
|
78
|
+
border-color: var(--ngp-border-strong);
|
|
79
|
+
background: var(--ngp-background-accent);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.slot[data-active] {
|
|
83
|
+
border-color: var(--ngp-focus-ring);
|
|
84
|
+
box-shadow: 0 0 0 1px var(--ngp-focus-ring);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.slot[data-placeholder] {
|
|
88
|
+
color: var(--ngp-text-placeholder);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.slot[data-caret]::after {
|
|
92
|
+
content: '';
|
|
93
|
+
position: absolute;
|
|
94
|
+
width: 2px;
|
|
95
|
+
height: 20px;
|
|
96
|
+
background: var(--ngp-focus-ring);
|
|
97
|
+
animation: blink 1s infinite;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@keyframes blink {
|
|
101
|
+
0%,
|
|
102
|
+
50% {
|
|
103
|
+
opacity: 1;
|
|
104
|
+
}
|
|
105
|
+
51%,
|
|
106
|
+
100% {
|
|
107
|
+
opacity: 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
:host([data-disabled]) .slot {
|
|
112
|
+
background: var(--ngp-background-disabled);
|
|
113
|
+
color: var(--ngp-text-disabled);
|
|
114
|
+
border-color: var(--ngp-border-disabled);
|
|
115
|
+
cursor: not-allowed;
|
|
116
|
+
}
|
|
117
|
+
`,
|
|
118
|
+
})
|
|
119
|
+
export class InputOtp<%= componentSuffix %> implements ControlValueAccessor {
|
|
120
|
+
/**
|
|
121
|
+
* The number of slots to display.
|
|
122
|
+
*/
|
|
123
|
+
readonly length = input<number, NumberInput>(6, {
|
|
124
|
+
transform: numberAttribute,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Whether the input is disabled.
|
|
129
|
+
*/
|
|
130
|
+
readonly disabled = input<boolean, BooleanInput>(false, {
|
|
131
|
+
transform: booleanAttribute,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The pattern for allowed characters.
|
|
136
|
+
*/
|
|
137
|
+
readonly pattern = input('[0-9]');
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The placeholder character for empty slots.
|
|
141
|
+
*/
|
|
142
|
+
readonly placeholder = input('');
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The input mode for the hidden input.
|
|
146
|
+
*/
|
|
147
|
+
readonly inputMode = input<'numeric' | 'text' | 'decimal' | 'tel' | 'search' | 'email' | 'url'>(
|
|
148
|
+
'numeric',
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Create an array for tracking slots.
|
|
153
|
+
*/
|
|
154
|
+
protected readonly slots = computed(() => Array.from({ length: this.length() }, (_, i) => i));
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The current value.
|
|
158
|
+
*/
|
|
159
|
+
readonly value = model<string>('');
|
|
160
|
+
|
|
161
|
+
private onChange: ChangeFn<string> = () => {};
|
|
162
|
+
private onTouched: TouchedFn = () => {};
|
|
163
|
+
|
|
164
|
+
protected readonly formDisabled = signal(false);
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Handle value changes from the input-otp directive.
|
|
168
|
+
*/
|
|
169
|
+
onValueChange(value: string): void {
|
|
170
|
+
this.value.set(value);
|
|
171
|
+
this.onChange(value);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Handle completion events from the input-otp directive.
|
|
176
|
+
*/
|
|
177
|
+
onComplete(): void {
|
|
178
|
+
this.onTouched();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ControlValueAccessor implementation
|
|
182
|
+
writeValue(value: string): void {
|
|
183
|
+
this.value.set(value);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
registerOnChange(fn: ChangeFn<string>): void {
|
|
187
|
+
this.onChange = fn;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
registerOnTouched(fn: TouchedFn): void {
|
|
191
|
+
this.onTouched = fn;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
setDisabledState(isDisabled: boolean): void {
|
|
195
|
+
this.formDisabled.set(isDisabled);
|
|
196
|
+
}
|
|
197
|
+
}
|