@egose/shadcn-theme-ng-tw 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.
Files changed (86) hide show
  1. package/README.md +1 -1
  2. package/accordion/README.md +405 -2
  3. package/alert/README.md +372 -2
  4. package/alert-dialog/README.md +471 -5
  5. package/aspect-ratio/README.md +272 -5
  6. package/autocomplete/README.md +502 -2
  7. package/avatar/README.md +357 -5
  8. package/badge/README.md +318 -2
  9. package/basic-alert/README.md +353 -2
  10. package/breadcrumb/README.md +406 -5
  11. package/button/README.md +482 -2
  12. package/button/fesm2022/button.mjs +85 -107
  13. package/button/types/button.d.ts +5 -8
  14. package/button-group/README.md +318 -5
  15. package/button-group/fesm2022/button-group.mjs +1 -1
  16. package/calendar/README.md +357 -2
  17. package/card/README.md +331 -5
  18. package/carousel/README.md +333 -5
  19. package/carousel/fesm2022/carousel.mjs +4 -1
  20. package/checkbox/README.md +320 -2
  21. package/collapsible/README.md +332 -5
  22. package/combobox/README.md +507 -5
  23. package/combobox/fesm2022/combobox.mjs +4 -1
  24. package/command/README.md +435 -5
  25. package/confirmation-dialog/README.md +301 -2
  26. package/context-menu/README.md +366 -5
  27. package/date-picker/README.md +465 -2
  28. package/date-picker/fesm2022/date-picker.mjs +2 -2
  29. package/dialog/README.md +448 -2
  30. package/drawer/README.md +395 -5
  31. package/dropdown-menu/README.md +417 -5
  32. package/empty/README.md +329 -5
  33. package/field/README.md +385 -5
  34. package/form-checkbox/README.md +312 -2
  35. package/form-date-picker/README.md +322 -2
  36. package/form-field/README.md +356 -2
  37. package/form-field-simple/README.md +340 -2
  38. package/form-searchable-multiselect/README.md +361 -2
  39. package/form-select/README.md +350 -2
  40. package/form-text-input/README.md +371 -2
  41. package/form-textarea/README.md +347 -2
  42. package/hover-card/README.md +256 -5
  43. package/icon/README.md +239 -2
  44. package/input/README.md +269 -2
  45. package/input-group/README.md +335 -5
  46. package/input-group/fesm2022/input-group.mjs +3 -3
  47. package/input-otp/README.md +375 -5
  48. package/item/README.md +385 -5
  49. package/item/fesm2022/item.mjs +3 -3
  50. package/kbd/README.md +291 -5
  51. package/label/README.md +272 -2
  52. package/layout-simple/README.md +193 -2
  53. package/layout-simple/fesm2022/layout-simple.mjs +877 -409
  54. package/layout-simple/types/layout-simple.d.ts +174 -137
  55. package/menu/README.md +417 -2
  56. package/menubar/README.md +343 -5
  57. package/native-select/README.md +323 -5
  58. package/navigation-menu/README.md +369 -5
  59. package/package.json +1 -1
  60. package/pagination/README.md +388 -5
  61. package/popover/README.md +331 -2
  62. package/progress/README.md +311 -5
  63. package/radio-group/README.md +364 -2
  64. package/radio-group/fesm2022/radio-group.mjs +5 -1
  65. package/resizable/README.md +269 -5
  66. package/scroll-area/README.md +233 -5
  67. package/searchable-multiselect/README.md +323 -2
  68. package/select/README.md +437 -2
  69. package/separator/README.md +222 -2
  70. package/sheet/README.md +311 -2
  71. package/sidebar/README.md +457 -5
  72. package/skeleton/README.md +217 -5
  73. package/slider/README.md +273 -5
  74. package/slider/fesm2022/slider.mjs +17 -13
  75. package/sonner/README.md +346 -2
  76. package/spinner/README.md +284 -2
  77. package/switch/README.md +310 -2
  78. package/table/README.md +423 -5
  79. package/tabs/README.md +411 -2
  80. package/tabs/fesm2022/tabs.mjs +12 -2
  81. package/textarea/README.md +282 -5
  82. package/toggle/README.md +270 -5
  83. package/toggle-group/README.md +340 -5
  84. package/tooltip/README.md +269 -2
  85. package/typography/README.md +271 -5
  86. package/utils/README.md +303 -2
@@ -1,11 +1,381 @@
1
- # InputOtp
1
+ # Input OTP (`@egose/shadcn-theme-ng/input-otp`)
2
2
 
3
- This project was generated using [Angular CLI](https://github.com/angular/angular-cli).
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
- ## Building
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
- To build the library, run:
7
+ ## Installation
8
8
 
9
9
  ```bash
10
- ng build input-otp
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.