@radix-ng/primitives 1.0.10 → 1.1.1

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.
Files changed (65) hide show
  1. package/README.md +26 -5
  2. package/fesm2022/radix-ng-primitives-autocomplete.mjs +88 -21
  3. package/fesm2022/radix-ng-primitives-autocomplete.mjs.map +1 -1
  4. package/fesm2022/radix-ng-primitives-checkbox.mjs +199 -129
  5. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  6. package/fesm2022/radix-ng-primitives-combobox.mjs +203 -52
  7. package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -1
  8. package/fesm2022/radix-ng-primitives-composite.mjs +221 -36
  9. package/fesm2022/radix-ng-primitives-composite.mjs.map +1 -1
  10. package/fesm2022/radix-ng-primitives-core.mjs +352 -24
  11. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  12. package/fesm2022/radix-ng-primitives-date-field.mjs +11 -5
  13. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  14. package/fesm2022/radix-ng-primitives-field.mjs +127 -23
  15. package/fesm2022/radix-ng-primitives-field.mjs.map +1 -1
  16. package/fesm2022/radix-ng-primitives-form.mjs +35 -4
  17. package/fesm2022/radix-ng-primitives-form.mjs.map +1 -1
  18. package/fesm2022/radix-ng-primitives-input.mjs +87 -15
  19. package/fesm2022/radix-ng-primitives-input.mjs.map +1 -1
  20. package/fesm2022/radix-ng-primitives-menu.mjs +34 -7
  21. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  22. package/fesm2022/radix-ng-primitives-number-field.mjs +38 -7
  23. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
  24. package/fesm2022/radix-ng-primitives-popper.mjs +80 -11
  25. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  26. package/fesm2022/radix-ng-primitives-radio.mjs +49 -2
  27. package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
  28. package/fesm2022/radix-ng-primitives-scroll-area.mjs +6 -3
  29. package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -1
  30. package/fesm2022/radix-ng-primitives-select.mjs +70 -14
  31. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  32. package/fesm2022/radix-ng-primitives-signal-forms.mjs +27 -11
  33. package/fesm2022/radix-ng-primitives-signal-forms.mjs.map +1 -1
  34. package/fesm2022/radix-ng-primitives-slider.mjs +17 -2
  35. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  36. package/fesm2022/radix-ng-primitives-switch.mjs +60 -7
  37. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  38. package/fesm2022/radix-ng-primitives-time-field.mjs +12 -6
  39. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  40. package/fesm2022/radix-ng-primitives-toggle-group.mjs +25 -3
  41. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  42. package/package.json +8 -3
  43. package/types/radix-ng-primitives-autocomplete.d.ts +16 -2
  44. package/types/radix-ng-primitives-checkbox.d.ts +66 -44
  45. package/types/radix-ng-primitives-combobox.d.ts +74 -3
  46. package/types/radix-ng-primitives-composite.d.ts +48 -2
  47. package/types/radix-ng-primitives-core.d.ts +212 -96
  48. package/types/radix-ng-primitives-date-field.d.ts +7 -4
  49. package/types/radix-ng-primitives-field.d.ts +55 -8
  50. package/types/radix-ng-primitives-form.d.ts +9 -0
  51. package/types/radix-ng-primitives-input.d.ts +10 -2
  52. package/types/radix-ng-primitives-menu.d.ts +45 -4
  53. package/types/radix-ng-primitives-navigation-menu.d.ts +2 -2
  54. package/types/radix-ng-primitives-number-field.d.ts +12 -5
  55. package/types/radix-ng-primitives-popover.d.ts +2 -2
  56. package/types/radix-ng-primitives-popper.d.ts +60 -15
  57. package/types/radix-ng-primitives-preview-card.d.ts +2 -2
  58. package/types/radix-ng-primitives-radio.d.ts +6 -1
  59. package/types/radix-ng-primitives-select.d.ts +25 -4
  60. package/types/radix-ng-primitives-signal-forms.d.ts +22 -8
  61. package/types/radix-ng-primitives-slider.d.ts +2 -1
  62. package/types/radix-ng-primitives-switch.d.ts +19 -3
  63. package/types/radix-ng-primitives-time-field.d.ts +9 -6
  64. package/types/radix-ng-primitives-toggle-group.d.ts +5 -1
  65. package/types/radix-ng-primitives-tooltip.d.ts +2 -2
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { inject, model, signal, computed, ElementRef, input, booleanAttribute, output, effect, untracked, Directive, InjectionToken, Injector, DestroyRef, afterNextRender, linkedSignal, contentChild, forwardRef, isDevMode } from '@angular/core';
3
3
  import * as i3 from '@radix-ng/primitives/core';
4
- import { isEqual, getActiveElement, formUiStateContext, createContext, RdxFormUiControlBase, injectId, createFloatingRootContext, useTransitionStatus, isNullish, createCancelableChangeEventDetails, provideFloatingTree, provideFloatingRootContext, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useListHighlight, useAnchoredScrollLock, RdxFloatingNodeRegistration, handleAndDispatchCustomEvent, resizeEffect, clamp, rdxDevError, setupInternalBackdrop, provideExistingToken } from '@radix-ng/primitives/core';
4
+ import { isEqual, getActiveElement, formUiStateContext, createContext, RdxFormUiControlBase, injectId, createFloatingRootContext, useTransitionStatus, isNullish, useNativeFormControl, serializeNativeFormValue, createCancelableChangeEventDetails, provideValueAccessor, provideFloatingTree, provideFloatingRootContext, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useListHighlight, useAnchoredScrollLock, RdxFloatingNodeRegistration, handleAndDispatchCustomEvent, resizeEffect, clamp, rdxDevError, setupInternalBackdrop, provideExistingToken, itemToStringLabel } from '@radix-ng/primitives/core';
5
5
  import { injectDirection } from '@radix-ng/primitives/direction-provider';
6
6
  import * as i2 from '@radix-ng/primitives/floating-focus-manager';
7
7
  import { getInteractionTypeFromEvent, provideFloatingFocusManagerConfig, RdxFloatingFocusManager, createRdxTriggerInteraction } from '@radix-ng/primitives/floating-focus-manager';
@@ -70,7 +70,7 @@ const context$2 = () => {
70
70
  openInteractionType: context.openInteractionType,
71
71
  closeInteractionType: context.closeInteractionType,
72
72
  ...formUiStateContext(context.formUi),
73
- disabled: context.disabled,
73
+ disabled: context.disabledState,
74
74
  readOnly: context.readOnly,
75
75
  required: context.required,
76
76
  modal: context.modal,
@@ -134,10 +134,20 @@ class RdxSelectRoot extends RdxFormUiControlBase {
134
134
  this.defaultOpen = input(false, { ...(ngDevMode ? { debugName: "defaultOpen" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
135
135
  this.multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
136
136
  this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
137
+ this.cvaDisabled = signal(false, /* @ts-ignore */
138
+ ...(ngDevMode ? [{ debugName: "cvaDisabled" }] : /* istanbul ignore next */ []));
139
+ this.disabledState = computed(() => this.disabled() || this.cvaDisabled(), /* @ts-ignore */
140
+ ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
137
141
  /** When `true`, the value cannot be changed by the user (the popup can still be opened to view it). */
138
142
  this.readOnly = input(false, { ...(ngDevMode ? { debugName: "readOnly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
139
143
  /** Marks the control as required — reflected on the trigger as `aria-required` / `data-required`. */
140
144
  this.required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
145
+ /** Name used when serializing this composite control into native `FormData`. */
146
+ this.name = input(/* @ts-ignore */
147
+ ...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
148
+ /** Id of an external form that owns this control. */
149
+ this.form = input(/* @ts-ignore */
150
+ ...(ngDevMode ? [undefined, { debugName: "form" }] : /* istanbul ignore next */ []));
141
151
  /** Whether the popup is modal: locks page scroll and makes outside content inert while open. */
142
152
  this.modal = input(true, { ...(ngDevMode ? { debugName: "modal" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
143
153
  this.dirInput = input(undefined, { ...(ngDevMode ? { debugName: "dirInput" } : /* istanbul ignore next */ {}), alias: 'dir' });
@@ -148,6 +158,9 @@ class RdxSelectRoot extends RdxFormUiControlBase {
148
158
  /** Converts a value to its display label (used by `RdxSelectValue`). */
149
159
  this.itemToStringLabel = input(/* @ts-ignore */
150
160
  ...(ngDevMode ? [undefined, { debugName: "itemToStringLabel" }] : /* istanbul ignore next */ []));
161
+ /** Converts an item value to the string submitted by a native form. */
162
+ this.itemToStringValue = input(/* @ts-ignore */
163
+ ...(ngDevMode ? [undefined, { debugName: "itemToStringValue" }] : /* istanbul ignore next */ []));
151
164
  /** Emits before an open-state change is committed; call `eventDetails.cancel()` to veto it. */
152
165
  this.onOpenChange = output();
153
166
  /** Emits before a value change is committed; call `eventDetails.cancel()` to veto it. */
@@ -169,6 +182,29 @@ class RdxSelectRoot extends RdxFormUiControlBase {
169
182
  ...(ngDevMode ? [{ debugName: "isEmptyModelValue" }] : /* istanbul ignore next */ []));
170
183
  this.hasAppliedDefaultValue = false;
171
184
  this.hasAppliedDefaultOpen = false;
185
+ this.nativeFormControl = useNativeFormControl({
186
+ name: this.name,
187
+ form: this.form,
188
+ disabled: this.disabledState,
189
+ value: this.value,
190
+ serialize: (value) => {
191
+ const itemToStringValue = this.itemToStringValue();
192
+ return itemToStringValue
193
+ ? serializeNativeFormValue(value, (entry) => itemToStringValue(entry))
194
+ : serializeNativeFormValue(value);
195
+ },
196
+ defaultValue: () => {
197
+ const defaultValue = this.defaultValue();
198
+ return defaultValue === undefined ? this.value() : defaultValue;
199
+ },
200
+ onReset: (value) => {
201
+ this.value.set(value);
202
+ if (!this.resetNgControl(value)) {
203
+ this.onChange?.(value);
204
+ }
205
+ this.formUi.resetInteractionState?.();
206
+ }
207
+ });
172
208
  this.optionsSet = signal(new Set(), /* @ts-ignore */
173
209
  ...(ngDevMode ? [{ debugName: "optionsSet" }] : /* istanbul ignore next */ []));
174
210
  // The native `select` only associates the correct default value if the corresponding
@@ -197,7 +233,9 @@ class RdxSelectRoot extends RdxFormUiControlBase {
197
233
  const defaultValue = this.defaultValue();
198
234
  if (!this.hasAppliedDefaultValue && defaultValue !== undefined) {
199
235
  this.hasAppliedDefaultValue = true;
200
- this.value.set(defaultValue);
236
+ if (untracked(this.value) === undefined) {
237
+ this.value.set(defaultValue);
238
+ }
201
239
  }
202
240
  });
203
241
  effect(() => {
@@ -237,7 +275,7 @@ class RdxSelectRoot extends RdxFormUiControlBase {
237
275
  return Array.from(this.optionsSet()).find((option) => valueComparator(value, option.value, this.isItemEqualToValue()));
238
276
  }
239
277
  setValue(value, reason = 'none', event = new Event('select.value-change')) {
240
- if (this.readOnly()) {
278
+ if (this.disabledState() || this.readOnly()) {
241
279
  return false;
242
280
  }
243
281
  const nextValue = this.multiple()
@@ -259,6 +297,7 @@ class RdxSelectRoot extends RdxFormUiControlBase {
259
297
  }
260
298
  this.value.set(nextValue);
261
299
  this.formUi.markDirty();
300
+ this.onChange?.(nextValue);
262
301
  return true;
263
302
  }
264
303
  setOpen(open, reason = 'none', event) {
@@ -279,8 +318,29 @@ class RdxSelectRoot extends RdxFormUiControlBase {
279
318
  }
280
319
  return true;
281
320
  }
321
+ /** @ignore Bridge the CVA touched callback into the shared Signal Forms UI-state path. */
322
+ formUiTouchTarget() {
323
+ return { markAsTouched: () => this.onTouched?.() };
324
+ }
325
+ /** @ignore Write a form-owned value without emitting a user change. */
326
+ writeValue(value) {
327
+ untracked(() => this.value.set(value));
328
+ }
329
+ /** @ignore Register the Reactive Forms / ngModel value callback. */
330
+ registerOnChange(fn) {
331
+ this.onChange = fn;
332
+ }
333
+ /** @ignore Register the Reactive Forms / ngModel touched callback. */
334
+ registerOnTouched(fn) {
335
+ this.onTouched = fn;
336
+ }
337
+ /** @ignore Merge form-owned disabled state with the public disabled input. */
338
+ setDisabledState(isDisabled) {
339
+ this.cvaDisabled.set(isDisabled);
340
+ }
282
341
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxSelectRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
283
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxSelectRoot, isStandalone: true, selector: "[rdxSelectRoot]", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, dirInput: { classPropertyName: "dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, isItemEqualToValue: { classPropertyName: "isItemEqualToValue", publicName: "isItemEqualToValue", isSignal: true, isRequired: false, transformFunction: null }, itemToStringLabel: { classPropertyName: "itemToStringLabel", publicName: "itemToStringLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", value: "valueChange", onOpenChange: "onOpenChange", onValueChange: "onValueChange", onOpenChangeComplete: "onOpenChangeComplete" }, providers: [
342
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxSelectRoot, isStandalone: true, selector: "[rdxSelectRoot]", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, dirInput: { classPropertyName: "dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, isItemEqualToValue: { classPropertyName: "isItemEqualToValue", publicName: "isItemEqualToValue", isSignal: true, isRequired: false, transformFunction: null }, itemToStringLabel: { classPropertyName: "itemToStringLabel", publicName: "itemToStringLabel", isSignal: true, isRequired: false, transformFunction: null }, itemToStringValue: { classPropertyName: "itemToStringValue", publicName: "itemToStringValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", value: "valueChange", onOpenChange: "onOpenChange", onValueChange: "onValueChange", onOpenChangeComplete: "onOpenChangeComplete" }, providers: [
343
+ provideValueAccessor(RdxSelectRoot),
284
344
  provideSelectRootContext(context$2),
285
345
  // New floating foundation (ADR 0015/0017) — the dismissal capability reads this shared context.
286
346
  provideFloatingTree(),
@@ -293,6 +353,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
293
353
  selector: '[rdxSelectRoot]',
294
354
  exportAs: 'rdxSelectRoot',
295
355
  providers: [
356
+ provideValueAccessor(RdxSelectRoot),
296
357
  provideSelectRootContext(context$2),
297
358
  // New floating foundation (ADR 0015/0017) — the dismissal capability reads this shared context.
298
359
  provideFloatingTree(),
@@ -300,7 +361,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
300
361
  ],
301
362
  hostDirectives: [RdxPopper]
302
363
  }]
303
- }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], defaultValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValue", required: false }] }], defaultOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultOpen", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], isItemEqualToValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "isItemEqualToValue", required: false }] }], itemToStringLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemToStringLabel", required: false }] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
364
+ }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], defaultValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValue", required: false }] }], defaultOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultOpen", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], isItemEqualToValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "isItemEqualToValue", required: false }] }], itemToStringLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemToStringLabel", required: false }] }], itemToStringValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemToStringValue", required: false }] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
304
365
 
305
366
  /**
306
367
  * An overlay rendered beneath the popup in `modal` mode. Place it inside the portal/presence; style
@@ -1514,14 +1575,12 @@ class RdxSelectTrigger {
1514
1575
  disabled: () => this.isDisabled(),
1515
1576
  contentId: () => this.rootContext.contentId
1516
1577
  });
1517
- this.invalidState = computed(() => this.rootContext.invalidState() || Boolean(this.fieldRootContext?.invalidState()), /* @ts-ignore */
1518
- ...(ngDevMode ? [{ debugName: "invalidState" }] : /* istanbul ignore next */ []));
1519
1578
  /**
1520
1579
  * Tri-state *displayed* validity: when inside a `rdxFieldRoot` the field's gated `validState` is the
1521
1580
  * single source (so the field's `validationMode` keeps the trigger neutral until revealed), otherwise
1522
1581
  * the trigger's own binary invalidity.
1523
1582
  */
1524
- this.displayValid = computed(() => this.fieldRootContext ? this.fieldRootContext.validState() : this.invalidState() ? false : true, /* @ts-ignore */
1583
+ this.displayValid = computed(() => this.fieldRootContext ? this.fieldRootContext.validState() : this.rootContext.validState(), /* @ts-ignore */
1525
1584
  ...(ngDevMode ? [{ debugName: "displayValid" }] : /* istanbul ignore next */ []));
1526
1585
  this.requiredState = computed(() => this.rootContext.required() || Boolean(this.fieldRootContext?.requiredState()), /* @ts-ignore */
1527
1586
  ...(ngDevMode ? [{ debugName: "requiredState" }] : /* istanbul ignore next */ []));
@@ -1539,10 +1598,7 @@ class RdxSelectTrigger {
1539
1598
  if (!this.fieldRootContext) {
1540
1599
  return undefined;
1541
1600
  }
1542
- const ids = [
1543
- ...this.fieldRootContext.descriptionIds(),
1544
- ...(this.fieldRootContext.invalidState() ? this.fieldRootContext.errorIds() : [])
1545
- ];
1601
+ const ids = [...this.fieldRootContext.descriptionIds(), ...this.fieldRootContext.errorIds()];
1546
1602
  return ids.length ? ids.join(' ') : undefined;
1547
1603
  }, /* @ts-ignore */
1548
1604
  ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
@@ -1680,7 +1736,7 @@ class RdxSelectValue {
1680
1736
  return customLabel(value);
1681
1737
  }
1682
1738
  const option = options.find((o) => valueComparator(value, o.value, this.rootContext.isItemEqualToValue()));
1683
- return option?.textContent ?? '';
1739
+ return option?.textContent ?? itemToStringLabel(value);
1684
1740
  };
1685
1741
  const value = this.rootContext.value();
1686
1742
  const list = Array.isArray(value) ? value.map((v) => labelFor(v)) : [labelFor(value)];