ng-hub-ui-forms 22.34.0 → 22.35.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 +140 -3
- package/fesm2022/ng-hub-ui-forms.mjs +1274 -42
- package/fesm2022/ng-hub-ui-forms.mjs.map +1 -1
- package/package.json +1 -1
- package/styles/_group-addons.scss +11 -0
- package/styles/_tokens.scss +129 -2
- package/types/ng-hub-ui-forms.d.ts +446 -13
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ mode — no Bootstrap dependency.
|
|
|
95
95
|
|
|
96
96
|
## 🎯 Features
|
|
97
97
|
|
|
98
|
-
- **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).
|
|
98
|
+
- **Fields** — `hub-input` (text/number/email/password/color/switch/checkbox/counter, the colour format as a hex field or, given a palette, a grid of swatches, 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 as a list, as tiles or inside the field together with the files a record already has, optional upload progress).
|
|
99
99
|
- **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.
|
|
100
100
|
- **Containers** — `fieldset[hubFieldset]` (or the `<hub-fieldset>` element) / `form[hubForm]` group fields and show their group errors; `hub-legend` renders an accessible legend.
|
|
101
101
|
- **Configurable** — `provideHubForms({ … })` sets the invalid-feedback templates, datepicker locale/labels, file-input labels and more, app-wide or per instance.
|
|
@@ -195,6 +195,57 @@ string, so asking it to carry markup would drop the markup silently.
|
|
|
195
195
|
<hub-input formControlName="darkMode" type="switch" label="Dark mode" />
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
+
#### Colour fields
|
|
199
|
+
|
|
200
|
+
`type="color"` is a text field for the hex code, with the colour in a square at its start. The square
|
|
201
|
+
opens the browser's picker. The text takes a colour typed with or without `#`, in three or six digits,
|
|
202
|
+
and the form stores it as lowercase `#rrggbb`, the one notation the native picker reads. Invalid text
|
|
203
|
+
leaves the value alone and goes back to the last valid colour on blur.
|
|
204
|
+
|
|
205
|
+
Give the field a list of colours and it becomes a grid of swatches, one row the height of a field:
|
|
206
|
+
|
|
207
|
+
```html
|
|
208
|
+
<hub-input formControlName="status" type="color" label="Status colour" [swatches]="palettes.status" />
|
|
209
|
+
|
|
210
|
+
<hub-input
|
|
211
|
+
formControlName="tag"
|
|
212
|
+
type="color"
|
|
213
|
+
label="Tag"
|
|
214
|
+
[swatches]="['#ef4444', { value: '#22c55e', label: 'Done' }]"
|
|
215
|
+
[allowCustomColor]="false"
|
|
216
|
+
/>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
import { HUB_COLOR_PALETTES } from 'ng-hub-ui-forms';
|
|
221
|
+
|
|
222
|
+
readonly palettes = HUB_COLOR_PALETTES;
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
- A swatch is any CSS colour that `parseColor` from `ng-hub-ui-utils` reads (hex, `rgb()`, `hsl()`,
|
|
226
|
+
`oklch()`, `oklab()`, a named colour), bare or as `{ value, label }`. The label is what a screen reader
|
|
227
|
+
says, so name the colours that have a name. The control receives the string exactly as written. An
|
|
228
|
+
entry that is not a colour is dropped, with a warning in development builds.
|
|
229
|
+
- The last cell opens the native picker for a colour outside the list. `[allowCustomColor]="false"`
|
|
230
|
+
leaves it out for a closed palette; `customColorLabel` names it.
|
|
231
|
+
- The cells share the row down to `--hub-input-swatch-min-width`, then wrap onto more rows. Once they
|
|
232
|
+
wrap the field drops its box; `--hub-input-swatch-wrapped-border-color` and `-wrapped-bg` bring it back.
|
|
233
|
+
- The grid is a radio group named by the field label, with one Tab stop; the arrows, Home and End move
|
|
234
|
+
the selection.
|
|
235
|
+
- `HUB_COLOR_PALETTES` has five frozen lists of lowercase hex, each swatch named in English: `tailwind`
|
|
236
|
+
(17), `material` (19), `pastel` (17), `neutral` (11) and `status` (5).
|
|
237
|
+
|
|
238
|
+
Which field is drawn:
|
|
239
|
+
|
|
240
|
+
| `swatches` | Application palette (`provideHubForms`) | Result |
|
|
241
|
+
| ---------------- | --------------------------------------- | -------------------------------- |
|
|
242
|
+
| `null` (default) | none (default) | hex field |
|
|
243
|
+
| `null` | a list | grid with the application palette |
|
|
244
|
+
| `[]` | any | hex field |
|
|
245
|
+
| a list | any | grid with the field's list |
|
|
246
|
+
|
|
247
|
+
A list in which no entry is a colour also leaves the hex field.
|
|
248
|
+
|
|
198
249
|
#### Icon affix & typeahead (search boxes)
|
|
199
250
|
|
|
200
251
|
Project a leading / trailing icon **inside** the field, emit a debounced term on every keystroke, and let the field render its own clear button:
|
|
@@ -597,7 +648,7 @@ Whatever the uploader reports on `done` is kept on the item, so the ids the serv
|
|
|
597
648
|
const uploadedIds = fileInput.files().map((item) => (item.response as { id: string }).id);
|
|
598
649
|
```
|
|
599
650
|
|
|
600
|
-
Customize it without forking the template: the `--hub-file-input-*` tokens (every icon is a swappable CSS mask), the `hub-file-input-theme(...)` mixin, and three projection slots.
|
|
651
|
+
Customize it without forking the template: the `--hub-file-input-*` tokens (every icon is a swappable CSS mask), the `hub-file-input-theme(...)` mixin, and three projection slots. `hubFileIcon` applies to `preview="list"`; the tiles of `grid` and `inline` draw the family icons described below.
|
|
601
652
|
|
|
602
653
|
```html
|
|
603
654
|
<hub-file-input formControlName="attachments" [multiple]="true">
|
|
@@ -607,6 +658,73 @@ Customize it without forking the template: the `--hub-file-input-*` tokens (ever
|
|
|
607
658
|
</hub-file-input>
|
|
608
659
|
```
|
|
609
660
|
|
|
661
|
+
#### Inline preview and stored files
|
|
662
|
+
|
|
663
|
+
`preview="inline"` puts the file inside the field. One tile fills it: the image when the browser can
|
|
664
|
+
paint it, otherwise the icon of its family and its name. Hover, keyboard focus or a drag over the tile
|
|
665
|
+
raise a "Replace" pill, and a button in the corner removes the file. With `multiple` the tiles form a
|
|
666
|
+
grid inside the field that ends in a tile for adding more, and `maxFiles` adds a "3 of 5 files"
|
|
667
|
+
counter; at the limit the add tile goes away.
|
|
668
|
+
|
|
669
|
+
`currentFile` shows what the record already has:
|
|
670
|
+
|
|
671
|
+
```html
|
|
672
|
+
<hub-file-input
|
|
673
|
+
formControlName="logo"
|
|
674
|
+
label="Logo"
|
|
675
|
+
accept="image/*"
|
|
676
|
+
preview="inline"
|
|
677
|
+
[currentFile]="company.logoUrl"
|
|
678
|
+
(currentFileRemoved)="markForDeletion($event)"
|
|
679
|
+
/>
|
|
680
|
+
|
|
681
|
+
<hub-file-input
|
|
682
|
+
formControlName="contract"
|
|
683
|
+
label="Signed contract"
|
|
684
|
+
preview="inline"
|
|
685
|
+
[currentFile]="{ url: '/api/contracts/42/file', name: 'contract.pdf', type: 'application/pdf' }"
|
|
686
|
+
/>
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
- A bare URL gives the name from its last segment, when that has an extension, and the type from a
|
|
690
|
+
`data:` URL. Pass a `HubCurrentFile` when the URL reveals neither, and a list with `multiple`.
|
|
691
|
+
- A stored file is only shown: the form value stays a `File`, a `File[]` or `null`. When the user
|
|
692
|
+
removes it, or replaces it with a picked file, `currentFileRemoved` emits it. That is the moment to
|
|
693
|
+
delete it on the server.
|
|
694
|
+
- A click on a tile opens its file: a picked image in a native `<dialog>`, a stored file or any other
|
|
695
|
+
picked file in a new tab. Delete or Backspace on a focused tile removes it.
|
|
696
|
+
- `readonly` keeps the files in view and openable but blocks every change. `[clearable]="false"` keeps
|
|
697
|
+
the user from removing files. `[imagePreview]="false"` draws every file as its icon and creates no
|
|
698
|
+
object URLs.
|
|
699
|
+
|
|
700
|
+
`preview="grid"` draws the same tiles under the dropzone. An avatar takes five tokens:
|
|
701
|
+
|
|
702
|
+
```css
|
|
703
|
+
.avatar-field {
|
|
704
|
+
--hub-file-input-inline-width: 8rem;
|
|
705
|
+
--hub-file-input-inline-aspect-ratio: 1;
|
|
706
|
+
--hub-file-input-tile-radius: 50%;
|
|
707
|
+
--hub-file-input-tile-fit: cover;
|
|
708
|
+
--hub-file-input-tile-padding: 0;
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
Each family icon (`pdf`, `document`, `spreadsheet`, `presentation`, `archive`, `audio`, `video`, `code`,
|
|
713
|
+
`image`, `generic`) is a mask token, so replacing one is one line, and the tile's `data-file-kind`
|
|
714
|
+
attribute scopes a colour to one family:
|
|
715
|
+
|
|
716
|
+
```css
|
|
717
|
+
.my-form {
|
|
718
|
+
--hub-file-input-kind-pdf-icon: url('/icons/pdf.svg');
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.my-form .hub-file-input__tile[data-file-kind='pdf'] {
|
|
722
|
+
--hub-file-input-kind-icon-color: #dc2626;
|
|
723
|
+
}
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
The built-in drawings are [Bootstrap Icons](https://icons.getbootstrap.com) 1.13.1, under the MIT License.
|
|
727
|
+
|
|
610
728
|
#### Reproducing your own dropzone
|
|
611
729
|
|
|
612
730
|
The dropzone is built from a glyph, an invitation and a browse action, each themeable on its own — so a design system reproduces its own without forking the template.
|
|
@@ -722,6 +840,18 @@ field once it is touched and valid. The invalid state is unaffected — it is al
|
|
|
722
840
|
automatic; only success is gated behind this flag. A per-field `showValid` input
|
|
723
841
|
overrides the global default.
|
|
724
842
|
|
|
843
|
+
`color` sets an application palette for every colour field without `swatches` of its own (there is
|
|
844
|
+
none by default) and the two accessible names the colour field adds: `customColorLabel`
|
|
845
|
+
(`'Custom color'`) for the grid's last cell and `pickerLabel` (`'Choose color'`) for the hex field's
|
|
846
|
+
square. `fileInput` carries the file-input labels, among them `removeFile(name)`, `open(name)`,
|
|
847
|
+
`replace`, `replaceFile(name)`, `close`, `count(count, max)` and `currentFile`.
|
|
848
|
+
|
|
849
|
+
```ts
|
|
850
|
+
provideHubForms({
|
|
851
|
+
color: { swatches: HUB_COLOR_PALETTES.tailwind, customColorLabel: 'Other colour' }
|
|
852
|
+
});
|
|
853
|
+
```
|
|
854
|
+
|
|
725
855
|
---
|
|
726
856
|
|
|
727
857
|
## 🎨 Styling
|
|
@@ -753,6 +883,11 @@ hub-input {
|
|
|
753
883
|
}
|
|
754
884
|
```
|
|
755
885
|
|
|
886
|
+
**Colour field** — `--hub-input-color-size` is the width of the hex field's square; its height is
|
|
887
|
+
always the field's, and the default, the field's inner height, keeps it square. The grid of swatches
|
|
888
|
+
reads the `--hub-input-swatch-*` tokens, and `--hub-input-swatch-mark-color` forces one colour for every
|
|
889
|
+
check mark (unset, each mark is black or white, whichever reads on its swatch).
|
|
890
|
+
|
|
756
891
|
**`hub-slider`** — `--hub-slider-track-fill` takes a full `<image>` (e.g. a `linear-gradient(to right, …)`) for the filled part of the track, which renders intact clipped to the current percentage; `--hub-slider-value-space` is the value-bubble headroom and collapses to `0` on a `[showValue]="false"` (flush) slider:
|
|
757
892
|
|
|
758
893
|
```css
|
|
@@ -799,7 +934,9 @@ import { HubSignalFieldControl, hubSignalErrorMessages } from 'ng-hub-ui-forms/s
|
|
|
799
934
|
|
|
800
935
|
## ♿ Accessibility
|
|
801
936
|
|
|
802
|
-
- Labels are associated with their control (`for`/`id`); required fields are marked.
|
|
937
|
+
- Labels are associated with their control (`for`/`id`); required fields are marked. The colour
|
|
938
|
+
grid is a radio group, which a `<label for>` cannot name, so it points at the label's `id` through
|
|
939
|
+
`aria-labelledby`.
|
|
803
940
|
- **`labelType="visually-hidden"` names a control that has no room for a visible label.** A
|
|
804
941
|
toolbar search box or a compact grid cell cannot repeat the same word down every row, and the
|
|
805
942
|
alternative was a control with no accessible name at all — a placeholder is not a name. The
|