ng-hub-ui-forms 22.28.0 → 22.30.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
@@ -116,7 +116,7 @@ import { provideHubPaginableFormControls } from 'ng-hub-ui-paginable';
116
116
  import { hubFormControlAdapter } from 'ng-hub-ui-forms';
117
117
 
118
118
  export const appConfig: ApplicationConfig = {
119
- providers: [provideHubPaginableFormControls(hubFormControlAdapter)]
119
+ providers: [provideHubPaginableFormControls(hubFormControlAdapter)]
120
120
  };
121
121
  ```
122
122
 
@@ -163,12 +163,7 @@ Project a leading / trailing icon **inside** the field, emit a debounced term on
163
163
 
164
164
  ```html
165
165
  <!-- Project any icon (any pack via the shorthand) + debounced search + built-in clear -->
166
- <hub-input
167
- label="Search frameworks"
168
- [clearable]="true"
169
- [debounceTime]="300"
170
- (search)="onSearch($event)"
171
- >
166
+ <hub-input label="Search frameworks" [clearable]="true" [debounceTime]="300" (search)="onSearch($event)">
172
167
  <hub-icon hubInputPrefix name="fa:solid:magnifying-glass" />
173
168
  </hub-input>
174
169
 
@@ -190,13 +185,7 @@ Project a leading / trailing icon **inside** the field, emit a debounced term on
190
185
  `type="password"` renders a masked field with an integrated reveal toggle inside the input group (a trailing addon, not a detached button):
191
186
 
192
187
  ```html
193
- <hub-input
194
- formControlName="password"
195
- type="password"
196
- label="Password"
197
- autocomplete="new-password"
198
- passwordStrength
199
- />
188
+ <hub-input formControlName="password" type="password" label="Password" autocomplete="new-password" passwordStrength />
200
189
  ```
201
190
 
202
191
  - `[(passwordRevealed)]` — two-way model for the reveal state; drive it externally or read it.
@@ -221,6 +210,64 @@ provideHubForms({
221
210
  });
222
211
  ```
223
212
 
213
+ #### Plain-text fields
214
+
215
+ `readonly` and `plaintext` are the two halves of a shut field, and the difference is who the
216
+ field is for. `readonly` is a *state* of a field somebody is still filling in, and a theme can
217
+ give it a box — `--hub-input-readonly-bg`, `--hub-input-readonly-border-color`, `-color` and
218
+ `-cursor` exist to be set. `plaintext` is for a value that is merely being *shown*: a record
219
+ open for consultation, a figure the server settled, a field a plan has locked. There the box is
220
+ noise, and having none is what `plaintext` is rather than a colour it happens to wear.
221
+
222
+ > **At the shipped defaults `readonly` already draws no box** — both those token defaults are
223
+ > `transparent`, deliberately: a read-only value is there to be read and loses only the chrome
224
+ > that promises you can type in it. Untouched, the two differ in the horizontal padding (12px
225
+ > against 0), the inline border width, the cursor, and the affordances. Set the two tokens and
226
+ > read-only takes the boxed look Bootstrap's own `readonly` ships with, while `plaintext` stays
227
+ > flat:
228
+ >
229
+ > ```css
230
+ > .hub-field--readonly {
231
+ > --hub-input-readonly-bg: var(--hub-sys-surface-sunken);
232
+ > --hub-input-readonly-border-color: var(--hub-sys-border-subtle);
233
+ > }
234
+ > ```
235
+
236
+ The value steps back a shade. Inside a box the box does the separating; with it gone, label and
237
+ value were the same colour and two pixels apart in size, so a column of them read as
238
+ undifferentiated lines. The label is left exactly as every other field's — same tokens, same
239
+ weight, because a form's labels keep one rhythm whatever state each field is in — and
240
+ `--hub-input-plaintext-color` moves the value instead, to `gray-700` against the editable
241
+ `gray-900`, with `--hub-input-plaintext-font-weight` one step lighter so it does not compete
242
+ with its own label.
243
+
244
+ The vertical padding moves rather than shrinks, through `--hub-input-plaintext-padding-block`:
245
+ none above, the field's whole vertical padding below. Nothing above puts the value directly under
246
+ its label — a label and its value are one thing and should read as a pair — while twice the
247
+ padding below holds the control at exactly an editable field's height, so a grid mixing the two
248
+ still lines up. Replace it with a single value and you give up one of the two.
249
+
250
+
251
+ ```html
252
+ <!-- being filled in, so it keeps the box -->
253
+ <hub-input formControlName="reference" label="Reference" [readonly]="true" />
254
+
255
+ <!-- merely being read, so the box goes -->
256
+ <hub-input formControlName="customer" label="Customer" [plaintext]="true" />
257
+ <hub-textarea formControlName="notes" label="Notes" [rows]="3" [plaintext]="true" />
258
+ ```
259
+
260
+ Modelled on Bootstrap's `.form-control-plaintext`, deliberately: the control stays a real
261
+ `<input>` / `<textarea>`, so the `<label for>` still points at something labelable and the text
262
+ stays selectable. A `<span>` would have broken both while going on looking right.
263
+
264
+ The horizontal padding goes and the border turns transparent **without losing its width**, so a
265
+ plain-text value lands on the same baseline as an editable neighbour and a form mixing the two
266
+ does not stagger. `plaintext` implies `readonly` and the two presentations are exclusive, so
267
+ they can never be passed in disagreement. Every affordance goes with the box — the clear button,
268
+ a projected caret, a datepicker icon, and a textarea's character counter, which tells you how
269
+ much room is left to type and so promises typing.
270
+
224
271
  ### Select
225
272
 
226
273
  ```html
@@ -237,7 +284,14 @@ provideHubForms({
237
284
  #### Floating label
238
285
 
239
286
  ```html
240
- <hub-select formControlName="country" labelType="floating" label="Country" [items]="countries" bindLabel="name" bindValue="code" />
287
+ <hub-select
288
+ formControlName="country"
289
+ labelType="floating"
290
+ label="Country"
291
+ [items]="countries"
292
+ bindLabel="name"
293
+ bindValue="code"
294
+ />
241
295
  ```
242
296
 
243
297
  The label sits inside the control and lifts on focus or on a value, on the same travel as
@@ -316,8 +370,7 @@ because a field keeps its box on the control rather than on its host.
316
370
  ### Datepicker
317
371
 
318
372
  ```html
319
- <hub-datepicker formControlName="date" label="Date" />
320
- <hub-datepicker formControlName="range" mode="range" label="Stay" />
373
+ <hub-datepicker formControlName="date" label="Date" /> <hub-datepicker formControlName="range" mode="range" label="Stay" />
321
374
  ```
322
375
 
323
376
  `granularity` sets how precise each picked point is, and selects the panel with it. It is
@@ -332,13 +385,38 @@ one is.
332
385
  <hub-datepicker formControlName="billingPeriod" granularity="month" />
333
386
  ```
334
387
 
335
- | `granularity` | Panel | Value (default `valueFormat`) |
336
- | --- | --- | --- |
337
- | `year` | Decade grid | `"2026"` |
338
- | `month` | 12-month grid | `"2026-09"` |
339
- | `day` *(default)* | Calendar | `"2026-09-01"` |
388
+ | `granularity` | Panel | Value (default `valueFormat`) |
389
+ | ---------------------------- | --------------------- | ----------------------------- |
390
+ | `year` | Decade grid | `"2026"` |
391
+ | `month` | 12-month grid | `"2026-09"` |
392
+ | `day` _(default)_ | Calendar | `"2026-09-01"` |
340
393
  | `hour` / `minute` / `second` | Calendar + time strip | `"2026-09-01T09:30:00+02:00"` |
341
394
 
395
+ #### Panel width and the month name
396
+
397
+ The panel is exactly as wide as the day grid it frames — seven cells, the six gaps between them
398
+ and the panel's own padding — so paging through the year never resizes it. Its header takes what
399
+ the two nav groups leave, which is about **102px**, and that is why the month is **abbreviated by
400
+ default**.
401
+
402
+ ```html
403
+ <!-- the month spelled out; only where the panel has been widened to fit it -->
404
+ <hub-datepicker formControlName="date" [monthFormat]="'long'" />
405
+ ```
406
+
407
+ Asked for at the default width, `long` is clipped with an ellipsis: «septiembre de 2026» needs
408
+ about 152px against the 102 available. Widen the panel first — both tokens feed the same
409
+ arithmetic, and both have to be declared **globally**: the calendar renders in an overlay
410
+ attached to `document.body`, outside the field's subtree, so a custom property set on the
411
+ component never reaches it.
412
+
413
+ ```css
414
+ :root {
415
+ --hub-daterangepicker-cell-size: 2.5rem; /* seven of these */
416
+ --hub-datepicker-grid-gap: 0.25rem; /* six of these */
417
+ }
418
+ ```
419
+
342
420
  **The value's timezone.** At `day` and coarser it is a bare calendar date with no zone attached,
343
421
  exactly as before. From `hour` onwards it is a full ISO 8601 timestamp carrying **the reader's
344
422
  local wall clock and the offset of that very date** — `+02:00` in Madrid in September, `+01:00`
@@ -382,7 +460,7 @@ Drag & drop, clipboard paste, constraints and previews. The control value stays
382
460
  />
383
461
  ```
384
462
 
385
- `accept`, `maxSize`, `maxFiles` and friends **filter**: an offending file never reaches the value and surfaces through `(rejected)` with a typed reason. They are enforced by hand, because the native `accept` attribute only filters the operating-system dialog — a drop or a paste bypasses it. To make the *control* invalid as well (worth doing when a value can also be patched in programmatically), add the matching validators:
463
+ `accept`, `maxSize`, `maxFiles` and friends **filter**: an offending file never reaches the value and surfaces through `(rejected)` with a typed reason. They are enforced by hand, because the native `accept` attribute only filters the operating-system dialog — a drop or a paste bypasses it. To make the _control_ invalid as well (worth doing when a value can also be patched in programmatically), add the matching validators:
386
464
 
387
465
  ```ts
388
466
  new FormControl<File[]>([], [hubMaxFiles(3), hubMaxFileSize(5 * 1024 * 1024), hubAcceptedFiles('image/*,.pdf')]);
@@ -482,7 +560,7 @@ error is surfaced by the fieldset/form — no manual error markup anywhere.
482
560
 
483
561
  The **invalid** state is always automatic: a touched, invalid field shows its
484
562
  error styling and message with no configuration. The **valid / success** state is
485
- strictly **opt-in** — success is *never* shown automatically. Enable it per field
563
+ strictly **opt-in** — success is _never_ shown automatically. Enable it per field
486
564
  with the `showValid` input, and optionally add a `validFeedback` message that
487
565
  renders below the control once the field is touched and valid:
488
566