ng-hub-ui-forms 22.1.2 → 22.3.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.1.2",
3
+ "version": "22.3.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)",
@@ -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);
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { OnInit, AfterContentInit, OnDestroy, TemplateRef, ElementRef, InjectionToken, EnvironmentProviders, PipeTransform, NgZone } from '@angular/core';
2
+ import { OnInit, AfterContentInit, OnDestroy, TemplateRef, ElementRef, InjectionToken, EnvironmentProviders, PipeTransform, NgZone, ViewContainerRef } from '@angular/core';
3
3
  import { NgControl, ControlContainer, ControlValueAccessor, ValidationErrors, AbstractControl, ValidatorFn } from '@angular/forms';
4
4
  import { Subject, OperatorFunction } from 'rxjs';
5
5
  import * as ng_hub_ui_forms from 'ng-hub-ui-forms';
@@ -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. */
@@ -1478,5 +1547,52 @@ declare function isMaskActive(mask: string | null | undefined): boolean;
1478
1547
  */
1479
1548
  declare function applyMask(value: string | null | undefined, mask: string): HubMaskResult;
1480
1549
 
1481
- 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, isDefined, isMaskActive, isString, joinButLast, provideHubForms, runInZone, uuid };
1482
- export type { FormTextType, HubDateRange, HubDateValue, HubDatepickerConfig, HubDatepickerLabels, HubDatepickerMode, HubFormsConfig, HubGroupErrorTrigger, HubInputFormat, HubLabelType, HubMaskResult, HubOtpMode, HubSelectFormat, HubSliderValue };
1550
+ /** A `{ value, label }` option for select-kind controls. */
1551
+ interface HubFormControlOption {
1552
+ value: unknown;
1553
+ label: string;
1554
+ }
1555
+ /**
1556
+ * Framework-neutral description of a primitive control to render dynamically.
1557
+ *
1558
+ * The shape mirrors (structurally) the contract other ng-hub-ui libraries expose
1559
+ * for optional control hosting (e.g. `ng-hub-ui-paginable`'s table), so this
1560
+ * adapter can be wired into them without either package importing the other.
1561
+ */
1562
+ interface HubFormControlConfig {
1563
+ kind: 'input' | 'select';
1564
+ value: unknown;
1565
+ type?: string;
1566
+ placeholder?: string;
1567
+ ariaLabel?: string;
1568
+ cssClass?: string;
1569
+ options?: ReadonlyArray<HubFormControlOption>;
1570
+ onValueChange: (value: unknown) => void;
1571
+ }
1572
+ /** Live handle to a control created by {@link hubFormControlAdapter}. */
1573
+ interface HubFormControlHandle {
1574
+ /** Pushes a new value into the control (external updates). */
1575
+ setValue(value: unknown): void;
1576
+ /** Destroys the control and releases its resources. */
1577
+ destroy(): void;
1578
+ }
1579
+ /** Adapter that renders primitive controls with the ng-hub-ui-forms components. */
1580
+ interface HubFormControlAdapter {
1581
+ create(container: ViewContainerRef, config: HubFormControlConfig): HubFormControlHandle;
1582
+ }
1583
+ /**
1584
+ * Ready-made {@link HubFormControlAdapter} backed by `HubInputComponent` /
1585
+ * `HubSelectComponent`.
1586
+ *
1587
+ * Wire it into any ng-hub-ui primitive that exposes an optional form-controls
1588
+ * token, e.g. `provideHubPaginableFormControls(hubFormControlAdapter)`. The host
1589
+ * library keeps **zero hard dependency** on `ng-hub-ui-forms`; only an app that
1590
+ * opts in pulls these components.
1591
+ *
1592
+ * Requires `provideHubForms()` (or the default config) to be available in the
1593
+ * environment so the field components can resolve their configuration.
1594
+ */
1595
+ declare const hubFormControlAdapter: HubFormControlAdapter;
1596
+
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 };
Binary file