@egose/shadcn-theme-ng 0.1.0 → 0.2.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/README.md +1 -1
- package/accordion/README.md +405 -2
- package/alert/README.md +372 -2
- package/alert-dialog/README.md +471 -5
- package/aspect-ratio/README.md +272 -5
- package/autocomplete/README.md +502 -2
- package/avatar/README.md +357 -5
- package/badge/README.md +318 -2
- package/basic-alert/README.md +353 -2
- package/breadcrumb/README.md +406 -5
- package/button/README.md +482 -2
- package/button/fesm2022/button.mjs +85 -107
- package/button/types/button.d.ts +5 -8
- package/button-group/README.md +318 -5
- package/calendar/README.md +357 -2
- package/card/README.md +331 -5
- package/carousel/README.md +333 -5
- package/carousel/fesm2022/carousel.mjs +4 -1
- package/checkbox/README.md +320 -2
- package/collapsible/README.md +332 -5
- package/combobox/README.md +507 -5
- package/combobox/fesm2022/combobox.mjs +4 -1
- package/command/README.md +435 -5
- package/confirmation-dialog/README.md +301 -2
- package/context-menu/README.md +366 -5
- package/date-picker/README.md +465 -2
- package/date-picker/fesm2022/date-picker.mjs +2 -2
- package/dialog/README.md +448 -2
- package/drawer/README.md +395 -5
- package/dropdown-menu/README.md +417 -5
- package/empty/README.md +329 -5
- package/field/README.md +385 -5
- package/form-checkbox/README.md +312 -2
- package/form-date-picker/README.md +322 -2
- package/form-field/README.md +356 -2
- package/form-field-simple/README.md +340 -2
- package/form-searchable-multiselect/README.md +361 -2
- package/form-select/README.md +350 -2
- package/form-text-input/README.md +371 -2
- package/form-textarea/README.md +347 -2
- package/hover-card/README.md +256 -5
- package/icon/README.md +239 -2
- package/input/README.md +269 -2
- package/input-group/README.md +335 -5
- package/input-group/fesm2022/input-group.mjs +3 -3
- package/input-otp/README.md +375 -5
- package/item/README.md +385 -5
- package/item/fesm2022/item.mjs +3 -3
- package/kbd/README.md +291 -5
- package/label/README.md +272 -2
- package/layout-simple/README.md +193 -2
- package/layout-simple/fesm2022/layout-simple.mjs +472 -236
- package/layout-simple/types/layout-simple.d.ts +174 -137
- package/menu/README.md +417 -2
- package/menubar/README.md +343 -5
- package/native-select/README.md +323 -5
- package/navigation-menu/README.md +369 -5
- package/package.json +1 -1
- package/pagination/README.md +388 -5
- package/popover/README.md +331 -2
- package/progress/README.md +311 -5
- package/radio-group/README.md +364 -2
- package/radio-group/fesm2022/radio-group.mjs +5 -1
- package/radio-group/types/radio-group.d.ts +1 -1
- package/resizable/README.md +269 -5
- package/scroll-area/README.md +233 -5
- package/searchable-multiselect/README.md +323 -2
- package/select/README.md +437 -2
- package/separator/README.md +222 -2
- package/sheet/README.md +311 -2
- package/sidebar/README.md +457 -5
- package/skeleton/README.md +217 -5
- package/slider/README.md +273 -5
- package/slider/fesm2022/slider.mjs +3 -3
- package/sonner/README.md +346 -2
- package/spinner/README.md +284 -2
- package/switch/README.md +310 -2
- package/table/README.md +423 -5
- package/tabs/README.md +411 -2
- package/tabs/fesm2022/tabs.mjs +2 -2
- package/textarea/README.md +282 -5
- package/toggle/README.md +270 -5
- package/toggle-group/README.md +340 -5
- package/tooltip/README.md +269 -2
- package/typography/README.md +271 -5
- package/typography/types/typography.d.ts +8 -8
- package/utils/README.md +303 -2
package/input-otp/README.md
CHANGED
|
@@ -1,11 +1,381 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Input OTP (`@egose/shadcn-theme-ng/input-otp`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
One-time-password entry: a row of individual character slots (with a blinking fake caret) that behaves as a single field — the shadcn/ui _InputOTP_ equivalent (6-digit SMS/email verification codes, 2FA, invite codes). Keystroke handling, paste splitting, and the `ControlValueAccessor` come from spartan-ng's `BrnInputOtp` family; this subpath adds the shadcn slot styling, group wrapper, separator glyph, and fake caret.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> **Ships as:** `@egose/shadcn-theme-ng/input-otp` (plain Tailwind) and `@egose/shadcn-theme-ng-tw/input-otp` (`tw:`-prefixed variant). See the [package README](../../README.md) for installation, peer dependencies, and the Tailwind-variant contract. Do not publish this project directory independently.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Installation
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
# Plain Tailwind (no prefix)
|
|
11
|
+
npm install @egose/shadcn-theme-ng
|
|
12
|
+
|
|
13
|
+
# Or the tw:-prefixed variant
|
|
14
|
+
npm install @egose/shadcn-theme-ng-tw
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Peer dependencies (Angular, CDK, `@spartan-ng/brain`, `rxjs`) are documented in the [package README](../../README.md#peer-dependencies).
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { HlmInputOtpImports } from '@egose/shadcn-theme-ng/input-otp';
|
|
21
|
+
// tw variant:
|
|
22
|
+
// import { HlmInputOtpImports } from '@egose/shadcn-theme-ng-tw/input-otp';
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Imports
|
|
26
|
+
|
|
27
|
+
The behavior host `BrnInputOtp` lives in `@spartan-ng/brain/input-otp` — import it alongside the styling imports:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// Standalone component:
|
|
31
|
+
import { BrnInputOtp } from '@spartan-ng/brain/input-otp';
|
|
32
|
+
import { HlmInputOtpImports } from '@egose/shadcn-theme-ng/input-otp';
|
|
33
|
+
|
|
34
|
+
@Component({
|
|
35
|
+
standalone: true,
|
|
36
|
+
imports: [BrnInputOtp, HlmInputOtpImports],
|
|
37
|
+
template: `
|
|
38
|
+
<brn-input-otp hlmInputOtp [length]="6">
|
|
39
|
+
<div hlmInputOtpGroup>
|
|
40
|
+
<hlm-input-otp-slot index="0" />
|
|
41
|
+
<hlm-input-otp-slot index="1" />
|
|
42
|
+
<hlm-input-otp-slot index="2" />
|
|
43
|
+
</div>
|
|
44
|
+
<hlm-input-otp-separator />
|
|
45
|
+
<div hlmInputOtpGroup>
|
|
46
|
+
<hlm-input-otp-slot index="3" />
|
|
47
|
+
<hlm-input-otp-slot index="4" />
|
|
48
|
+
<hlm-input-otp-slot index="5" />
|
|
49
|
+
</div>
|
|
50
|
+
</brn-input-otp>
|
|
51
|
+
`,
|
|
52
|
+
})
|
|
53
|
+
export class MyComp {}
|
|
11
54
|
```
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// NgModule-based:
|
|
58
|
+
import { HlmInputOtpModule } from '@egose/shadcn-theme-ng/input-otp';
|
|
59
|
+
|
|
60
|
+
@NgModule({ imports: [BrnInputOtp, HlmInputOtpModule] })
|
|
61
|
+
export class MyModule {}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Exported from `src/public-api.ts`: `HlmInputOtp`, `HlmInputOtpGroup`, `HlmInputOtpSeparator`, `HlmInputOtpSlot`, `HlmInputOtpFakeCaret`, plus `HlmInputOtpImports` and `HlmInputOtpModule`.
|
|
65
|
+
|
|
66
|
+
## Anatomy / Structure
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<label for="otp-code">Verification code</label>
|
|
70
|
+
<brn-input-otp hlmInputOtp [length]="6" inputId="otp-code">
|
|
71
|
+
<div hlmInputOtpGroup>
|
|
72
|
+
<hlm-input-otp-slot index="0" />
|
|
73
|
+
<hlm-input-otp-slot index="1" />
|
|
74
|
+
<hlm-input-otp-slot index="2" />
|
|
75
|
+
</div>
|
|
76
|
+
<hlm-input-otp-separator />
|
|
77
|
+
<div hlmInputOtpGroup>
|
|
78
|
+
<hlm-input-otp-slot index="3" />
|
|
79
|
+
<hlm-input-otp-slot index="4" />
|
|
80
|
+
<hlm-input-otp-slot index="5" />
|
|
81
|
+
</div>
|
|
82
|
+
</brn-input-otp>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Real selectors: `brn-input-otp[hlmInputOtp]` / `brn-input-otp[hlm]` (flex row container, `data-slot="input-otp"`); `[hlmInputOtpGroup]` / `hlm-input-otp-group` (slot cluster, `data-slot="input-otp-group"`); `hlm-input-otp-slot` (component, requires `index`, renders `brn-input-otp-slot` + `hlm-input-otp-fake-caret`); `hlm-input-otp-separator` (component, `role="separator"`, `lucideMinus` glyph); `hlm-input-otp-fake-caret` (blinking caret block, usually not used directly — the slot renders it).
|
|
86
|
+
|
|
87
|
+
Brain inputs on `brn-input-otp` (from `@spartan-ng/brain/input-otp`): `length` (**required**), `value` / `valueChange`, `completed`, `disabled`, `inputId`, `inputAutocomplete`, `inputMode`, `inputClass`, `autofocus`, `transformPaste`, `hostStyles` / `inputStyles` / `containerStyles`.
|
|
88
|
+
|
|
89
|
+
## API reference
|
|
90
|
+
|
|
91
|
+
### `brn-input-otp[hlmInputOtp]` — `HlmInputOtp`
|
|
92
|
+
|
|
93
|
+
Pure styling directive (`data-slot="input-otp"`, flex row, dims on `has-disabled`). No inputs/outputs — bind `length`, `value`, `disabled`, `inputId`, … on the `brn-input-otp` element itself.
|
|
94
|
+
|
|
95
|
+
### `[hlmInputOtpGroup]` — `HlmInputOtpGroup`
|
|
96
|
+
|
|
97
|
+
Slot cluster wrapper (`data-slot="input-otp-group"`). No inputs/outputs. Use one group per visual cluster (e.g. `3+3` with a separator, or a single group of 4/6).
|
|
98
|
+
|
|
99
|
+
### `hlm-input-otp-slot` — `HlmInputOtpSlot`
|
|
100
|
+
|
|
101
|
+
| Input | Type | Description |
|
|
102
|
+
| ------- | -------------------------------------------------- | -------------------------------------------------------- |
|
|
103
|
+
| `index` | `number` (**required**, `numberAttribute` coerced) | Zero-based position of the character this slot displays. |
|
|
104
|
+
|
|
105
|
+
Renders `<brn-input-otp-slot [index]>` internally; active slot gets the `ring` highlight, invalid state the destructive border.
|
|
106
|
+
|
|
107
|
+
### `hlm-input-otp-separator` — `HlmInputOtpSeparator`
|
|
108
|
+
|
|
109
|
+
Visual `-` divider between groups (`role="separator"`, `lucideMinus` via `ng-icon`). No inputs/outputs.
|
|
110
|
+
|
|
111
|
+
### `hlm-input-otp-fake-caret` — `HlmInputOtpFakeCaret`
|
|
112
|
+
|
|
113
|
+
Blinking caret block rendered inside each slot. No inputs/outputs; not normally instantiated directly.
|
|
114
|
+
|
|
115
|
+
## Examples
|
|
116
|
+
|
|
117
|
+
### 1. Basic 6-digit code (3+3 with separator)
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { Component } from '@angular/core';
|
|
121
|
+
import { BrnInputOtp } from '@spartan-ng/brain/input-otp';
|
|
122
|
+
import { HlmInputOtpImports } from '@egose/shadcn-theme-ng/input-otp';
|
|
123
|
+
|
|
124
|
+
@Component({
|
|
125
|
+
standalone: true,
|
|
126
|
+
imports: [BrnInputOtp, HlmInputOtpImports],
|
|
127
|
+
template: `
|
|
128
|
+
<label for="otp-code">Verification code</label>
|
|
129
|
+
<brn-input-otp hlmInputOtp [length]="6" inputId="otp-code">
|
|
130
|
+
<div hlmInputOtpGroup>
|
|
131
|
+
<hlm-input-otp-slot index="0" />
|
|
132
|
+
<hlm-input-otp-slot index="1" />
|
|
133
|
+
<hlm-input-otp-slot index="2" />
|
|
134
|
+
</div>
|
|
135
|
+
<hlm-input-otp-separator />
|
|
136
|
+
<div hlmInputOtpGroup>
|
|
137
|
+
<hlm-input-otp-slot index="3" />
|
|
138
|
+
<hlm-input-otp-slot index="4" />
|
|
139
|
+
<hlm-input-otp-slot index="5" />
|
|
140
|
+
</div>
|
|
141
|
+
</brn-input-otp>
|
|
142
|
+
`,
|
|
143
|
+
})
|
|
144
|
+
export class BasicExample {}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 2. Reactive form + auto-submit on `completed`
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { Component } from '@angular/core';
|
|
151
|
+
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
|
152
|
+
import { BrnInputOtp } from '@spartan-ng/brain/input-otp';
|
|
153
|
+
import { HlmInputOtpImports } from '@egose/shadcn-theme-ng/input-otp';
|
|
154
|
+
|
|
155
|
+
@Component({
|
|
156
|
+
standalone: true,
|
|
157
|
+
imports: [ReactiveFormsModule, BrnInputOtp, HlmInputOtpImports],
|
|
158
|
+
template: `
|
|
159
|
+
<form [formGroup]="form">
|
|
160
|
+
<label for="otp">Enter the 6-digit code</label>
|
|
161
|
+
<brn-input-otp
|
|
162
|
+
hlmInputOtp
|
|
163
|
+
formControlName="code"
|
|
164
|
+
[length]="6"
|
|
165
|
+
inputId="otp"
|
|
166
|
+
inputMode="numeric"
|
|
167
|
+
inputAutocomplete="one-time-code"
|
|
168
|
+
(completed)="verify()"
|
|
169
|
+
>
|
|
170
|
+
<div hlmInputOtpGroup>
|
|
171
|
+
<hlm-input-otp-slot index="0" />
|
|
172
|
+
<hlm-input-otp-slot index="1" />
|
|
173
|
+
<hlm-input-otp-slot index="2" />
|
|
174
|
+
<hlm-input-otp-slot index="3" />
|
|
175
|
+
<hlm-input-otp-slot index="4" />
|
|
176
|
+
<hlm-input-otp-slot index="5" />
|
|
177
|
+
</div>
|
|
178
|
+
</brn-input-otp>
|
|
179
|
+
<p class="tw:text-sm">Value: {{ form.value.code }}</p>
|
|
180
|
+
</form>
|
|
181
|
+
`,
|
|
182
|
+
})
|
|
183
|
+
export class ReactiveExample {
|
|
184
|
+
readonly form = new FormGroup({
|
|
185
|
+
code: new FormControl<string>('', { nonNullable: true, validators: [Validators.minLength(6)] }),
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
verify() {
|
|
189
|
+
console.log('verifying', this.form.value.code);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 3. Two-way value binding + controlled value
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
import { Component, signal } from '@angular/core';
|
|
198
|
+
import { BrnInputOtp } from '@spartan-ng/brain/input-otp';
|
|
199
|
+
import { HlmInputOtpImports } from '@egose/shadcn-theme-ng/input-otp';
|
|
200
|
+
|
|
201
|
+
@Component({
|
|
202
|
+
standalone: true,
|
|
203
|
+
imports: [BrnInputOtp, HlmInputOtpImports],
|
|
204
|
+
template: `
|
|
205
|
+
<brn-input-otp hlmInputOtp [length]="4" [value]="pin()" (valueChange)="pin.set($event)" inputId="pin">
|
|
206
|
+
<div hlmInputOtpGroup>
|
|
207
|
+
<hlm-input-otp-slot index="0" />
|
|
208
|
+
<hlm-input-otp-slot index="1" />
|
|
209
|
+
<hlm-input-otp-slot index="2" />
|
|
210
|
+
<hlm-input-otp-slot index="3" />
|
|
211
|
+
</div>
|
|
212
|
+
</brn-input-otp>
|
|
213
|
+
<div class="tw:flex tw:gap-2">
|
|
214
|
+
<button type="button" (click)="pin.set('')">Clear</button>
|
|
215
|
+
<button type="button" (click)="pin.set('1234')">Fill demo</button>
|
|
216
|
+
</div>
|
|
217
|
+
`,
|
|
218
|
+
})
|
|
219
|
+
export class ControlledExample {
|
|
220
|
+
readonly pin = signal('');
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 4. Different lengths: 4-digit PIN vs 8-char invite code
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
import { Component } from '@angular/core';
|
|
228
|
+
import { BrnInputOtp } from '@spartan-ng/brain/input-otp';
|
|
229
|
+
import { HlmInputOtpImports } from '@egose/shadcn-theme-ng/input-otp';
|
|
230
|
+
|
|
231
|
+
@Component({
|
|
232
|
+
standalone: true,
|
|
233
|
+
imports: [BrnInputOtp, HlmInputOtpImports],
|
|
234
|
+
template: `
|
|
235
|
+
<label for="pin">Card PIN (4 digits)</label>
|
|
236
|
+
<brn-input-otp hlmInputOtp [length]="4" inputId="pin" inputMode="numeric">
|
|
237
|
+
<div hlmInputOtpGroup>
|
|
238
|
+
<hlm-input-otp-slot index="0" />
|
|
239
|
+
<hlm-input-otp-slot index="1" />
|
|
240
|
+
<hlm-input-otp-slot index="2" />
|
|
241
|
+
<hlm-input-otp-slot index="3" />
|
|
242
|
+
</div>
|
|
243
|
+
</brn-input-otp>
|
|
244
|
+
|
|
245
|
+
<label for="invite">Invite code (8 characters, two groups of 4)</label>
|
|
246
|
+
<brn-input-otp hlmInputOtp [length]="8" inputId="invite" inputMode="text">
|
|
247
|
+
<div hlmInputOtpGroup>
|
|
248
|
+
<hlm-input-otp-slot index="0" />
|
|
249
|
+
<hlm-input-otp-slot index="1" />
|
|
250
|
+
<hlm-input-otp-slot index="2" />
|
|
251
|
+
<hlm-input-otp-slot index="3" />
|
|
252
|
+
</div>
|
|
253
|
+
<hlm-input-otp-separator />
|
|
254
|
+
<div hlmInputOtpGroup>
|
|
255
|
+
<hlm-input-otp-slot index="4" />
|
|
256
|
+
<hlm-input-otp-slot index="5" />
|
|
257
|
+
<hlm-input-otp-slot index="6" />
|
|
258
|
+
<hlm-input-otp-slot index="7" />
|
|
259
|
+
</div>
|
|
260
|
+
</brn-input-otp>
|
|
261
|
+
`,
|
|
262
|
+
})
|
|
263
|
+
export class LengthsExample {}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### 5. Disabled + error display with resend flow
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
import { Component, signal } from '@angular/core';
|
|
270
|
+
import { BrnInputOtp } from '@spartan-ng/brain/input-otp';
|
|
271
|
+
import { HlmInputOtpImports } from '@egose/shadcn-theme-ng/input-otp';
|
|
272
|
+
import { HlmError } from '@egose/shadcn-theme-ng/form-field';
|
|
273
|
+
|
|
274
|
+
@Component({
|
|
275
|
+
standalone: true,
|
|
276
|
+
imports: [BrnInputOtp, HlmInputOtpImports, HlmError],
|
|
277
|
+
template: `
|
|
278
|
+
<label for="otp-verify">Verification code</label>
|
|
279
|
+
<brn-input-otp
|
|
280
|
+
hlmInputOtp
|
|
281
|
+
[length]="6"
|
|
282
|
+
inputId="otp-verify"
|
|
283
|
+
inputMode="numeric"
|
|
284
|
+
inputAutocomplete="one-time-code"
|
|
285
|
+
[disabled]="verifying()"
|
|
286
|
+
[value]="code()"
|
|
287
|
+
(valueChange)="code.set($event); error.set(null)"
|
|
288
|
+
(completed)="verify()"
|
|
289
|
+
aria-describedby="otp-error"
|
|
290
|
+
>
|
|
291
|
+
<div hlmInputOtpGroup>
|
|
292
|
+
<hlm-input-otp-slot index="0" />
|
|
293
|
+
<hlm-input-otp-slot index="1" />
|
|
294
|
+
<hlm-input-otp-slot index="2" />
|
|
295
|
+
</div>
|
|
296
|
+
<hlm-input-otp-separator />
|
|
297
|
+
<div hlmInputOtpGroup>
|
|
298
|
+
<hlm-input-otp-slot index="3" />
|
|
299
|
+
<hlm-input-otp-slot index="4" />
|
|
300
|
+
<hlm-input-otp-slot index="5" />
|
|
301
|
+
</div>
|
|
302
|
+
</brn-input-otp>
|
|
303
|
+
@if (error()) {
|
|
304
|
+
<hlm-error id="otp-error">{{ error() }}</hlm-error>
|
|
305
|
+
}
|
|
306
|
+
<button type="button" (click)="resend()" [disabled]="verifying()">
|
|
307
|
+
{{ verifying() ? 'Verifying…' : 'Resend code' }}
|
|
308
|
+
</button>
|
|
309
|
+
`,
|
|
310
|
+
})
|
|
311
|
+
export class VerifyFlowExample {
|
|
312
|
+
readonly code = signal('');
|
|
313
|
+
readonly error = signal<string | null>(null);
|
|
314
|
+
readonly verifying = signal(false);
|
|
315
|
+
|
|
316
|
+
verify() {
|
|
317
|
+
this.verifying.set(true);
|
|
318
|
+
setTimeout(() => {
|
|
319
|
+
this.verifying.set(false);
|
|
320
|
+
if (this.code() !== '123456') {
|
|
321
|
+
this.error.set('That code is incorrect. Try again or resend.');
|
|
322
|
+
this.code.set('');
|
|
323
|
+
}
|
|
324
|
+
}, 900);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
resend() {
|
|
328
|
+
this.error.set(null);
|
|
329
|
+
this.code.set('');
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### 6. Paste normalization with `transformPaste`
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
import { Component } from '@angular/core';
|
|
338
|
+
import { BrnInputOtp } from '@spartan-ng/brain/input-otp';
|
|
339
|
+
import { HlmInputOtpImports } from '@egose/shadcn-theme-ng/input-otp';
|
|
340
|
+
|
|
341
|
+
@Component({
|
|
342
|
+
standalone: true,
|
|
343
|
+
imports: [BrnInputOtp, HlmInputOtpImports],
|
|
344
|
+
template: `
|
|
345
|
+
<label for="otp-paste">Code (pasting “12-34-56” works)</label>
|
|
346
|
+
<brn-input-otp hlmInputOtp [length]="6" inputId="otp-paste" [transformPaste]="stripSeparators">
|
|
347
|
+
<div hlmInputOtpGroup>
|
|
348
|
+
<hlm-input-otp-slot index="0" />
|
|
349
|
+
<hlm-input-otp-slot index="1" />
|
|
350
|
+
<hlm-input-otp-slot index="2" />
|
|
351
|
+
<hlm-input-otp-slot index="3" />
|
|
352
|
+
<hlm-input-otp-slot index="4" />
|
|
353
|
+
<hlm-input-otp-slot index="5" />
|
|
354
|
+
</div>
|
|
355
|
+
</brn-input-otp>
|
|
356
|
+
`,
|
|
357
|
+
})
|
|
358
|
+
export class PasteExample {
|
|
359
|
+
stripSeparators(pasted: string): string {
|
|
360
|
+
return pasted.replace(/[^0-9]/g, '').slice(0, 6);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## Accessibility notes
|
|
366
|
+
|
|
367
|
+
- Always render a visible `<label>` bound via `inputId` — the hidden native input is what AT focuses; without the label the purpose is unclear.
|
|
368
|
+
- `inputMode="numeric"` (digits) vs `text` (alphanumeric) selects the right mobile keyboard; `inputAutocomplete="one-time-code"` lets browsers/OS autofill SMS codes.
|
|
369
|
+
- Announce failures with a text error (`<hlm-error>` + `aria-describedby`), never by slot color alone.
|
|
370
|
+
- Keep `length` aligned with what the backend expects and validate `minLength(length)` on the form control so incomplete codes cannot submit.
|
|
371
|
+
|
|
372
|
+
## Theming / CSS variables
|
|
373
|
+
|
|
374
|
+
No component-specific CSS variables; slots use the shared `--input` / `--ring` / `--destructive` tokens. Slot size is fixed (`size-9`); adjust grouping/spacing with wrapper classes rather than per-slot overrides.
|
|
375
|
+
|
|
376
|
+
## Related subpaths
|
|
377
|
+
|
|
378
|
+
- `@egose/shadcn-theme-ng/input` — single-field `HlmInput` for non-OTP entry.
|
|
379
|
+
- `@egose/shadcn-theme-ng/form-field` — `HlmError`/`HlmHint` for code error text.
|
|
380
|
+
- `@egose/shadcn-theme-ng/button` — Verify/Resend actions.
|
|
381
|
+
- `@egose/shadcn-theme-ng/form-text-input` — labeled wrapper pattern to mirror for OTP forms.
|