@truenas/ui-components 0.1.64 → 0.1.66

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truenas/ui-components",
3
- "version": "0.1.64",
3
+ "version": "0.1.66",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org",
6
6
  "access": "public"
@@ -952,11 +952,12 @@ interface IconButtonHarnessFilters extends BaseHarnessFilters {
952
952
 
953
953
  declare enum InputType {
954
954
  Email = "email",
955
+ Number = "number",
955
956
  Password = "password",
956
957
  PlainText = "text"
957
958
  }
958
959
 
959
- declare class TnInputComponent implements AfterViewInit, ControlValueAccessor {
960
+ declare class TnInputComponent implements AfterViewInit, OnDestroy, ControlValueAccessor {
960
961
  inputEl: _angular_core.Signal<ElementRef<HTMLInputElement | HTMLTextAreaElement>>;
961
962
  inputType: _angular_core.InputSignal<InputType>;
962
963
  placeholder: _angular_core.InputSignal<string>;
@@ -964,6 +965,25 @@ declare class TnInputComponent implements AfterViewInit, ControlValueAccessor {
964
965
  disabled: _angular_core.InputSignal<boolean>;
965
966
  multiline: _angular_core.InputSignal<boolean>;
966
967
  rows: _angular_core.InputSignal<number>;
968
+ /**
969
+ * Accessible name for the control. Rendered as `aria-label` on the input/textarea.
970
+ *
971
+ * Leave unset when the input is wrapped in a `tn-form-field` (or otherwise has a
972
+ * visible `<label>`); set it for standalone usage so the control isn't unnamed in
973
+ * the a11y tree.
974
+ */
975
+ ariaLabel: _angular_core.InputSignal<string | undefined>;
976
+ /**
977
+ * Integer/decimal switch — only meaningful when `inputType` is `InputType.Number`.
978
+ *
979
+ * - **`true` (default) → decimal mode**: accepts a single `.` and emits via
980
+ * `parseFloat`, so a `Number` field accepts `"3.5"` out of the box.
981
+ * - **`false` → integer mode**: strips `.` and emits via `parseInt`.
982
+ *
983
+ * Range enforcement is intentionally left to the consumer's form validators
984
+ * (e.g. `Validators.min`/`max`), which work because the control emits real numbers.
985
+ */
986
+ allowDecimals: _angular_core.InputSignal<boolean>;
967
987
  prefixIcon: _angular_core.InputSignal<string | undefined>;
968
988
  prefixIconLibrary: _angular_core.InputSignal<IconLibraryType | undefined>;
969
989
  suffixIcon: _angular_core.InputSignal<string | undefined>;
@@ -972,22 +992,37 @@ declare class TnInputComponent implements AfterViewInit, ControlValueAccessor {
972
992
  onSuffixAction: _angular_core.OutputEmitterRef<MouseEvent>;
973
993
  hasPrefixIcon: _angular_core.Signal<boolean>;
974
994
  hasSuffixIcon: _angular_core.Signal<boolean>;
995
+ isNumeric: _angular_core.Signal<boolean>;
996
+ /** True when the field only accepts whole numbers (i.e. `allowDecimals` is false). */
997
+ integerOnly: _angular_core.Signal<boolean>;
998
+ /** The `type` attribute actually rendered. Number mode uses a text input + inputmode to avoid the native type="number" footguns. */
999
+ resolvedType: _angular_core.Signal<InputType>;
1000
+ /** `inputmode` hint: numeric keypad for integers, decimal keypad otherwise. Null (omitted) when not in number mode. */
1001
+ numericInputMode: _angular_core.Signal<"numeric" | "decimal" | null>;
1002
+ /** Number mode is always single-line; it wins over `multiline` if both are set. */
1003
+ showTextarea: _angular_core.Signal<boolean>;
975
1004
  id: string;
976
- value: string;
1005
+ protected value: string;
977
1006
  private formDisabled;
978
1007
  isDisabled: _angular_core.Signal<boolean>;
979
1008
  private onChange;
980
1009
  private onTouched;
981
1010
  private focusMonitor;
1011
+ private monitoredEl?;
982
1012
  ngAfterViewInit(): void;
983
- writeValue(value: string): void;
984
- registerOnChange(fn: (value: string) => void): void;
1013
+ ngOnDestroy(): void;
1014
+ writeValue(value: string | number | null | undefined): void;
1015
+ registerOnChange(fn: (value: string | number | null) => void): void;
985
1016
  registerOnTouched(fn: () => void): void;
986
1017
  setDisabledState(isDisabled: boolean): void;
987
- onValueChange(event: Event): void;
988
- onBlur(): void;
1018
+ protected onValueChange(event: Event): void;
1019
+ protected onBlur(): void;
1020
+ /** Strips any character that can't appear in the current numeric mode (single leading '-', single '.' for decimals). */
1021
+ private sanitizeNumeric;
1022
+ /** Parses a sanitized string to a number, mapping empty/partial input to null (never 0). */
1023
+ private parseNumeric;
989
1024
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TnInputComponent, never>;
990
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnInputComponent, "tn-input", never, { "inputType": { "alias": "inputType"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "testId": { "alias": "testId"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "multiline": { "alias": "multiline"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "prefixIcon": { "alias": "prefixIcon"; "required": false; "isSignal": true; }; "prefixIconLibrary": { "alias": "prefixIconLibrary"; "required": false; "isSignal": true; }; "suffixIcon": { "alias": "suffixIcon"; "required": false; "isSignal": true; }; "suffixIconLibrary": { "alias": "suffixIconLibrary"; "required": false; "isSignal": true; }; "suffixIconAriaLabel": { "alias": "suffixIconAriaLabel"; "required": false; "isSignal": true; }; }, { "onSuffixAction": "onSuffixAction"; }, never, never, true, never>;
1025
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnInputComponent, "tn-input", never, { "inputType": { "alias": "inputType"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "testId": { "alias": "testId"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "multiline": { "alias": "multiline"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "allowDecimals": { "alias": "allowDecimals"; "required": false; "isSignal": true; }; "prefixIcon": { "alias": "prefixIcon"; "required": false; "isSignal": true; }; "prefixIconLibrary": { "alias": "prefixIconLibrary"; "required": false; "isSignal": true; }; "suffixIcon": { "alias": "suffixIcon"; "required": false; "isSignal": true; }; "suffixIconLibrary": { "alias": "suffixIconLibrary"; "required": false; "isSignal": true; }; "suffixIconAriaLabel": { "alias": "suffixIconAriaLabel"; "required": false; "isSignal": true; }; }, { "onSuffixAction": "onSuffixAction"; }, never, never, true, never>;
991
1026
  }
992
1027
 
993
1028
  /**
@@ -1222,6 +1257,34 @@ declare class TnInputHarness extends ComponentHarness {
1222
1257
  * @param value The value to set.
1223
1258
  */
1224
1259
  setValue(value: string): Promise<void>;
1260
+ /**
1261
+ * Gets the current value parsed as a number, mirroring what the control emits in number mode.
1262
+ * Empty or non-numeric input resolves to null (never 0).
1263
+ *
1264
+ * @returns Promise resolving to the numeric value, or null.
1265
+ */
1266
+ getNumericValue(): Promise<number | null>;
1267
+ /**
1268
+ * Gets the `inputmode` attribute (e.g. 'numeric' or 'decimal' in number mode).
1269
+ *
1270
+ * @returns Promise resolving to the inputmode string, or null if unset.
1271
+ */
1272
+ getInputMode(): Promise<string | null>;
1273
+ /**
1274
+ * Whether the field is in integer-only mode (i.e. `allowDecimals` is false).
1275
+ *
1276
+ * Derived from `inputmode`: number mode renders `numeric` for integers and
1277
+ * `decimal` otherwise. A convenience wrapper so tests need not know that mapping.
1278
+ *
1279
+ * @returns Promise resolving to true when only whole numbers are accepted.
1280
+ */
1281
+ isIntegerOnly(): Promise<boolean>;
1282
+ /**
1283
+ * Gets the `aria-label` (accessible name set via the `ariaLabel` input).
1284
+ *
1285
+ * @returns Promise resolving to the aria-label string, or null if unset.
1286
+ */
1287
+ getAriaLabel(): Promise<string | null>;
1225
1288
  /**
1226
1289
  * Gets the placeholder text.
1227
1290
  *
@@ -2863,6 +2926,10 @@ declare class TnFormFieldComponent implements AfterContentInit {
2863
2926
  required: _angular_core.InputSignal<boolean>;
2864
2927
  testId: _angular_core.InputSignal<string>;
2865
2928
  subscriptSizing: _angular_core.InputSignal<SubscriptSizing>;
2929
+ /** Optional tooltip shown via a help icon next to the label. */
2930
+ tooltip: _angular_core.InputSignal<string>;
2931
+ /** Placement of the tooltip relative to its help icon. */
2932
+ tooltipPosition: _angular_core.InputSignal<TooltipPosition>;
2866
2933
  control: _angular_core.Signal<NgControl | undefined>;
2867
2934
  protected hasError: _angular_core.WritableSignal<boolean>;
2868
2935
  protected errorMessage: _angular_core.WritableSignal<string>;
@@ -2873,7 +2940,7 @@ declare class TnFormFieldComponent implements AfterContentInit {
2873
2940
  showHint: _angular_core.Signal<boolean>;
2874
2941
  protected showSubscript: _angular_core.Signal<boolean>;
2875
2942
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TnFormFieldComponent, never>;
2876
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnFormFieldComponent, "tn-form-field", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "testId": { "alias": "testId"; "required": false; "isSignal": true; }; "subscriptSizing": { "alias": "subscriptSizing"; "required": false; "isSignal": true; }; }, {}, ["control"], ["*"], true, never>;
2943
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnFormFieldComponent, "tn-form-field", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "testId": { "alias": "testId"; "required": false; "isSignal": true; }; "subscriptSizing": { "alias": "subscriptSizing"; "required": false; "isSignal": true; }; "tooltip": { "alias": "tooltip"; "required": false; "isSignal": true; }; "tooltipPosition": { "alias": "tooltipPosition"; "required": false; "isSignal": true; }; }, {}, ["control"], ["*"], true, never>;
2877
2944
  }
2878
2945
 
2879
2946
  /**
@@ -2907,6 +2974,7 @@ declare class TnFormFieldHarness extends ComponentHarness {
2907
2974
  private _label;
2908
2975
  private _error;
2909
2976
  private _hint;
2977
+ private _tooltip;
2910
2978
  /**
2911
2979
  * Gets a `HarnessPredicate` that can be used to search for a form field
2912
2980
  * with specific attributes.
@@ -2975,6 +3043,30 @@ declare class TnFormFieldHarness extends ComponentHarness {
2975
3043
  * ```
2976
3044
  */
2977
3045
  getHint(): Promise<string | null>;
3046
+ /**
3047
+ * Checks whether the form field has a tooltip help icon.
3048
+ *
3049
+ * @returns Promise resolving to true if the tooltip trigger is present.
3050
+ *
3051
+ * @example
3052
+ * ```typescript
3053
+ * const field = await loader.getHarness(TnFormFieldHarness.with({ label: 'Purpose' }));
3054
+ * expect(await field.hasTooltip()).toBe(true);
3055
+ * ```
3056
+ */
3057
+ hasTooltip(): Promise<boolean>;
3058
+ /**
3059
+ * Gets the tooltip message (read from the trigger's accessible label).
3060
+ *
3061
+ * @returns Promise resolving to the tooltip text, or null if no tooltip.
3062
+ *
3063
+ * @example
3064
+ * ```typescript
3065
+ * const field = await loader.getHarness(TnFormFieldHarness.with({ label: 'Purpose' }));
3066
+ * expect(await field.getTooltip()).toBe('What this share is used for');
3067
+ * ```
3068
+ */
3069
+ getTooltip(): Promise<string | null>;
2978
3070
  /**
2979
3071
  * Checks whether the form field is marked as required.
2980
3072
  *