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 +102 -24
- package/fesm2022/ng-hub-ui-forms.mjs +57 -11
- package/fesm2022/ng-hub-ui-forms.mjs.map +1 -1
- package/package.json +2 -2
- package/styles/_field.scss +69 -0
- package/styles/_tokens.scss +20 -0
- package/types/ng-hub-ui-forms.d.ts +44 -3
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
|
-
|
|
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
|
|
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`
|
|
336
|
-
|
|
|
337
|
-
| `year`
|
|
338
|
-
| `month`
|
|
339
|
-
| `day`
|
|
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
|
|
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
|
|
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
|
|