@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,3 +1,313 @@
1
- # Form Checkbox Subpath
1
+ # Form Checkbox (`@egose/shadcn-theme-ng/form-checkbox`)
2
2
 
3
- This project ships only as `@egose/shadcn-theme-ng/form-checkbox` or `@egose/shadcn-theme-ng-tw/form-checkbox`. See the [package README](../../README.md) for installation, compatibility, Tailwind variant, test, and release guidance. Do not publish this project directory independently.
3
+ A ready-made reactive-form checkbox row: `hlm-checkbox` + label + required marker with automatic `hlm-error` / `hlm-hint` display, wrapped in `eg-form-field` error switching. Equivalent to shadcn/ui `Form` + `Checkbox` composition.
4
+
5
+ The Angular implementation is a standalone `ControlValueAccessor`-compatible wrapper (not a brain
6
+ primitive itself): it renders `HlmCheckbox` bound with `formControlName`, `HlmLabel`, `EgFormField`
7
+ from `@egose/shadcn-theme-ng/form-field-simple`, and `HlmError` / `HlmHint` from
8
+ `@egose/shadcn-theme-ng/form-field`. It must live inside a `FormGroupDirective` (a
9
+ `[formGroup]` parent) and forwards `ControlContainer` to it. Ids are generated by
10
+ `HlmFormIdGenerator` unless overridden.
11
+
12
+ > **Ships as:** `@egose/shadcn-theme-ng/form-checkbox` and `@egose/shadcn-theme-ng-tw/form-checkbox`
13
+ > (the `tw:`-prefixed Tailwind variant). Both expose the identical TypeScript surface; only the
14
+ > emitted Tailwind class strings differ. See the [package README](../../README.md) for install
15
+ > steps, peer dependencies, and Tailwind setup. Do not publish this project directory independently.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # Plain Tailwind (no prefix)
21
+ npm install @egose/shadcn-theme-ng
22
+
23
+ # tw:-prefixed Tailwind variant
24
+ npm install @egose/shadcn-theme-ng-tw
25
+ ```
26
+
27
+ Peer dependencies (Angular, `@spartan-ng/brain`, `@ng-icons/*`, `rxjs`, …) are documented in the
28
+ [package README](../../README.md#peer-dependencies). This subpath additionally relies at runtime on
29
+ `@egose/shadcn-theme-ng/checkbox`, `@egose/shadcn-theme-ng/label`,
30
+ `@egose/shadcn-theme-ng/form-field`, and `@egose/shadcn-theme-ng/form-field-simple`.
31
+
32
+ ## Imports
33
+
34
+ Exported from the subpath root (`projects/form-checkbox/src/public-api.ts`). Note: this subpath
35
+ exports a single standalone component — there is no `*Imports` array or `*Module`:
36
+
37
+ ```ts
38
+ import { EgFormCheckbox } from '@egose/shadcn-theme-ng/form-checkbox';
39
+ // tw variant: replace with '@egose/shadcn-theme-ng-tw/form-checkbox'
40
+ ```
41
+
42
+ Standalone usage:
43
+
44
+ ```ts
45
+ import { Component } from '@angular/core';
46
+ import { ReactiveFormsModule } from '@angular/forms';
47
+ import { EgFormCheckbox } from '@egose/shadcn-theme-ng/form-checkbox';
48
+
49
+ @Component({
50
+ selector: 'app-demo',
51
+ standalone: true,
52
+ imports: [ReactiveFormsModule, EgFormCheckbox],
53
+ template: `...`,
54
+ })
55
+ export class DemoComponent {}
56
+ ```
57
+
58
+ NgModule-based consumer: add `EgFormCheckbox` (and `ReactiveFormsModule`) to the module's `imports`
59
+ — it is a standalone component, not a module.
60
+
61
+ `ControlValueAccessor` behavior: `eg-form-checkbox` itself is not a `ControlValueAccessor`; the
62
+ inner `hlm-checkbox` is bound via `[formControlName]="controlName()"`, so the parent `FormGroup`
63
+ owns the value. `checked()` sets the initial checkbox input; the form control is the source of
64
+ truth afterwards.
65
+
66
+ ## Anatomy / Structure
67
+
68
+ ```html
69
+ <form [formGroup]="form">
70
+ <eg-form-checkbox
71
+ controlName="acceptTerms"
72
+ label="Accept terms and conditions"
73
+ [required]="true"
74
+ hint="You must accept to continue."
75
+ error="You must accept the terms."
76
+ />
77
+ </form>
78
+ ```
79
+
80
+ Selector (from source): `eg-form-checkbox` (standalone component).
81
+
82
+ ## API reference
83
+
84
+ ### `EgFormCheckbox` — `eg-form-checkbox`
85
+
86
+ | Input | Type | Default | Description |
87
+ | --------------- | --------------------- | ------- | ------------------------------------------------------------------------------------------- |
88
+ | `controlName` | `string` | `''` | `formControlName` key inside the parent `FormGroup`. **Required.** |
89
+ | `label` | `string` | `''` | Label text next to the checkbox. |
90
+ | `error` | `string \| undefined` | — | Error text shown when the control is invalid + touched/dirty (via `EgFormField` switching). |
91
+ | `hint` | `string \| undefined` | — | Hint text shown when there is no error to display. |
92
+ | `controlId` | `string \| undefined` | — | Explicit control id (first priority for `effectiveId`). |
93
+ | `id` | `string \| undefined` | — | Fallback id (second priority). |
94
+ | `name` | `string \| undefined` | — | Checkbox `name` attribute (defaults to `controlName`). |
95
+ | `checked` | `boolean` | `false` | Initial checked state passed to `hlm-checkbox`. |
96
+ | `required` | `boolean` | `false` | Shows a red `*` and sets checkbox `required`. |
97
+ | `disabled` | `boolean` | `false` | Locks interaction via checkbox `wrapperDisabled` (does not write to the form control). |
98
+ | `class` | `ClassValue` | `''` | Extra host classes. |
99
+ | `checkboxClass` | `string` | `''` | Extra classes for `hlm-checkbox`. |
100
+ | `labelClass` | `string` | `''` | Extra classes for the label. |
101
+ | `$errorClass` | `string` | `''` | Extra classes for `hlm-error`. (Note the `$` prefix — part of the real input name.) |
102
+ | `$hintClass` | `string` | `''` | Extra classes for `hlm-hint`. (Note the `$` prefix.) |
103
+
104
+ | Member | Description |
105
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
106
+ | `effectiveId` | `controlId() \|\| id() \|\| generated` — wired to checkbox `id` and label `for`. |
107
+ | `errorId` / `hintId` | `effectiveId + '-error' / '-hint'` for `aria-describedby`. |
108
+ | `describedBy()` | Returns `errorId` when `error()` is set and the control is invalid + dirty/touched, else `hintId` when `hint()` is set, else `null`. |
109
+
110
+ Requires a `[formGroup]` ancestor: the component injects `FormGroupDirective` and provides
111
+ `ControlContainer → FormGroupDirective` so `formControlName` resolves.
112
+
113
+ ## Examples
114
+
115
+ ### 1. Basic required terms checkbox
116
+
117
+ ```ts
118
+ import { Component, inject } from '@angular/core';
119
+ import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
120
+ import { EgFormCheckbox } from '@egose/shadcn-theme-ng/form-checkbox';
121
+
122
+ @Component({
123
+ selector: 'app-terms',
124
+ standalone: true,
125
+ imports: [ReactiveFormsModule, EgFormCheckbox],
126
+ template: `
127
+ <form [formGroup]="form" (ngSubmit)="submit()">
128
+ <eg-form-checkbox
129
+ controlName="accept"
130
+ label="Accept terms and conditions"
131
+ [required]="true"
132
+ error="You must accept the terms."
133
+ />
134
+ <button type="submit" [disabled]="form.invalid">Continue</button>
135
+ </form>
136
+ `,
137
+ })
138
+ export class TermsComponent {
139
+ private readonly fb = inject(FormBuilder);
140
+ readonly form = this.fb.group({ accept: [false, Validators.requiredTrue] });
141
+ submit() {
142
+ console.log(this.form.value);
143
+ }
144
+ }
145
+ ```
146
+
147
+ ### 2. Hint + validation error display
148
+
149
+ ```ts
150
+ import { Component, inject } from '@angular/core';
151
+ import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
152
+ import { EgFormCheckbox } from '@egose/shadcn-theme-ng/form-checkbox';
153
+
154
+ @Component({
155
+ selector: 'app-newsletter',
156
+ standalone: true,
157
+ imports: [ReactiveFormsModule, EgFormCheckbox],
158
+ template: `
159
+ <form [formGroup]="form">
160
+ <eg-form-checkbox
161
+ controlName="newsletter"
162
+ label="Email me news and offers"
163
+ hint="One email per month, unsubscribe anytime."
164
+ error="Please confirm your preference."
165
+ />
166
+ </form>
167
+ <p class="tw:text-sm">Value: {{ form.value.newsletter }}</p>
168
+ `,
169
+ })
170
+ export class NewsletterComponent {
171
+ private readonly fb = inject(FormBuilder);
172
+ readonly form = this.fb.group({ newsletter: [true, Validators.requiredTrue] });
173
+ }
174
+ ```
175
+
176
+ ### 3. Disabled / locked checkbox
177
+
178
+ ```ts
179
+ import { Component, inject } from '@angular/core';
180
+ import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
181
+ import { EgFormCheckbox } from '@egose/shadcn-theme-ng/form-checkbox';
182
+
183
+ @Component({
184
+ selector: 'app-locked',
185
+ standalone: true,
186
+ imports: [ReactiveFormsModule, EgFormCheckbox],
187
+ template: `
188
+ <form [formGroup]="form">
189
+ <eg-form-checkbox
190
+ controlName="readonly"
191
+ label="Two-factor authentication (enforced)"
192
+ [checked]="true"
193
+ [disabled]="true"
194
+ hint="Managed by your organization."
195
+ />
196
+ </form>
197
+ `,
198
+ })
199
+ export class LockedComponent {
200
+ private readonly fb = inject(FormBuilder);
201
+ readonly form = this.fb.group({ readonly: [true] });
202
+ }
203
+ ```
204
+
205
+ > `disabled` locks the UI via `wrapperDisabled` without disabling the form control itself, so the
206
+ > value still submits. To exclude the value, call `form.get('readonly')?.disable()` instead.
207
+
208
+ ### 4. Custom ids + styling hooks
209
+
210
+ ```ts
211
+ import { Component, inject } from '@angular/core';
212
+ import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
213
+ import { EgFormCheckbox } from '@egose/shadcn-theme-ng/form-checkbox';
214
+
215
+ @Component({
216
+ selector: 'app-styled-check',
217
+ standalone: true,
218
+ imports: [ReactiveFormsModule, EgFormCheckbox],
219
+ template: `
220
+ <form [formGroup]="form">
221
+ <eg-form-checkbox
222
+ controlName="marketing"
223
+ controlId="marketing-opt-in"
224
+ label="Send me product updates"
225
+ checkboxClass="tw:border-primary"
226
+ labelClass="tw:font-medium"
227
+ class="tw:rounded-md tw:border tw:p-3"
228
+ />
229
+ </form>
230
+ `,
231
+ })
232
+ export class StyledCheckComponent {
233
+ private readonly fb = inject(FormBuilder);
234
+ readonly form = this.fb.group({ marketing: [false] });
235
+ }
236
+ ```
237
+
238
+ ### 5. Settings list (multiple checkboxes, one group)
239
+
240
+ ```ts
241
+ import { Component, inject } from '@angular/core';
242
+ import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
243
+ import { EgFormCheckbox } from '@egose/shadcn-theme-ng/form-checkbox';
244
+
245
+ @Component({
246
+ selector: 'app-settings',
247
+ standalone: true,
248
+ imports: [ReactiveFormsModule, EgFormCheckbox],
249
+ template: `
250
+ <form [formGroup]="form" class="tw:grid tw:gap-3">
251
+ <eg-form-checkbox controlName="email" label="Email notifications" />
252
+ <eg-form-checkbox controlName="sms" label="SMS notifications" hint="Carrier rates may apply." />
253
+ <eg-form-checkbox controlName="push" label="Push notifications" />
254
+ </form>
255
+ <pre class="tw:text-xs">{{ form.value | json }}</pre>
256
+ `,
257
+ })
258
+ export class SettingsComponent {
259
+ private readonly fb = inject(FormBuilder);
260
+ readonly form = this.fb.group({ email: [true], sms: [false], push: [true] });
261
+ }
262
+ ```
263
+
264
+ ### 6. Submitted-state validation (mark all touched)
265
+
266
+ ```ts
267
+ import { Component, inject } from '@angular/core';
268
+ import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
269
+ import { EgFormCheckbox } from '@egose/shadcn-theme-ng/form-checkbox';
270
+
271
+ @Component({
272
+ selector: 'app-submit-check',
273
+ standalone: true,
274
+ imports: [ReactiveFormsModule, EgFormCheckbox],
275
+ template: `
276
+ <form [formGroup]="form" (ngSubmit)="submit()">
277
+ <eg-form-checkbox
278
+ controlName="consent"
279
+ label="I consent to data processing"
280
+ [required]="true"
281
+ error="Consent is required to create your account."
282
+ />
283
+ <button type="submit">Create account</button>
284
+ </form>
285
+ `,
286
+ })
287
+ export class SubmitCheckComponent {
288
+ private readonly fb = inject(FormBuilder);
289
+ readonly form = this.fb.group({ consent: [false, Validators.requiredTrue] });
290
+ submit() {
291
+ this.form.markAllAsTouched();
292
+ if (this.form.valid) console.log('creating account…');
293
+ }
294
+ }
295
+ ```
296
+
297
+ ## Accessibility notes
298
+
299
+ - The checkbox `id` and label `for` are generated (`eg-form-checkbox-<app>-<n>`) unless `controlId`/`id` is given — labels are always programmatically associated.
300
+ - `aria-describedby` points at the error id only while the control is invalid + touched/dirty, otherwise at the hint id — screen readers hear the right message in each state.
301
+ - The required marker (`*`) is visual; the underlying `hlm-checkbox` also receives `required` so assistive tech announces it.
302
+ - Keep the component inside a `<form>` with a submit path; the row itself is a single tab stop (the checkbox).
303
+
304
+ ## Theming / CSS variables
305
+
306
+ No component-specific CSS variables. Style via `class`, `checkboxClass`, `labelClass`, `$errorClass`, `$hintClass` inputs and global tokens. The row layout (`flex items-center gap-1`) is fixed in the template.
307
+
308
+ ## Related subpaths
309
+
310
+ - `@egose/shadcn-theme-ng/checkbox` — standalone `hlm-checkbox` when you need a custom layout.
311
+ - `@egose/shadcn-theme-ng/form-field-simple` — `eg-form-field` error/hint switching used internally.
312
+ - `@egose/shadcn-theme-ng/form-field` — `hlm-form-field` / `hlm-error` / `hlm-hint` primitives.
313
+ - `@egose/shadcn-theme-ng/label` — `HlmLabel` used for the row label.
@@ -1,3 +1,323 @@
1
- # Form Date Picker Subpath
1
+ # Form Date Picker (`@egose/shadcn-theme-ng/form-date-picker`)
2
2
 
3
- This project ships only as `@egose/shadcn-theme-ng/form-date-picker` or `@egose/shadcn-theme-ng-tw/form-date-picker`. See the [package README](../../README.md) for installation, compatibility, Tailwind variant, test, and release guidance. Do not publish this project directory independently.
3
+ A ready-made reactive-form date field: label + `hlm-date-picker` + validation error/hint display in one tag. Equivalent to shadcn/ui `Form` + date-picker composition.
4
+
5
+ The Angular implementation is a standalone wrapper (not a brain primitive): it renders
6
+ `HlmFormField` / `HlmError` / `HlmHint` from `@egose/shadcn-theme-ng/form-field`, `HlmLabel`, and
7
+ `HlmDatePicker` + `HlmDatePickerInput` from `@egose/shadcn-theme-ng/date-picker`. The inner
8
+ `hlm-date-picker` is bound with `[formControlName]="controlName()"`, so the parent `FormGroup`
9
+ owns the `Date | null` value. It must live inside a `FormGroupDirective` (`[formGroup]` parent);
10
+ ids come from `HlmFormIdGenerator` unless overridden.
11
+
12
+ > **Ships as:** `@egose/shadcn-theme-ng/form-date-picker` and `@egose/shadcn-theme-ng-tw/form-date-picker`
13
+ > (the `tw:`-prefixed Tailwind variant). Both expose the identical TypeScript surface; only the
14
+ > emitted Tailwind class strings differ. See the [package README](../../README.md) for install
15
+ > steps, peer dependencies, and Tailwind setup. Do not publish this project directory independently.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # Plain Tailwind (no prefix)
21
+ npm install @egose/shadcn-theme-ng
22
+
23
+ # tw:-prefixed Tailwind variant
24
+ npm install @egose/shadcn-theme-ng-tw
25
+ ```
26
+
27
+ Peer dependencies (Angular, `@spartan-ng/brain`, `@ng-icons/*`, `rxjs`, …) are documented in the
28
+ [package README](../../README.md#peer-dependencies). This subpath additionally relies at runtime on
29
+ `@egose/shadcn-theme-ng/date-picker`, `@egose/shadcn-theme-ng/form-field`, and
30
+ `@egose/shadcn-theme-ng/label`.
31
+
32
+ ## Imports
33
+
34
+ Exported from the subpath root (`projects/form-date-picker/src/public-api.ts`). Note: this subpath
35
+ exports a single standalone component — there is no `*Imports` array or `*Module`:
36
+
37
+ ```ts
38
+ import { EgFormDatePicker } from '@egose/shadcn-theme-ng/form-date-picker';
39
+ // tw variant: replace with '@egose/shadcn-theme-ng-tw/form-date-picker'
40
+ ```
41
+
42
+ Standalone usage:
43
+
44
+ ```ts
45
+ import { Component } from '@angular/core';
46
+ import { ReactiveFormsModule } from '@angular/forms';
47
+ import { EgFormDatePicker } from '@egose/shadcn-theme-ng/form-date-picker';
48
+
49
+ @Component({
50
+ selector: 'app-demo',
51
+ standalone: true,
52
+ imports: [ReactiveFormsModule, EgFormDatePicker],
53
+ template: `...`,
54
+ })
55
+ export class DemoComponent {}
56
+ ```
57
+
58
+ NgModule-based consumer: add `EgFormDatePicker` (and `ReactiveFormsModule`) to the module's
59
+ `imports` — it is a standalone component, not a module.
60
+
61
+ `ControlValueAccessor` behavior: `eg-form-date-picker` itself is not a `ControlValueAccessor`; the
62
+ inner `hlm-date-picker` is (bound via `formControlName`), so `formControlName`/`formGroup` handling,
63
+ `Validators`, `disabled` state from the control, and `dateChange` values (`Date | null`) all flow
64
+ through the parent form.
65
+
66
+ ## Anatomy / Structure
67
+
68
+ ```html
69
+ <form [formGroup]="form">
70
+ <eg-form-date-picker
71
+ controlName="birthday"
72
+ label="Date of birth"
73
+ placeholder="Pick a date"
74
+ [required]="true"
75
+ hint="We use this to verify your age."
76
+ error="Birth date is required."
77
+ />
78
+ </form>
79
+ ```
80
+
81
+ Selector (from source): `eg-form-date-picker` (standalone component, host `tw:w-full`).
82
+
83
+ ## API reference
84
+
85
+ ### `EgFormDatePicker` — `eg-form-date-picker`
86
+
87
+ | Input | Type | Default | Description |
88
+ | ------------------- | ------------------------ | --------------- | ----------------------------------------------------------------------------------------------------------- |
89
+ | `controlName` | `string` | `''` | `formControlName` key inside the parent `FormGroup`. **Required.** |
90
+ | `label` | `string \| undefined` | — | Label text (hidden when omitted). |
91
+ | `error` | `string \| undefined` | — | Error text shown when invalid. |
92
+ | `hint` | `string \| undefined` | — | Hint text shown otherwise. |
93
+ | `controlId` | `string \| undefined` | — | Explicit id (first priority for `effectiveId`). |
94
+ | `id` | `string \| undefined` | — | Fallback id (second priority). |
95
+ | `name` | `string \| undefined` | — | Declared input; **not bound** to the inner picker in the current template (surprise — see below). |
96
+ | `placeholder` | `string` | `'Pick a date'` | Input placeholder. |
97
+ | `readonly` | `boolean` | `false` | Declared input; **not bound** in the current template. |
98
+ | `disabled` | `boolean` | `false` | Locks interaction via picker `wrapperDisabled` (form control stays enabled). |
99
+ | `required` | `boolean` | `false` | Shows a red `*` next to the label. |
100
+ | `min` | `Date \| string \| null` | `null` | Minimum date forwarded to `hlm-date-picker`. |
101
+ | `max` | `Date \| string \| null` | `null` | Maximum date forwarded to `hlm-date-picker`. |
102
+ | `autoCloseOnSelect` | `boolean` | `true` | Declared input; **not bound** to the inner picker in the current template (picker default `false` applies). |
103
+ | `class` | `ClassValue` | `''` | Declared but **not applied** to the host in the current template (host is fixed `tw:w-full`). |
104
+ | `labelClass` | `string` | `''` | Extra label classes (base `tw:mb-1`). |
105
+ | `pickerClass` | `string` | `''` | Extra picker classes (base `tw:mb-1`). |
106
+ | `errorClass` | `string` | `''` | Extra error classes (base `tw:mt-0`). |
107
+ | `hintClass` | `string` | `''` | Extra hint classes (base `tw:mt-0`). |
108
+
109
+ | Member | Description |
110
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
111
+ | `effectiveId` | `controlId() \|\| id() \|\| generated` — wired to input `inputId` and label `for`. |
112
+ | `errorId` / `hintId` | `effectiveId + '-error' / '-hint'`. |
113
+ | `describedBy()` | `errorId` when `error()` is set and control is invalid + dirty/touched, else `hintId` when `hint()` is set, else `null` — wired to input `ariaDescribedby`. |
114
+
115
+ Requires a `[formGroup]` ancestor (injects `FormGroupDirective`, provides `ControlContainer → FormGroupDirective`).
116
+
117
+ ## Examples
118
+
119
+ ### 1. Basic required date field
120
+
121
+ ```ts
122
+ import { Component, inject } from '@angular/core';
123
+ import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
124
+ import { EgFormDatePicker } from '@egose/shadcn-theme-ng/form-date-picker';
125
+
126
+ @Component({
127
+ selector: 'app-birthday',
128
+ standalone: true,
129
+ imports: [ReactiveFormsModule, EgFormDatePicker],
130
+ template: `
131
+ <form [formGroup]="form" (ngSubmit)="submit()">
132
+ <eg-form-date-picker
133
+ controlName="birthday"
134
+ label="Date of birth"
135
+ [required]="true"
136
+ error="Birth date is required."
137
+ />
138
+ <button type="submit" [disabled]="form.invalid">Continue</button>
139
+ </form>
140
+ `,
141
+ })
142
+ export class BirthdayComponent {
143
+ private readonly fb = inject(FormBuilder);
144
+ readonly form = this.fb.group({ birthday: [null as Date | null, Validators.required] });
145
+ submit() {
146
+ console.log(this.form.value.birthday);
147
+ }
148
+ }
149
+ ```
150
+
151
+ ### 2. Hint + min/max bounds
152
+
153
+ ```ts
154
+ import { Component, inject } from '@angular/core';
155
+ import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
156
+ import { EgFormDatePicker } from '@egose/shadcn-theme-ng/form-date-picker';
157
+
158
+ @Component({
159
+ selector: 'app-bounds',
160
+ standalone: true,
161
+ imports: [ReactiveFormsModule, EgFormDatePicker],
162
+ template: `
163
+ <form [formGroup]="form">
164
+ <eg-form-date-picker
165
+ controlName="departure"
166
+ label="Departure"
167
+ placeholder="Select departure"
168
+ [min]="today"
169
+ [max]="nextYear"
170
+ hint="Bookings open up to one year ahead."
171
+ error="Pick a valid departure date."
172
+ />
173
+ </form>
174
+ `,
175
+ })
176
+ export class BoundsComponent {
177
+ private readonly fb = inject(FormBuilder);
178
+ readonly form = this.fb.group({ departure: [null as Date | null] });
179
+ readonly today = new Date();
180
+ readonly nextYear = new Date(new Date().getFullYear() + 1, 11, 31);
181
+ }
182
+ ```
183
+
184
+ ### 3. Booking range (two fields, cross-validation)
185
+
186
+ ```ts
187
+ import { Component, inject } from '@angular/core';
188
+ import { FormBuilder, ReactiveFormsModule, Validators, AbstractControl } from '@angular/forms';
189
+ import { EgFormDatePicker } from '@egose/shadcn-theme-ng/form-date-picker';
190
+
191
+ @Component({
192
+ selector: 'app-booking',
193
+ standalone: true,
194
+ imports: [ReactiveFormsModule, EgFormDatePicker],
195
+ template: `
196
+ <form [formGroup]="form" class="tw:grid tw:gap-4">
197
+ <eg-form-date-picker controlName="checkIn" label="Check-in" [required]="true" error="Check-in is required." />
198
+ <eg-form-date-picker
199
+ controlName="checkOut"
200
+ label="Check-out"
201
+ [required]="true"
202
+ [min]="form.value.checkIn"
203
+ error="Check-out must be after check-in."
204
+ />
205
+ </form>
206
+ `,
207
+ })
208
+ export class BookingComponent {
209
+ private readonly fb = inject(FormBuilder);
210
+ readonly form = this.fb.group(
211
+ { checkIn: [null as Date | null, Validators.required], checkOut: [null as Date | null, Validators.required] },
212
+ {
213
+ validators: (g: AbstractControl) =>
214
+ (g.get('checkOut')?.value ?? 0) >= (g.get('checkIn')?.value ?? 0) ? null : { order: true },
215
+ },
216
+ );
217
+ }
218
+ ```
219
+
220
+ ### 4. Disabled / read-only preview
221
+
222
+ ```ts
223
+ import { Component, inject } from '@angular/core';
224
+ import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
225
+ import { EgFormDatePicker } from '@egose/shadcn-theme-ng/form-date-picker';
226
+
227
+ @Component({
228
+ selector: 'app-locked-date',
229
+ standalone: true,
230
+ imports: [ReactiveFormsModule, EgFormDatePicker],
231
+ template: `
232
+ <form [formGroup]="form">
233
+ <eg-form-date-picker
234
+ controlName="founded"
235
+ label="Founded"
236
+ [disabled]="true"
237
+ hint="Managed by workspace admins."
238
+ />
239
+ </form>
240
+ `,
241
+ })
242
+ export class LockedDateComponent {
243
+ private readonly fb = inject(FormBuilder);
244
+ readonly form = this.fb.group({ founded: [new Date(2020, 0, 15)] });
245
+ }
246
+ ```
247
+
248
+ ### 5. Submit-gated validation + value preview
249
+
250
+ ```ts
251
+ import { Component, inject } from '@angular/core';
252
+ import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
253
+ import { EgFormDatePicker } from '@egose/shadcn-theme-ng/form-date-picker';
254
+
255
+ @Component({
256
+ selector: 'app-submit-date',
257
+ standalone: true,
258
+ imports: [ReactiveFormsModule, EgFormDatePicker],
259
+ template: `
260
+ <form [formGroup]="form" (ngSubmit)="submit()">
261
+ <eg-form-date-picker controlName="start" label="Start date" [required]="true" error="Start date is required." />
262
+ <button type="submit">Save</button>
263
+ </form>
264
+ <p class="tw:text-sm">ISO: {{ form.value.start?.toISOString() ?? '—' }}</p>
265
+ `,
266
+ })
267
+ export class SubmitDateComponent {
268
+ private readonly fb = inject(FormBuilder);
269
+ readonly form = this.fb.group({ start: [null as Date | null, Validators.required] });
270
+ submit() {
271
+ this.form.markAllAsTouched();
272
+ if (this.form.valid) console.log('saving', this.form.value.start);
273
+ }
274
+ }
275
+ ```
276
+
277
+ ### 6. Custom label/picker styling
278
+
279
+ ```ts
280
+ import { Component, inject } from '@angular/core';
281
+ import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
282
+ import { EgFormDatePicker } from '@egose/shadcn-theme-ng/form-date-picker';
283
+
284
+ @Component({
285
+ selector: 'app-styled-date',
286
+ standalone: true,
287
+ imports: [ReactiveFormsModule, EgFormDatePicker],
288
+ template: `
289
+ <form [formGroup]="form">
290
+ <eg-form-date-picker
291
+ controlName="event"
292
+ controlId="event-date"
293
+ label="Event date"
294
+ labelClass="tw:font-semibold"
295
+ pickerClass="tw:max-w-xs"
296
+ hint="Doors open one hour earlier."
297
+ />
298
+ </form>
299
+ `,
300
+ })
301
+ export class StyledDateComponent {
302
+ private readonly fb = inject(FormBuilder);
303
+ readonly form = this.fb.group({ event: [null as Date | null] });
304
+ }
305
+ ```
306
+
307
+ ## Accessibility notes
308
+
309
+ - Label `for` ↔ input `inputId` wiring is automatic via `effectiveId`; the input also receives `ariaLabel` (the label text) and `ariaDescribedby` (error/hint id) — always pass a `label`.
310
+ - Closing the picker popover marks the control touched, so errors appear after interaction even without typing.
311
+ - The required `*` is visual; pair with `Validators.required` so assistive tech and validation agree.
312
+ - Arrow-down opens the calendar from the input; the calendar/popup primitives handle focus trap, escape, and outside-click dismissal.
313
+
314
+ ## Theming / CSS variables
315
+
316
+ No component-specific CSS variables. Style via `labelClass` / `pickerClass` / `errorClass` / `hintClass` and global tokens. The host is fixed `tw:w-full`; constrain width with a wrapping container.
317
+
318
+ ## Related subpaths
319
+
320
+ - `@egose/shadcn-theme-ng/date-picker` — raw `hlm-date-picker` + input/trigger/config tokens for custom layouts.
321
+ - `@egose/shadcn-theme-ng/form-field` — `hlm-form-field` / `hlm-error` / `hlm-hint` used internally.
322
+ - `@egose/shadcn-theme-ng/calendar` — calendars rendered inside the picker popover.
323
+ - `@egose/shadcn-theme-ng/form-field-simple` — alternative minimal wrapper when you compose pickers by hand.