ng-hub-ui-forms 22.3.0 → 22.4.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.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ng-hub-ui-forms",
3
- "version": "22.3.0",
3
+ "version": "22.4.0",
4
4
  "license": "MIT",
5
5
  "description": "Accessible, signal-based form fields for Angular (input, textarea, slider, select, datepicker) with automatic error display for controls, FormGroups and FormArrays. Reactive Forms today, Signal Forms ready. Part of the ng-hub-ui family.",
6
6
  "author": "Carlos Morcillo <carlos.morcillo@me.com> (https://www.carlosmorcillo.com)",
@@ -50,7 +50,7 @@
50
50
  // ── Input ─────────────────────────────────────────────────────────────────
51
51
  --hub-input-color: var(--hub-sys-text-primary, #212529);
52
52
  --hub-input-bg: var(--hub-sys-surface-page, #fff);
53
- --hub-input-font-family: var(--hub-ref-font-family-base, system-ui, sans-serif);
53
+ --hub-input-font-family: var(--hub-ref-font-family-base, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif);
54
54
  --hub-input-font-size: var(--hub-ref-font-size-base, 1rem);
55
55
  --hub-input-font-weight: var(--hub-ref-font-weight-base, 400);
56
56
  --hub-input-line-height: var(--hub-ref-line-height-base, 1.5);
@@ -122,6 +122,16 @@
122
122
  --hub-slider-track-border-radius: var(--hub-ref-radius-pill, 50rem);
123
123
  --hub-slider-track-bg: var(--hub-sys-border-color-default, #dee2e6);
124
124
  --hub-slider-track-fill-bg: var(--hub-sys-color-primary, #0d6efd);
125
+ // Full background <image> for the filled portion of the track. The track layers
126
+ // this as a sized background over `--hub-slider-track-bg`, so it accepts a
127
+ // gradient (e.g. `linear-gradient(to right, …)`) that renders intact, clipped to
128
+ // the current percentage. The default wraps the solid `--hub-slider-track-fill-bg`
129
+ // in a flat gradient so it stays a valid, sizeable background layer while
130
+ // preserving the previous solid look (the colour token is kept for back-compat).
131
+ --hub-slider-track-fill: linear-gradient(var(--hub-slider-track-fill-bg), var(--hub-slider-track-fill-bg));
132
+ // Vertical room reserved above the rail for the value bubble. Set to 0 by the
133
+ // `--flush` modifier when the slider renders no value bubble.
134
+ --hub-slider-value-space: 1.75rem;
125
135
  --hub-slider-thumb-width: 1.1rem;
126
136
  --hub-slider-thumb-height: 1.1rem;
127
137
  --hub-slider-thumb-border-radius: 50%;
@@ -162,7 +172,12 @@
162
172
  --hub-select-dropdown-bg: var(--hub-sys-surface-page, #fff);
163
173
  --hub-select-dropdown-border-color: var(--hub-sys-border-color-default, #dee2e6);
164
174
  --hub-select-dropdown-border-radius: var(--hub-ref-radius-md, 0.375rem);
165
- --hub-select-dropdown-box-shadow: var(--hub-sys-shadow, 0 0.5rem 1rem rgba(0, 0, 0, 0.12));
175
+ --hub-select-dropdown-box-shadow: var(--hub-sys-shadow, 0 0.5rem 1rem rgba(0, 0, 0, 0.15));
176
+ // Dropdown panel stacking. The vendored ng-select hard-codes `z-index: 1050` on
177
+ // `.ng-dropdown-panel` — one below HubModal (`--hub-sys-zindex-modal`, 1055) — so a
178
+ // select opened inside a modal was clipped underneath it. Sit a few layers above
179
+ // the modal instead.
180
+ --hub-select-dropdown-z-index: calc(var(--hub-sys-zindex-modal, 1055) + 5);
166
181
 
167
182
  // ── Datepicker ──────────────────────────────────────────────────────────────
168
183
  --hub-datepicker-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%236c757d' d='M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z'/%3E%3C/svg%3E");
@@ -174,7 +189,7 @@
174
189
  --hub-daterangepicker-color: var(--hub-sys-text-primary, #212529);
175
190
  --hub-daterangepicker-border-color: var(--hub-sys-border-color-default, #dee2e6);
176
191
  --hub-daterangepicker-border-radius: var(--hub-ref-radius-md, 0.375rem);
177
- --hub-daterangepicker-box-shadow: var(--hub-sys-shadow, 0 0.5rem 1rem rgba(0, 0, 0, 0.12));
192
+ --hub-daterangepicker-box-shadow: var(--hub-sys-shadow, 0 0.5rem 1rem rgba(0, 0, 0, 0.15));
178
193
  --hub-daterangepicker-padding-x: var(--hub-ref-space-3, 1rem);
179
194
  --hub-daterangepicker-padding-y: var(--hub-ref-space-3, 1rem);
180
195
  --hub-daterangepicker-cell-size: 2rem;
@@ -203,4 +218,20 @@
203
218
  // Text on the selected button sits on the primary accent — derived contrast token.
204
219
  --hub-select-button-selected-color: var(--hub-sys-color-primary-on, var(--hub-ref-color-white, #fff));
205
220
  --hub-select-button-selected-border-color: var(--hub-sys-color-primary, #0d6efd);
221
+
222
+ // ── Segmented ───────────────────────────────────────────────────────────────
223
+ --hub-segmented-bg: var(--hub-sys-surface-elevated, #f8f9fa);
224
+ // Optional single-slot accent. Its default (transparent) contributes nothing, so the selected
225
+ // pill keeps the neutral white surface below; set it — or apply a `[color]` / `data-variant` —
226
+ // to tint the pill. A custom variant re-bases `--hub-segmented-selected-bg` (mirrors the
227
+ // `--hub-table-accent` model), which both the sliding indicator and the multiple-mode pill read.
228
+ --hub-segmented-accent: transparent;
229
+ --hub-segmented-selected-bg: var(--hub-sys-surface-page, #fff);
230
+ --hub-segmented-selected-color: var(--hub-sys-text-primary, #212529);
231
+ --hub-segmented-radius: var(--hub-ref-radius-md, 0.375rem);
232
+ --hub-segmented-gap: 0.25rem;
233
+ --hub-segmented-padding-x: var(--hub-ref-space-3, 1rem);
234
+ --hub-segmented-padding-y: var(--hub-ref-space-2, 0.5rem);
235
+ // Duration/easing of the single-mode sliding indicator as it moves between options.
236
+ --hub-segmented-indicator-transition: 0.2s ease;
206
237
  }
@@ -11,3 +11,6 @@
11
11
 
12
12
  @use 'tokens';
13
13
  @use 'field';
14
+
15
+ // One-call theming mixins (opt-in; forwarded so consumers can `@use` them from the package root).
16
+ @forward 'mixins/segmented-theme';
@@ -0,0 +1,66 @@
1
+ // ─────────────────────────────────────────────────────────────────────────
2
+ // hub-segmented-theme — one-call theming for `<hub-segmented>`
3
+ // ─────────────────────────────────────────────────────────────────────────
4
+ //
5
+ // Override any of the `--hub-segmented-*` design tokens in a single include.
6
+ // Every parameter is OPTIONAL and defaults to `null`: only the parameters you
7
+ // pass are emitted, so the rest keep the component's defaults. Token-based and
8
+ // self-contained (no Bootstrap dependencies).
9
+ //
10
+ // Apply it inside any selector that wraps the control — the host element, a
11
+ // container, a route, or `:root` for a global theme.
12
+ //
13
+ // @example — a compact, brand-accented bar with a rounded frame:
14
+ //
15
+ // @use 'ng-hub-ui-forms/styles/mixins/segmented-theme' as *;
16
+ //
17
+ // .view-switch {
18
+ // @include hub-segmented-theme(
19
+ // $selected-bg: var(--hub-sys-color-brand),
20
+ // $selected-color: var(--hub-sys-color-brand-on, #fff),
21
+ // $radius: 0.75rem,
22
+ // $padding-y: 0.375rem
23
+ // );
24
+ // }
25
+ //
26
+ // scss-docs-start hub-segmented-theme
27
+ @mixin hub-segmented-theme(
28
+ // ── Colour ──
29
+ $bg: null, // the bar (track) surface
30
+ $selected-bg: null, // selected pill / sliding-indicator fill
31
+ $selected-color: null, // selected option text colour
32
+ // ── Shape ──
33
+ $radius: null, // bar corner radius (pill radius derives from it)
34
+ // ── Density / spacing ──
35
+ $gap: null, // padding around, and gutter between, the options
36
+ $padding-x: null, // option horizontal padding
37
+ $padding-y: null // option vertical padding
38
+ ) {
39
+ // Colour
40
+ @if $bg != null {
41
+ --hub-segmented-bg: #{$bg};
42
+ }
43
+ @if $selected-bg != null {
44
+ --hub-segmented-selected-bg: #{$selected-bg};
45
+ }
46
+ @if $selected-color != null {
47
+ --hub-segmented-selected-color: #{$selected-color};
48
+ }
49
+
50
+ // Shape
51
+ @if $radius != null {
52
+ --hub-segmented-radius: #{$radius};
53
+ }
54
+
55
+ // Density / spacing
56
+ @if $gap != null {
57
+ --hub-segmented-gap: #{$gap};
58
+ }
59
+ @if $padding-x != null {
60
+ --hub-segmented-padding-x: #{$padding-x};
61
+ }
62
+ @if $padding-y != null {
63
+ --hub-segmented-padding-y: #{$padding-y};
64
+ }
65
+ }
66
+ // scss-docs-end hub-segmented-theme
@@ -771,6 +771,108 @@ declare class HubSliderComponent extends HubFieldControl {
771
771
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<HubSliderComponent, "hub-slider", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "labelType": { "alias": "labelType"; "required": false; "isSignal": true; }; "range": { "alias": "range"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "showValue": { "alias": "showValue"; "required": false; "isSignal": true; }; "formText": { "alias": "formText"; "required": false; "isSignal": true; }; "formTextType": { "alias": "formTextType"; "required": false; "isSignal": true; }; "classlist": { "alias": "classlist"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
772
772
  }
773
773
 
774
+ /** A single choice rendered by {@link HubSegmentedComponent}. */
775
+ interface HubSegmentedOption {
776
+ /** Value written to the form control when this option is selected. */
777
+ value: unknown;
778
+ /** Visible label for the segment. */
779
+ label: string;
780
+ /** When `true`, the segment is rendered but cannot be selected. */
781
+ disabled?: boolean;
782
+ }
783
+ /** Density of the segmented control. */
784
+ type HubSegmentedSize = 'sm' | 'md' | 'lg';
785
+ /**
786
+ * Segmented button bar (`hub-segmented`): a compact group of 2..n options rendered as an inline
787
+ * (or vertical) segmented control. A full `ng-hub-ui-forms` field — it extends
788
+ * {@link HubFieldControl}, so it binds with `formControlName` / `ngModel` and shares the label,
789
+ * helper text and validation chrome with every other field.
790
+ *
791
+ * Two selection modes:
792
+ * - **single** (default): exclusive choice following the WAI-ARIA radiogroup pattern
793
+ * (`role="radiogroup"` wrapping `role="radio"` buttons). Arrow keys move focus **and** select.
794
+ * The value is the scalar of the chosen option.
795
+ * - **multiple** (`[multiple]="true"`): a toggle group (`role="group"` wrapping
796
+ * `aria-pressed` buttons). Clicking toggles membership; arrow keys only move focus.
797
+ * The value is an array of the selected option values.
798
+ *
799
+ * ```html
800
+ * <hub-segmented
801
+ * formControlName="view"
802
+ * [options]="[{ value: 'list', label: 'List' }, { value: 'grid', label: 'Grid' }]"
803
+ * />
804
+ *
805
+ * <hub-segmented formControlName="tags" [multiple]="true" [vertical]="true" [options]="tags" />
806
+ * ```
807
+ */
808
+ declare class HubSegmentedComponent extends HubFieldControl {
809
+ #private;
810
+ protected readonly _labelTypes: typeof HubLabelTypes;
811
+ /** The selectable options, in render order. */
812
+ readonly options: _angular_core.InputSignal<HubSegmentedOption[]>;
813
+ /** Visual density. */
814
+ readonly size: _angular_core.InputSignal<HubSegmentedSize>;
815
+ /**
816
+ * Semantic accent for the selected pill. Drives `data-variant` on the bar, which re-bases the
817
+ * `--hub-segmented-selected-*` tokens. Built-in values map to the design-system palette
818
+ * (`primary`, `secondary`, `success`, `danger`, `warning`, `info`, `neutral`), but the set is
819
+ * OPEN — any custom string works as long as the consumer supplies the matching
820
+ * `--hub-segmented-selected-bg` / `--hub-segmented-selected-color` (or `--hub-segmented-accent`)
821
+ * for that `data-variant`. Empty string (default) keeps the neutral white-pill look.
822
+ */
823
+ readonly color: _angular_core.InputSignal<string>;
824
+ /** Label text. */
825
+ readonly label: _angular_core.InputSignal<string>;
826
+ /** Label display type (`stacked`, `horizontal`). */
827
+ readonly labelType: _angular_core.InputSignal<HubLabelType>;
828
+ /** Helper text shown below the control. */
829
+ readonly formText: _angular_core.InputSignal<string>;
830
+ /** When `true`, options toggle independently and the value is an array. */
831
+ readonly multiple: _angular_core.InputSignalWithTransform<boolean, unknown>;
832
+ /** When `true`, the segments stack vertically instead of sitting in a row. */
833
+ readonly vertical: _angular_core.InputSignalWithTransform<boolean, unknown>;
834
+ /** Currently selected value — a scalar in single mode, an array in multiple mode. */
835
+ readonly value: _angular_core.ModelSignal<unknown>;
836
+ /** The rendered option buttons, used to move focus during keyboard navigation. */
837
+ private readonly _buttons;
838
+ /** The segmented bar element — the positioning context for the sliding indicator. */
839
+ private readonly _bar;
840
+ private readonly _destroyRef;
841
+ private readonly _isBrowser;
842
+ constructor();
843
+ /**
844
+ * Index of the option that owns the group's tab stop (roving tabindex): the first selected
845
+ * option, or the first enabled option when nothing is selected yet.
846
+ */
847
+ readonly rovingIndex: _angular_core.Signal<number>;
848
+ /** Whether the given option is currently selected (mode-aware). */
849
+ isSelected(option: HubSegmentedOption): boolean;
850
+ /**
851
+ * Selects (single) or toggles (multiple) an option and notifies the form. No-op when the
852
+ * control or the option is disabled.
853
+ */
854
+ select(option: HubSegmentedOption): void;
855
+ /**
856
+ * Keyboard navigation. In single mode the arrow keys move to (and select) the next / previous
857
+ * enabled option (radiogroup pattern); in multiple mode they only move focus and selection is
858
+ * left to the native button click (`Space` / `Enter`). `Home` / `End` jump to the first / last
859
+ * enabled option.
860
+ */
861
+ onKeydown(event: KeyboardEvent): void;
862
+ /** Writes an incoming value from the form model (coerces to an array in multiple mode). */
863
+ writeValue(value: unknown): void;
864
+ /**
865
+ * Measures the selected option (single mode) and writes its position and size onto the bar as
866
+ * `--hub-segmented-indicator-{x,y,width,height}` px custom properties, which the sliding
867
+ * indicator reads. Collapses the indicator (width/height 0) in multiple mode or when nothing is
868
+ * selected. Browser-only — invoked from `afterRenderEffect` / `afterNextRender` / the
869
+ * `ResizeObserver`, so the DOM is always up to date when it runs.
870
+ */
871
+ private updateIndicator;
872
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubSegmentedComponent, never>;
873
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<HubSegmentedComponent, "hub-segmented", never, { "options": { "alias": "options"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "labelType": { "alias": "labelType"; "required": false; "isSignal": true; }; "formText": { "alias": "formText"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "vertical": { "alias": "vertical"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, never, never, true, never>;
874
+ }
875
+
774
876
  /**
775
877
  * Groups related fields under a `<fieldset>`/`<legend>` and **automatically displays the
776
878
  * group-level (cross-field) validation errors** of the bound `FormGroup`/`FormArray`.
@@ -899,9 +1001,22 @@ declare class HubSelectComponent extends HubFieldControl {
899
1001
  protected readonly _headerTpl: _angular_core.Signal<TemplateRef<any> | undefined>;
900
1002
  protected readonly _footerTpl: _angular_core.Signal<TemplateRef<any> | undefined>;
901
1003
  protected readonly _notFoundTpl: _angular_core.Signal<TemplateRef<any> | undefined>;
902
- /** Rendering format (`dropdown`, `buttons`, `checkbox`, `radio`). */
1004
+ /**
1005
+ * Rendering format (`dropdown`, `buttons`, `checkbox`, `radio`).
1006
+ *
1007
+ * @deprecated The non-dropdown values (`buttons` / `checkbox` / `radio`) are deprecated and
1008
+ * will be removed in the next major — use `<hub-segmented>` instead, which is the dedicated,
1009
+ * lightweight control for inline options as segments/buttons (single **and** multiple selection,
1010
+ * horizontal **and** vertical, with label / helper text). Migration: `format="buttons"` →
1011
+ * `<hub-segmented>`; `format="checkbox"` → `<hub-segmented [multiple]="true">`; `format="radio"`
1012
+ * → `<hub-segmented [vertical]="true">`. Only `dropdown` (the default) will remain on `hub-select`.
1013
+ */
903
1014
  readonly format: _angular_core.InputSignal<HubSelectFormat>;
904
- /** Lay out the `buttons`/`checkbox`/`radio` options vertically. */
1015
+ /**
1016
+ * Lay out the `buttons`/`checkbox`/`radio` options vertically.
1017
+ *
1018
+ * @deprecated Tied to the deprecated non-dropdown `format` values — use `<hub-segmented [vertical]="true">` instead.
1019
+ */
905
1020
  readonly vertical: _angular_core.InputSignalWithTransform<boolean, unknown>;
906
1021
  /** Items to choose from. */
907
1022
  readonly items: _angular_core.InputSignal<any[]>;
@@ -1594,5 +1709,5 @@ interface HubFormControlAdapter {
1594
1709
  */
1595
1710
  declare const hubFormControlAdapter: HubFormControlAdapter;
1596
1711
 
1597
- export { FormTextTypes, HUB_FORMS_CONFIG, HubAutoresizeDirective, HubDatepickerComponent, HubFieldControl, HubFieldsetComponent, HubFormComponent, HubFormControl, HubFormTextDirective, HubGroupControl, HubInputComponent, HubInputFormats, HubInputPrefixDirective, HubInputSuffixDirective, HubInvertColorPipe, HubJoinButLastPipe, HubLabelTypes, HubLegendComponent, HubLegendDirective, HubMapPipe, HubOtpInputComponent, HubSafeUrlPipe, HubSelectComponent, HubSelectFormats, HubSliderComponent, HubSnakeUpperPipe, HubTextareaComponent, HubUcfirstPipe, HubValidationErrorDirective, NgClearButtonTemplateDirective, NgFooterTemplateDirective, NgHeaderTemplateDirective, NgLabelTemplateDirective, NgLoadingSpinnerTemplateDirective, NgLoadingTextTemplateDirective, NgMultiLabelTemplateDirective, NgNotFoundTemplateDirective, NgOptgroupTemplateDirective, NgOptionComponent, NgOptionTemplateDirective, NgSelectConfig, NgTagTemplateDirective, NgTypeToSearchTemplateDirective, applyMask, areEqual, camelToSnakeUpper, controlHasMinOrMaxValidator, defaultHubDatepickerConfig, defaultHubDatepickerLabels, defaultHubFormsConfig, defaultInvalidFeedback, get, getActiveElement, getMinOrMaxValueFromValidator, hubAreEqual, hubFormControlAdapter, isDefined, isMaskActive, isString, joinButLast, provideHubForms, runInZone, uuid };
1598
- export type { FormTextType, HubDateRange, HubDateValue, HubDatepickerConfig, HubDatepickerLabels, HubDatepickerMode, HubFormControlAdapter, HubFormControlConfig, HubFormControlHandle, HubFormControlOption, HubFormsConfig, HubGroupErrorTrigger, HubInputFormat, HubLabelType, HubMaskResult, HubOtpMode, HubSelectFormat, HubSliderValue };
1712
+ export { FormTextTypes, HUB_FORMS_CONFIG, HubAutoresizeDirective, HubDatepickerComponent, HubFieldControl, HubFieldsetComponent, HubFormComponent, HubFormControl, HubFormTextDirective, HubGroupControl, HubInputComponent, HubInputFormats, HubInputPrefixDirective, HubInputSuffixDirective, HubInvertColorPipe, HubJoinButLastPipe, HubLabelTypes, HubLegendComponent, HubLegendDirective, HubMapPipe, HubOtpInputComponent, HubSafeUrlPipe, HubSegmentedComponent, HubSelectComponent, HubSelectFormats, HubSliderComponent, HubSnakeUpperPipe, HubTextareaComponent, HubUcfirstPipe, HubValidationErrorDirective, NgClearButtonTemplateDirective, NgFooterTemplateDirective, NgHeaderTemplateDirective, NgLabelTemplateDirective, NgLoadingSpinnerTemplateDirective, NgLoadingTextTemplateDirective, NgMultiLabelTemplateDirective, NgNotFoundTemplateDirective, NgOptgroupTemplateDirective, NgOptionComponent, NgOptionTemplateDirective, NgSelectConfig, NgTagTemplateDirective, NgTypeToSearchTemplateDirective, applyMask, areEqual, camelToSnakeUpper, controlHasMinOrMaxValidator, defaultHubDatepickerConfig, defaultHubDatepickerLabels, defaultHubFormsConfig, defaultInvalidFeedback, get, getActiveElement, getMinOrMaxValueFromValidator, hubAreEqual, hubFormControlAdapter, isDefined, isMaskActive, isString, joinButLast, provideHubForms, runInZone, uuid };
1713
+ export type { FormTextType, HubDateRange, HubDateValue, HubDatepickerConfig, HubDatepickerLabels, HubDatepickerMode, HubFormControlAdapter, HubFormControlConfig, HubFormControlHandle, HubFormControlOption, HubFormsConfig, HubGroupErrorTrigger, HubInputFormat, HubLabelType, HubMaskResult, HubOtpMode, HubSegmentedOption, HubSegmentedSize, HubSelectFormat, HubSliderValue };
Binary file