@truenas/ui-components 0.3.5 → 0.3.7

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.3.5",
3
+ "version": "0.3.7",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org",
6
6
  "access": "public"
@@ -2293,30 +2293,54 @@ interface ChipHarnessFilters extends BaseHarnessFilters {
2293
2293
  label?: string | RegExp;
2294
2294
  }
2295
2295
 
2296
+ /**
2297
+ * Option shape for `tn-chip-input`'s value mode — the `label` is displayed on
2298
+ * the chip, the `value` is committed to the form control. Structurally
2299
+ * identical to `TnSelectOption`/`TnAutocompleteOption`, so the same data sources
2300
+ * feed all three.
2301
+ */
2302
+ type TnChipInputOption<T = unknown> = TnSelectOption<T>;
2296
2303
  /**
2297
2304
  * An editable, multi-value chip input — tokenized entry where typed text
2298
2305
  * becomes removable `tn-chip`s alongside an inline text field. Text is
2299
2306
  * committed to a chip on Enter (or a configurable separator key); Backspace on
2300
2307
  * an empty field removes the last chip.
2301
2308
  *
2302
- * It is a `ControlValueAccessor` over `string[]`, so it drops into a reactive
2303
- * or template-driven form (`[formControl]`, `[(ngModel)]`) and slots into a
2304
- * `tn-form-field` as a real projected control — the field's required/error
2305
- * inference reads this control directly.
2309
+ * It is a `ControlValueAccessor` over `T[]` (defaulting to `string[]`), so it
2310
+ * drops into a reactive or template-driven form (`[formControl]`, `[(ngModel)]`)
2311
+ * and slots into a `tn-form-field` as a real projected control — the field's
2312
+ * required/error inference reads this control directly.
2313
+ *
2314
+ * **String mode (default).** Pass `[suggestions]` (a `string[]`) for typeahead;
2315
+ * the typed/picked string is the value. Set `allowCustomValue=false` to restrict
2316
+ * commits to the suggestion list.
2306
2317
  *
2307
- * Suggestions are optional: pass `[suggestions]` for a static list, or drive
2308
- * them asynchronously by listening to `(searchChange)` and updating
2309
- * `[suggestions]` as results arrive. The dropdown is portaled through a CDK
2310
- * overlay so it escapes any ancestor `overflow: hidden` (cards, side panels).
2318
+ * **Value mode.** Pass `[options]` (`{ label, value }[]`) to display labels while
2319
+ * committing values the model becomes `T[]`. A written value resolves to its
2320
+ * option's label (falling back to `String(value)` until the option is
2321
+ * available). Provide `[compareWith]` when the values are objects. Committing a
2322
+ * typed string matches an option by label (case-insensitive); free text that
2323
+ * matches no option is only accepted when `allowCustomValue` is `true` (which is
2324
+ * only sound for string-valued inputs).
2325
+ *
2326
+ * Either source can be driven asynchronously by listening to `(searchChange)`
2327
+ * and updating `[suggestions]`/`[options]` as results arrive. The dropdown is
2328
+ * portaled through a CDK overlay so it escapes any ancestor `overflow: hidden`.
2311
2329
  *
2312
2330
  * @example
2313
2331
  * ```html
2332
+ * <!-- string mode -->
2314
2333
  * <tn-form-field label="Tags">
2315
- * <tn-chip-input [formControl]="tags" placeholder="Add a tag…" />
2334
+ * <tn-chip-input [formControl]="tags" [suggestions]="tagSuggestions" />
2335
+ * </tn-form-field>
2336
+ *
2337
+ * <!-- value mode: shows names, commits ids -->
2338
+ * <tn-form-field label="Groups">
2339
+ * <tn-chip-input [formControl]="groupIds" [options]="groupOptions" [allowCustomValue]="false" />
2316
2340
  * </tn-form-field>
2317
2341
  * ```
2318
2342
  */
2319
- declare class TnChipInputComponent implements ControlValueAccessor, OnDestroy {
2343
+ declare class TnChipInputComponent<T = string> implements ControlValueAccessor, OnDestroy {
2320
2344
  private readonly overlay;
2321
2345
  private readonly viewContainerRef;
2322
2346
  /** Unique instance id for ARIA linkage between the input and its dropdown. */
@@ -2333,21 +2357,43 @@ declare class TnChipInputComponent implements ControlValueAccessor, OnDestroy {
2333
2357
  separatorKeys: _angular_core.InputSignal<string[]>;
2334
2358
  /** Commit a pending (non-empty) text value as a chip when the field loses focus. */
2335
2359
  addOnBlur: _angular_core.InputSignal<boolean>;
2360
+ /**
2361
+ * Whether free text not matching any option/suggestion may be committed.
2362
+ * Defaults to `true` — any typed value becomes a chip. Set `false` to restrict
2363
+ * the field to its list (a "pick from the list" control): a commit only
2364
+ * succeeds when the text matches an option/suggestion label (case-insensitive,
2365
+ * committing the canonical entry); unmatched text is discarded. Mirrors
2366
+ * `tn-autocomplete`'s `allowCustomValue`. In value mode, leave this `false` —
2367
+ * fabricating a typed string as a non-string value is unsound.
2368
+ */
2369
+ allowCustomValue: _angular_core.InputSignal<boolean>;
2336
2370
  /**
2337
2371
  * Allow the same value to be added more than once. Off by default.
2338
- * Duplicate detection is exact-match (case-sensitive), so with this off
2339
- * `Angular` and `angular` are still distinct values — only suggestion
2340
- * *filtering* is case-insensitive.
2372
+ * Duplicate detection uses `compareWith` (or identity); string-mode matching
2373
+ * is exact (case-sensitive), so `Angular` and `angular` are distinct — only
2374
+ * the *filtering* of suggestions is case-insensitive.
2341
2375
  */
2342
2376
  allowDuplicates: _angular_core.InputSignal<boolean>;
2343
2377
  /** Hard cap on the number of chips; `undefined` means no limit. */
2344
2378
  maxChips: _angular_core.InputSignal<number | undefined>;
2345
2379
  /**
2346
- * Optional suggestion list. When non-empty, a dropdown offers entries that
2347
- * match the typed text and are not already selected. For async sources,
2348
- * update this in response to `(searchChange)`.
2380
+ * String-mode suggestion list. When non-empty, a dropdown offers entries that
2381
+ * match the typed text and are not already selected. Ignored when `options`
2382
+ * is provided. For async sources, update this in response to `(searchChange)`.
2349
2383
  */
2350
2384
  suggestions: _angular_core.InputSignal<string[]>;
2385
+ /**
2386
+ * Value-mode option list (`{ label, value }`). When non-empty, chips display
2387
+ * the resolved `label` while the form model holds `value`s. Takes precedence
2388
+ * over `suggestions`. For async sources, update in response to `(searchChange)`.
2389
+ */
2390
+ options: _angular_core.InputSignal<TnChipInputOption<T>[]>;
2391
+ /**
2392
+ * Comparator for value equality — used for de-duplication, display resolution
2393
+ * and the selected-set. Defaults to identity (`===`), correct for primitives;
2394
+ * provide this when values are objects (e.g. `(a, b) => a?.id === b?.id`).
2395
+ */
2396
+ compareWith: _angular_core.InputSignal<((a: T | null, b: T | null) => boolean) | undefined>;
2351
2397
  /** Accessible name for the text field. Leave unset inside a `tn-form-field`. */
2352
2398
  ariaLabel: _angular_core.InputSignal<string | undefined>;
2353
2399
  /**
@@ -2357,9 +2403,9 @@ declare class TnChipInputComponent implements ControlValueAccessor, OnDestroy {
2357
2403
  */
2358
2404
  testId: _angular_core.InputSignal<TnTestIdValue>;
2359
2405
  /** Emits the committed value whenever a chip is added. */
2360
- chipAdded: _angular_core.OutputEmitterRef<string>;
2406
+ chipAdded: _angular_core.OutputEmitterRef<T>;
2361
2407
  /** Emits the removed value whenever a chip is removed. */
2362
- chipRemoved: _angular_core.OutputEmitterRef<string>;
2408
+ chipRemoved: _angular_core.OutputEmitterRef<T>;
2363
2409
  /**
2364
2410
  * Emits the current text as the user types (not on programmatic writes or
2365
2411
  * chip commits). Drive server-side suggestion lookups from this; debounce in
@@ -2370,7 +2416,7 @@ declare class TnChipInputComponent implements ControlValueAccessor, OnDestroy {
2370
2416
  private readonly inputEl;
2371
2417
  private readonly dropdownTemplate;
2372
2418
  /** Committed chip values — the form model. */
2373
- protected values: _angular_core.WritableSignal<string[]>;
2419
+ protected values: _angular_core.WritableSignal<T[]>;
2374
2420
  /** Current text in the field. */
2375
2421
  protected inputValue: _angular_core.WritableSignal<string>;
2376
2422
  /** Whether the suggestion dropdown is open. */
@@ -2385,16 +2431,21 @@ declare class TnChipInputComponent implements ControlValueAccessor, OnDestroy {
2385
2431
  protected isDisabled: _angular_core.Signal<boolean>;
2386
2432
  /** Whether another chip may still be added under `maxChips`. */
2387
2433
  protected canAddMore: _angular_core.Signal<boolean>;
2388
- /** Suggestions that match the typed text and are not already selected. */
2389
- protected filteredSuggestions: _angular_core.Signal<string[]>;
2434
+ /**
2435
+ * Unified option list. Value-mode `options` win; otherwise string-mode
2436
+ * `suggestions` are lifted into `{ label: s, value: s }`.
2437
+ */
2438
+ protected optionList: _angular_core.Signal<TnChipInputOption<T>[]>;
2439
+ /** Options matching the typed text and not already selected. */
2440
+ protected filteredSuggestions: _angular_core.Signal<TnChipInputOption<T>[]>;
2390
2441
  private onChange;
2391
2442
  private onTouched;
2392
2443
  private overlayRef?;
2393
2444
  private overlaySubs;
2394
2445
  constructor();
2395
2446
  ngOnDestroy(): void;
2396
- writeValue(value: string[] | null | undefined): void;
2397
- registerOnChange(fn: (value: string[]) => void): void;
2447
+ writeValue(value: T[] | null | undefined): void;
2448
+ registerOnChange(fn: (value: T[]) => void): void;
2398
2449
  registerOnTouched(fn: () => void): void;
2399
2450
  setDisabledState(isDisabled: boolean): void;
2400
2451
  /** Clicking anywhere in the container focuses the text field. */
@@ -2403,19 +2454,26 @@ declare class TnChipInputComponent implements ControlValueAccessor, OnDestroy {
2403
2454
  protected onFocus(): void;
2404
2455
  protected onBlur(): void;
2405
2456
  protected onKeydown(event: KeyboardEvent): void;
2406
- protected onSuggestionClick(suggestion: string): void;
2457
+ protected onSuggestionClick(option: TnChipInputOption<T>): void;
2407
2458
  /** Prevents the option `mousedown` from blurring the input before the click lands. */
2408
2459
  protected onSuggestionMousedown(event: MouseEvent): void;
2409
2460
  protected removeChip(index: number): void;
2461
+ /** The label shown on a chip for a committed value. */
2462
+ protected displayLabel(value: T): string;
2410
2463
  /** Scopes a per-chip test id beneath the component's base. */
2411
- protected chipTestId(value: string): TnTestIdValue;
2464
+ protected chipTestId(value: T): TnTestIdValue;
2412
2465
  private isCommitKey;
2413
- private addChip;
2466
+ /** Commits typed text: resolve it to an option's value, else accept as custom. */
2467
+ private commitText;
2468
+ /** Commits a resolved value, honouring duplicate and cap rules. */
2469
+ private commitValue;
2470
+ private valuesIncludes;
2471
+ private valueMatches;
2414
2472
  private clearInput;
2415
2473
  /**
2416
2474
  * Opens the dropdown when there is something to show, closes it otherwise.
2417
2475
  * Stays closed once the chip cap is reached — suggesting rows that
2418
- * `addChip()` would reject is misleading.
2476
+ * `commitValue()` would reject is misleading.
2419
2477
  */
2420
2478
  private syncDropdown;
2421
2479
  /** Keeps the keyboard-highlighted suggestion visible within the scrolling panel. */
@@ -2424,8 +2482,8 @@ declare class TnChipInputComponent implements ControlValueAccessor, OnDestroy {
2424
2482
  private close;
2425
2483
  private attachOverlay;
2426
2484
  private detachOverlay;
2427
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<TnChipInputComponent, never>;
2428
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnChipInputComponent, "tn-chip-input", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "separatorKeys": { "alias": "separatorKeys"; "required": false; "isSignal": true; }; "addOnBlur": { "alias": "addOnBlur"; "required": false; "isSignal": true; }; "allowDuplicates": { "alias": "allowDuplicates"; "required": false; "isSignal": true; }; "maxChips": { "alias": "maxChips"; "required": false; "isSignal": true; }; "suggestions": { "alias": "suggestions"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "testId": { "alias": "testId"; "required": false; "isSignal": true; }; }, { "chipAdded": "chipAdded"; "chipRemoved": "chipRemoved"; "searchChange": "searchChange"; }, never, never, true, never>;
2485
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TnChipInputComponent<any>, never>;
2486
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnChipInputComponent<any>, "tn-chip-input", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "separatorKeys": { "alias": "separatorKeys"; "required": false; "isSignal": true; }; "addOnBlur": { "alias": "addOnBlur"; "required": false; "isSignal": true; }; "allowCustomValue": { "alias": "allowCustomValue"; "required": false; "isSignal": true; }; "allowDuplicates": { "alias": "allowDuplicates"; "required": false; "isSignal": true; }; "maxChips": { "alias": "maxChips"; "required": false; "isSignal": true; }; "suggestions": { "alias": "suggestions"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "compareWith": { "alias": "compareWith"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "testId": { "alias": "testId"; "required": false; "isSignal": true; }; }, { "chipAdded": "chipAdded"; "chipRemoved": "chipRemoved"; "searchChange": "searchChange"; }, never, never, true, never>;
2429
2487
  }
2430
2488
 
2431
2489
  /**
@@ -8291,4 +8349,4 @@ declare const TN_THEME_DEFINITIONS: readonly TnThemeDefinition[];
8291
8349
  declare const THEME_MAP: Map<TnTheme, TnThemeDefinition>;
8292
8350
 
8293
8351
  export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, InputType, LIGHT_THEME, LabelMarkupPipe, LabelTextPipe, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, StripMntPrefixPipe, THEME_MAP, THEME_STORAGE_KEY, TN_FORM_FIELD_ERRORS, TN_TABLE_PAGER_DEFAULT_LABELS, TN_TABLE_PAGER_LABELS, TN_TEST_ATTR, TN_THEME_DEFINITIONS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarComponent, TnCalendarHeaderComponent, TnCardComponent, TnCardFooterActionsDirective, TnCardHeaderActionsDirective, TnCardHeaderDirective, TnCellDefDirective, TnCheckboxComponent, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnChipHarness, TnChipInputComponent, TnChipInputHarness, TnConfirmDialogComponent, TnDateInputComponent, TnDateInputHarness, TnDateRangeInputComponent, TnDateRangeInputHarness, TnDetailRowDefDirective, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFilePickerComponent, TnFilePickerPopupComponent, TnFormFieldComponent, TnFormFieldHarness, TnFormSectionComponent, TnFormSectionHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuItemComponent, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioHarness, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTableHarness, TnTablePagerComponent, TnTablePagerHarness, TnTabsComponent, TnTabsHarness, TnTestIdDirective, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeNodeComponent, TnTreeNodeOutletDirective, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, composeTestId, createLucideLibrary, createShortcut, defaultSpriteBasePath, defaultSpriteConfigPath, formatSize, kebabTestSegment, labelMarkupToHtml, labelMarkupToText, libIconMarker, parseLabelMarkup, parseSize, registerLucideIcons, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
8294
- export type { AutocompleteHarnessFilters, BannerHarnessFilters, ButtonHarnessFilters, ButtonToggleHarnessFilters, CalendarCell, CheckboxHarnessFilters, ChipColor, ChipHarnessFilters, CreateFolderEvent, DateInputHarnessFilters, DateRange, DateRangeInputHarnessFilters, DialogHarnessFilters, EmptyHarnessFilters, ExpansionPanelHarnessFilters, FilePickerCallbacks, FilePickerError, FilePickerMode, FileSystemItem, FormFieldHarnessFilters, FormSectionHarnessFilters, IconButtonHarnessFilters, IconHarnessFilters, IconLibrary, IconLibraryType, IconResult, IconSize, IconSource, IconTestingMockOverrides, InputHarnessFilters, KeyCombination, LabelMarkupSegment, LabelMarkupSegmentType, LabelType, LucideIconOptions, MenuHarnessFilters, MockIconRegistry, MockSpriteLoader, PathSegment, PlatformType, ProgressBarMode, RadioHarnessFilters, ResolvedIcon, SelectHarnessFilters, ShortcutHandler, SidePanelHarnessFilters, SizeStandard, SlideToggleColor, SlideToggleHarnessFilters, SpinnerMode, SpriteConfig, SubscriptSizing, TabChangeEvent, TabHarnessFilters, TabPanelHarnessFilters, TabsHarnessFilters, TnAutocompleteOption, TnBannerType, TnButtonToggleType, TnCardAction, TnCardControl, TnCardFooterLink, TnCardHeaderStatus, TnChipInputHarnessFilters, TnConfirmDialogData, TnDialogDefaults, TnDialogOpenTarget, TnDrawerMode, TnDrawerPosition, TnEmptySize, TnFlatTreeNode, TnFormFieldErrorMessage, TnFormFieldErrorMessages, TnFormFieldErrorResolver, TnMenuItem, TnSelectOption, TnSelectOptionGroup, TnSelectionChange, TnSortEvent, TnTableDataProvider, TnTableDataSource, TnTableHarnessFilters, TnTablePagerHarnessFilters, TnTablePagerLabels, TnTablePagination, TnTestAttrName, TnTestIdValue, TnThemeDefinition, TnToastCall, TnToastConfig, TooltipPosition, YearCell };
8352
+ export type { AutocompleteHarnessFilters, BannerHarnessFilters, ButtonHarnessFilters, ButtonToggleHarnessFilters, CalendarCell, CheckboxHarnessFilters, ChipColor, ChipHarnessFilters, CreateFolderEvent, DateInputHarnessFilters, DateRange, DateRangeInputHarnessFilters, DialogHarnessFilters, EmptyHarnessFilters, ExpansionPanelHarnessFilters, FilePickerCallbacks, FilePickerError, FilePickerMode, FileSystemItem, FormFieldHarnessFilters, FormSectionHarnessFilters, IconButtonHarnessFilters, IconHarnessFilters, IconLibrary, IconLibraryType, IconResult, IconSize, IconSource, IconTestingMockOverrides, InputHarnessFilters, KeyCombination, LabelMarkupSegment, LabelMarkupSegmentType, LabelType, LucideIconOptions, MenuHarnessFilters, MockIconRegistry, MockSpriteLoader, PathSegment, PlatformType, ProgressBarMode, RadioHarnessFilters, ResolvedIcon, SelectHarnessFilters, ShortcutHandler, SidePanelHarnessFilters, SizeStandard, SlideToggleColor, SlideToggleHarnessFilters, SpinnerMode, SpriteConfig, SubscriptSizing, TabChangeEvent, TabHarnessFilters, TabPanelHarnessFilters, TabsHarnessFilters, TnAutocompleteOption, TnBannerType, TnButtonToggleType, TnCardAction, TnCardControl, TnCardFooterLink, TnCardHeaderStatus, TnChipInputHarnessFilters, TnChipInputOption, TnConfirmDialogData, TnDialogDefaults, TnDialogOpenTarget, TnDrawerMode, TnDrawerPosition, TnEmptySize, TnFlatTreeNode, TnFormFieldErrorMessage, TnFormFieldErrorMessages, TnFormFieldErrorResolver, TnMenuItem, TnSelectOption, TnSelectOptionGroup, TnSelectionChange, TnSortEvent, TnTableDataProvider, TnTableDataSource, TnTableHarnessFilters, TnTablePagerHarnessFilters, TnTablePagerLabels, TnTablePagination, TnTestAttrName, TnTestIdValue, TnThemeDefinition, TnToastCall, TnToastConfig, TooltipPosition, YearCell };