ng-hub-ui-forms 22.32.0 → 22.33.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 CHANGED
@@ -50,10 +50,11 @@ This library is part of the **ng-hub-ui** ecosystem:
50
50
  npm install ng-hub-ui-forms
51
51
  ```
52
52
 
53
- `@angular/cdk` is a peer dependency (used by the datepicker overlay and the select):
53
+ `ng-hub-ui-utils` is a peer dependency (the datepicker opens its panel through its overlay
54
+ service, and every field renders its tooltip helper text with `hubTooltip`):
54
55
 
55
56
  ```bash
56
- npm install @angular/cdk
57
+ npm install ng-hub-ui-utils
57
58
  ```
58
59
 
59
60
  ### 2. Import
@@ -86,15 +87,15 @@ bind them with **Reactive Forms** and the matching validation errors appear
86
87
  **automatically** at the control, group and form level. Fields are standalone,
87
88
  `OnPush` and signal-native; the select is a maintained fork of
88
89
  [ng-select](https://github.com/ng-select/ng-select) (see [Credits](#-credits)); the
89
- datepicker is built from scratch on native `Date` and the Angular CDK overlay.
90
+ datepicker is built from scratch on native `Date` and the `ng-hub-ui-utils` overlay.
90
91
  Everything is themed through canonical `--hub-*` CSS variables with runtime dark
91
92
  mode — no Bootstrap dependency.
92
93
 
93
94
  ## 🎯 Features
94
95
 
95
- - **Fields** — `hub-input` (text/number/email/password/color/switch/checkbox/counter, with input-group addons & masks, projected in-field affixes, a built-in `clearable` button, the mixed `indeterminate` state on checkboxes and debounced typeahead `search`; the `file` format is **deprecated** → use `hub-file-input`), `hub-otp-input`, `hub-textarea` (+ `hubAutoresize`), `hub-slider` (single / dual thumb, gradient fill), `hub-segmented` (segmented control field — single & multiple selection, horizontal & vertical, with label + validation), `hub-select` (dropdown format, grouping, client-side search via `searchable` **and** server-side async typeahead via a `typeahead` Subject, tag creation with `addTag`, custom templates, `prepend` / `append` group addons and attached icons/buttons via `hubPrepend` / `hubAppend`; the `buttons` / `checkbox` / `radio` formats are **deprecated** → use `hub-segmented`), `hub-datepicker` (single & range at any granularity from a year to a second, time picking, min/max down to the minute, keyboard nav, i18n), `hub-file-input` (drag & drop, clipboard paste, type/size limits, previews, optional upload progress).
96
- - **Automatic error display** — bind a field and its control errors render below it; `hub-fieldset`, `form[hubForm]` and `hub-legend` surface group- and form-level (cross-field) errors the same way, with zero wiring.
97
- - **Containers** — `hub-fieldset` / `form[hubForm]` group fields and show their group errors; `hub-legend` renders an accessible legend.
96
+ - **Fields** — `hub-input` (text/number/email/password/color/switch/checkbox/counter, with input-group addons & masks, projected in-field affixes, a built-in `clearable` button, the mixed `indeterminate` state on checkboxes and debounced typeahead `search`; the `file` format is **deprecated** → use `hub-file-input`), `hub-otp-input`, `hub-textarea` (+ `hubAutoresize`), `hub-slider` (single / dual thumb, gradient fill), `hub-segmented` (segmented control field — single & multiple selection, horizontal & vertical, with label + validation), `hub-select` (dropdown format, grouping, client-side search via `searchable` **and** server-side async typeahead via a `typeahead` Subject, tag creation with `addTag`, custom templates, `prepend` / `append` group addons and attached icons/buttons via `hubPrepend` / `hubAppend`; the `buttons` / `checkbox` / `radio` formats are **deprecated** → use `hub-segmented`), `hub-datepicker` (single & range at any granularity from a year to a second, time picking, min/max down to the minute, keyboard nav, i18n), `hub-timepicker` (a time of day as `HH:MM`, on the platform's own time control, with `min` / `max` / `step`), `hub-file-input` (drag & drop, clipboard paste, type/size limits, previews, optional upload progress).
97
+ - **Automatic error display** — bind a field and its control errors render below it; `fieldset[hubFieldset]`, `form[hubForm]` and `hub-legend` surface group- and form-level (cross-field) errors the same way, with zero wiring.
98
+ - **Containers** — `fieldset[hubFieldset]` (or the `<hub-fieldset>` element) / `form[hubForm]` group fields and show their group errors; `hub-legend` renders an accessible legend.
98
99
  - **Configurable** — `provideHubForms({ … })` sets the invalid-feedback templates, datepicker locale/labels, file-input labels and more, app-wide or per instance.
99
100
  - **Validators & helpers** — `hubAreEqual` cross-field validator, the file validators (`hubAcceptedFiles`, `hubMaxFileSize`, `hubMinFileSize`, `hubMaxTotalSize`, `hubMaxFiles`, `hubMinFiles`), `hubValidationError` / `hubFormText` projection directives, and a set of utility pipes.
100
101
  - **Signal Forms ready** — an opt-in [`ng-hub-ui-forms/signals`](#-signal-forms-opt-in) secondary entry point integrates Angular Signal Forms; the core stays Reactive-Forms-based and Angular-21-safe.
@@ -130,18 +131,18 @@ section.
130
131
  ## 📦 Installation
131
132
 
132
133
  ```bash
133
- npm install ng-hub-ui-forms @angular/cdk
134
+ npm install ng-hub-ui-forms ng-hub-ui-utils
134
135
  ```
135
136
 
136
137
  ### Peer Dependencies
137
138
 
138
139
  ```json
139
140
  {
140
- "@angular/cdk": ">=21.0.0",
141
141
  "@angular/common": ">=21.0.0",
142
142
  "@angular/core": ">=21.0.0",
143
143
  "@angular/forms": ">=21.0.0",
144
- "@angular/platform-browser": ">=21.0.0"
144
+ "@angular/platform-browser": ">=21.0.0",
145
+ "ng-hub-ui-utils": ">=22.12.0"
145
146
  }
146
147
  ```
147
148
 
@@ -188,7 +189,7 @@ string, so asking it to carry markup would drop the markup silently.
188
189
  ```html
189
190
  <hub-input formControlName="email" type="email" label="Email" required />
190
191
  <hub-input formControlName="amount" type="number" label="Amount" />
191
- <hub-input formControlName="darkMode" format="switch" label="Dark mode" />
192
+ <hub-input formControlName="darkMode" type="switch" label="Dark mode" />
192
193
  ```
193
194
 
194
195
  #### Icon affix & typeahead (search boxes)
@@ -476,6 +477,27 @@ Three independent axes control the formats:
476
477
  ISO strings of any width, `Date` instances and epoch milliseconds are detected automatically, so
477
478
  `parse` is only needed for dialects outside that set.
478
479
 
480
+ ### Timepicker
481
+
482
+ A time of day, as `HH:MM`. Built on the platform's `<input type="time">`, so it brings the
483
+ numeric keyboard on a phone, the stepper, and the reader's own 12- or 24-hour presentation —
484
+ while what the control holds is normalised to `HH:MM`, and so does not change with the locale.
485
+
486
+ ```html
487
+ <hub-timepicker formControlName="opensAt" label="Opens at" />
488
+ <hub-timepicker formControlName="closesAt" [step]="900" min="08:00" max="22:00" />
489
+ ```
490
+
491
+ | Input | Type | Default | What it does |
492
+ | ------ | ------------------ | ------- | --------------------------------------------------------------------------------------------------------------- |
493
+ | `min` | `string` (`HH:MM`) | `''` | Earliest time the field accepts. |
494
+ | `max` | `string` (`HH:MM`) | `''` | Latest time the field accepts. |
495
+ | `step` | `number` (seconds) | `0` | Granularity. `900` offers quarter hours; under `60` the control shows seconds, which an opening time never has. |
496
+
497
+ An empty field publishes `null`, not `''` — "no time" is an absence, and a zero-length string
498
+ sails past a `required` written as a null check. `label`, `labelType`, `readonly`, `prepend` /
499
+ `append` and the projected `hubPrepend` / `hubAppend` behave as on every other field.
500
+
479
501
  ### File input
480
502
 
481
503
  Drag & drop, clipboard paste, constraints and previews. The control value stays native — a `File`, a `File[]`, or `null` — so it goes straight into a `FormData`.
@@ -571,10 +593,10 @@ The dropzone is built from a glyph, an invitation and a browse action, each them
571
593
 
572
594
  ```html
573
595
  <form [formGroup]="form" hubForm (submit)="save()">
574
- <hub-fieldset legend="Credentials">
596
+ <fieldset hubFieldset legend="Credentials">
575
597
  <hub-input formControlName="email" type="email" label="Email" required />
576
598
  <hub-input formControlName="confirm" type="email" label="Confirm email" required />
577
- </hub-fieldset>
599
+ </fieldset>
578
600
  <button type="submit">Create account</button>
579
601
  </form>
580
602
  ```
@@ -589,6 +611,25 @@ form = new FormGroup(
589
611
  On submit, each invalid field shows its error and the cross-field `hubAreEqual`
590
612
  error is surfaced by the fieldset/form — no manual error markup anywhere.
591
613
 
614
+ #### Two ways to write the fieldset
615
+
616
+ `hubFieldset` is an attribute on the native element, so the group costs one element instead of
617
+ two: the `<fieldset hubFieldset>` you write **is** the fieldset the browser sees. The
618
+ `<hub-fieldset>` element form is still supported and takes the same inputs, but it has to render
619
+ a `<fieldset>` of its own inside the host. Prefer the attribute — it is the markup a plain HTML
620
+ form would have written anyway.
621
+
622
+ ```html
623
+ <!-- preferred: the host is the fieldset -->
624
+ <fieldset hubFieldset legend="Credentials" [group]="form.controls.credentials">…</fieldset>
625
+
626
+ <!-- equivalent, one element deeper -->
627
+ <hub-fieldset legend="Credentials" [group]="form.controls.credentials">…</hub-fieldset>
628
+ ```
629
+
630
+ The attribute is restricted to `<fieldset>` on purpose: on a `<div>` it would draw a legend over
631
+ a group with none of the semantics assistive technology reads from a real fieldset.
632
+
592
633
  ### Validation states (invalid is automatic, valid is opt-in)
593
634
 
594
635
  The **invalid** state is always automatic: a touched, invalid field shows its
@@ -637,7 +678,7 @@ Everything is themed through `--hub-*` CSS custom properties. The package ships
637
678
  shared SCSS tokens; import them once at the app root:
638
679
 
639
680
  ```scss
640
- @use 'ng-hub-ui-forms/src/lib/styles/index' as hub-forms;
681
+ @use 'ng-hub-ui-forms/styles' as hub-forms;
641
682
  ```
642
683
 
643
684
  ```css
@@ -707,7 +748,7 @@ import { HubSignalFieldControl, hubSignalErrorMessages } from 'ng-hub-ui-forms/s
707
748
  ## ♿ Accessibility
708
749
 
709
750
  - Labels are associated with their control (`for`/`id`); required fields are marked.
710
- - `required` — set inline or derived from `Validators.required`, with `formControlName` **or** a direct `[formControl]` binding — is reflected as `aria-required` on every field, including the select's combobox search input, the segmented `radiogroup` and each OTP cell.
751
+ - `required` — set inline or derived from `Validators.required`, with `formControlName` **or** a direct `[formControl]` binding — is reflected as `aria-required` on every field, including the select's combobox search input, the segmented `radiogroup` and each OTP cell. On a reactive binding the control's validators decide: an inline `required` is overwritten by them, so declare it on the validators. Template-driven bindings (`ngModel`) keep honouring the inline input.
711
752
  - Validation errors render in an `role="alert"` region tied to the field.
712
753
  - The select exposes correct combobox/listbox semantics; the datepicker is fully keyboard-navigable.
713
754