ng-hub-ui-forms 22.2.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.2.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);
@@ -70,6 +70,18 @@
70
70
  --hub-input-group-addon-color: var(--hub-sys-text-muted, #6c757d);
71
71
  --hub-input-group-addon-border-color: var(--hub-input-border-color);
72
72
 
73
+ // Input · affix (projected leading/trailing content, e.g. a <hub-icon>)
74
+ --hub-input-icon-color: var(--hub-sys-text-muted, #6c757d);
75
+ --hub-input-icon-size: var(--hub-ref-font-size-base, 1rem);
76
+ --hub-input-affix-inset: var(--hub-input-padding-x);
77
+ --hub-input-affix-gap: var(--hub-ref-space-2, 0.5rem);
78
+
79
+ // Input · clear button ([clearable]) — glyph is a swappable mask
80
+ --hub-input-clear-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='black' d='M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708'/%3E%3C/svg%3E");
81
+ --hub-input-clear-size: var(--hub-ref-font-size-base, 1rem);
82
+ --hub-input-clear-color: var(--hub-sys-text-muted, #6c757d);
83
+ --hub-input-clear-hover-color: var(--hub-sys-color-danger, #dc3545);
84
+
73
85
  // Input · counter format (−/+)
74
86
  --hub-input-counter-button-bg: var(--hub-sys-surface-elevated, #f8f9fa);
75
87
  --hub-input-counter-button-color: var(--hub-sys-text-primary, #212529);
@@ -110,6 +122,16 @@
110
122
  --hub-slider-track-border-radius: var(--hub-ref-radius-pill, 50rem);
111
123
  --hub-slider-track-bg: var(--hub-sys-border-color-default, #dee2e6);
112
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;
113
135
  --hub-slider-thumb-width: 1.1rem;
114
136
  --hub-slider-thumb-height: 1.1rem;
115
137
  --hub-slider-thumb-border-radius: 50%;
@@ -150,7 +172,12 @@
150
172
  --hub-select-dropdown-bg: var(--hub-sys-surface-page, #fff);
151
173
  --hub-select-dropdown-border-color: var(--hub-sys-border-color-default, #dee2e6);
152
174
  --hub-select-dropdown-border-radius: var(--hub-ref-radius-md, 0.375rem);
153
- --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);
154
181
 
155
182
  // ── Datepicker ──────────────────────────────────────────────────────────────
156
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");
@@ -162,7 +189,7 @@
162
189
  --hub-daterangepicker-color: var(--hub-sys-text-primary, #212529);
163
190
  --hub-daterangepicker-border-color: var(--hub-sys-border-color-default, #dee2e6);
164
191
  --hub-daterangepicker-border-radius: var(--hub-ref-radius-md, 0.375rem);
165
- --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));
166
193
  --hub-daterangepicker-padding-x: var(--hub-ref-space-3, 1rem);
167
194
  --hub-daterangepicker-padding-y: var(--hub-ref-space-3, 1rem);
168
195
  --hub-daterangepicker-cell-size: 2rem;
@@ -191,4 +218,20 @@
191
218
  // Text on the selected button sits on the primary accent — derived contrast token.
192
219
  --hub-select-button-selected-color: var(--hub-sys-color-primary-on, var(--hub-ref-color-white, #fff));
193
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;
194
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
@@ -383,6 +383,44 @@ declare enum HubInputFormats {
383
383
  File = "file"
384
384
  }
385
385
 
386
+ /**
387
+ * Projects content into the **inline-start** affix area of a `<hub-input>` (left in
388
+ * LTR, right in RTL). Use it for a leading icon — a `<hub-icon>`, currency symbol,
389
+ * inline `<svg>` or even a small button.
390
+ *
391
+ * The input automatically reserves inline padding so its text never overlaps the
392
+ * affix, and themes a projected `<hub-icon>` with its `--hub-input-icon-*` tokens.
393
+ *
394
+ * ```html
395
+ * <hub-input placeholder="Search…">
396
+ * <hub-icon hubInputPrefix name="fa:solid:magnifying-glass" />
397
+ * </hub-input>
398
+ * ```
399
+ */
400
+ declare class HubInputPrefixDirective {
401
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubInputPrefixDirective, never>;
402
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<HubInputPrefixDirective, "[hubInputPrefix]", never, {}, {}, never, never, true, never>;
403
+ }
404
+
405
+ /**
406
+ * Projects content into the **inline-end** affix area of a `<hub-input>` (right in
407
+ * LTR, left in RTL). Use it for a trailing icon or a unit label. For a clear
408
+ * button, prefer the built-in `[clearable]` input instead of projecting one.
409
+ *
410
+ * The input automatically reserves inline padding so its text never overlaps the
411
+ * affix, and themes a projected `<hub-icon>` with its `--hub-input-icon-*` tokens.
412
+ *
413
+ * ```html
414
+ * <hub-input>
415
+ * <hub-icon hubInputSuffix name="fa:solid:circle-info" />
416
+ * </hub-input>
417
+ * ```
418
+ */
419
+ declare class HubInputSuffixDirective {
420
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubInputSuffixDirective, never>;
421
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<HubInputSuffixDirective, "[hubInputSuffix]", never, {}, {}, never, never, true, never>;
422
+ }
423
+
386
424
  /** Value held by a `<hub-input>` across its supported formats. */
387
425
  type HubInputValue = number | string | boolean | File | FileList | null;
388
426
  /**
@@ -437,6 +475,23 @@ declare class HubInputComponent extends HubFieldControl {
437
475
  readonly prepend: _angular_core.InputSignal<string | string[]>;
438
476
  /** Text shown after the control as an input-group addon (text-like formats). */
439
477
  readonly append: _angular_core.InputSignal<string | string[]>;
478
+ /** Projected inline-start affix (`[hubInputPrefix]`) — e.g. a `<hub-icon>`, when present. */
479
+ protected readonly prefixDir: _angular_core.Signal<HubInputPrefixDirective | undefined>;
480
+ /** Projected inline-end affix (`[hubInputSuffix]`) — e.g. a `<hub-icon>`, when present. */
481
+ protected readonly suffixDir: _angular_core.Signal<HubInputSuffixDirective | undefined>;
482
+ /**
483
+ * When true, a clear (✕) button is rendered inside the field once it holds a
484
+ * value; activating it resets the control. The glyph comes from the
485
+ * `--hub-input-clear-icon` CSS token, so it can be restyled without touching
486
+ * the template.
487
+ */
488
+ readonly clearable: _angular_core.InputSignalWithTransform<boolean, unknown>;
489
+ /** Whether the internal clear button should be shown right now. */
490
+ protected readonly showClear: _angular_core.Signal<boolean>;
491
+ /** Whether an inline-start affix (projected prefix) is present. */
492
+ protected readonly hasPrefix: _angular_core.Signal<boolean>;
493
+ /** Whether an inline-end affix (projected suffix or the clear button) is present. */
494
+ protected readonly hasSuffix: _angular_core.Signal<boolean>;
440
495
  /** Extra CSS classes applied to the host element. */
441
496
  readonly classlist: _angular_core.InputSignal<string>;
442
497
  /**
@@ -455,6 +510,16 @@ declare class HubInputComponent extends HubFieldControl {
455
510
  readonly valueChange: _angular_core.OutputEmitterRef<HubInputValue>;
456
511
  /** Emits the current value when Enter is pressed. */
457
512
  readonly enter: _angular_core.OutputEmitterRef<HubInputValue>;
513
+ /** Debounce in milliseconds before {@link search} fires. `0` emits on every keystroke. */
514
+ readonly debounceTime: _angular_core.InputSignalWithTransform<number, unknown>;
515
+ /**
516
+ * Debounced typeahead event: emits the current term (stringified) `debounceTime`
517
+ * ms after the user stops typing. Wire it to drive search / autocomplete without
518
+ * rolling your own debounce. Text-like formats only; `valueChange` stays synchronous.
519
+ */
520
+ readonly search: _angular_core.OutputEmitterRef<string>;
521
+ /** Clears any pending debounce timer when the component is destroyed. */
522
+ private readonly _searchCleanup;
458
523
  /** Accepted file types (file format), e.g. `image/*,.pdf`. */
459
524
  readonly accept: _angular_core.InputSignal<string>;
460
525
  /** Whether multiple files can be selected (file format). */
@@ -465,6 +530,8 @@ declare class HubInputComponent extends HubFieldControl {
465
530
  protected readonly fileInput: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
466
531
  /** Whether the current format renders a checkable control (checkbox / switch). */
467
532
  protected readonly isCheckable: _angular_core.Signal<boolean>;
533
+ /** Whether the current format renders a typeable text-like control (drives the `search` event). */
534
+ protected readonly isTextLike: _angular_core.Signal<boolean>;
468
535
  /** Display label for the selected file(s). */
469
536
  protected readonly fileLabel: _angular_core.Signal<string>;
470
537
  /** Normalized list of prepend addons. */
@@ -497,10 +564,12 @@ declare class HubInputComponent extends HubFieldControl {
497
564
  * @param event - The native `change` event of the file input.
498
565
  */
499
566
  protected setFileValue(event: Event): void;
567
+ /** Resets a text-like control to empty via the internal clear button. */
568
+ protected clear(): void;
500
569
  /** Clears the selected file(s). */
501
570
  protected clearFile(): void;
502
571
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubInputComponent, never>;
503
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<HubInputComponent, "hub-input", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "labelType": { "alias": "labelType"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "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; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "formText": { "alias": "formText"; "required": false; "isSignal": true; }; "formTextType": { "alias": "formTextType"; "required": false; "isSignal": true; }; "prepend": { "alias": "prepend"; "required": false; "isSignal": true; }; "append": { "alias": "append"; "required": false; "isSignal": true; }; "classlist": { "alias": "classlist"; "required": false; "isSignal": true; }; "mask": { "alias": "mask"; "required": false; "isSignal": true; }; "unmaskValue": { "alias": "unmaskValue"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "buttonLabel": { "alias": "buttonLabel"; "required": false; "isSignal": true; }; }, { "labelType": "labelTypeChange"; "placeholder": "placeholderChange"; "min": "minChange"; "max": "maxChange"; "valueChange": "valueChange"; "enter": "enter"; }, never, never, true, never>;
572
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<HubInputComponent, "hub-input", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "labelType": { "alias": "labelType"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "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; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "formText": { "alias": "formText"; "required": false; "isSignal": true; }; "formTextType": { "alias": "formTextType"; "required": false; "isSignal": true; }; "prepend": { "alias": "prepend"; "required": false; "isSignal": true; }; "append": { "alias": "append"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "classlist": { "alias": "classlist"; "required": false; "isSignal": true; }; "mask": { "alias": "mask"; "required": false; "isSignal": true; }; "unmaskValue": { "alias": "unmaskValue"; "required": false; "isSignal": true; }; "debounceTime": { "alias": "debounceTime"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "buttonLabel": { "alias": "buttonLabel"; "required": false; "isSignal": true; }; }, { "labelType": "labelTypeChange"; "placeholder": "placeholderChange"; "min": "minChange"; "max": "maxChange"; "valueChange": "valueChange"; "enter": "enter"; "search": "search"; }, ["prefixDir", "suffixDir"], ["[hubInputPrefix]", "[hubInputSuffix]"], true, never>;
504
573
  }
505
574
 
506
575
  /** Character set accepted by the OTP field. */
@@ -702,6 +771,108 @@ declare class HubSliderComponent extends HubFieldControl {
702
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>;
703
772
  }
704
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
+
705
876
  /**
706
877
  * Groups related fields under a `<fieldset>`/`<legend>` and **automatically displays the
707
878
  * group-level (cross-field) validation errors** of the bound `FormGroup`/`FormArray`.
@@ -830,9 +1001,22 @@ declare class HubSelectComponent extends HubFieldControl {
830
1001
  protected readonly _headerTpl: _angular_core.Signal<TemplateRef<any> | undefined>;
831
1002
  protected readonly _footerTpl: _angular_core.Signal<TemplateRef<any> | undefined>;
832
1003
  protected readonly _notFoundTpl: _angular_core.Signal<TemplateRef<any> | undefined>;
833
- /** 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
+ */
834
1014
  readonly format: _angular_core.InputSignal<HubSelectFormat>;
835
- /** 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
+ */
836
1020
  readonly vertical: _angular_core.InputSignalWithTransform<boolean, unknown>;
837
1021
  /** Items to choose from. */
838
1022
  readonly items: _angular_core.InputSignal<any[]>;
@@ -1525,5 +1709,5 @@ interface HubFormControlAdapter {
1525
1709
  */
1526
1710
  declare const hubFormControlAdapter: HubFormControlAdapter;
1527
1711
 
1528
- export { FormTextTypes, HUB_FORMS_CONFIG, HubAutoresizeDirective, HubDatepickerComponent, HubFieldControl, HubFieldsetComponent, HubFormComponent, HubFormControl, HubFormTextDirective, HubGroupControl, HubInputComponent, HubInputFormats, 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 };
1529
- 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