@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,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Directive, signal, computed, untracked, effect, inject, booleanAttribute, Injector, ElementRef, model, input, numberAttribute, output, isDevMode, DestroyRef, ChangeDetectionStrategy, Component, afterNextRender, afterRenderEffect, NgModule } from '@angular/core';
2
+ import { Directive, computed, signal, untracked, effect, inject, booleanAttribute, Injector, ElementRef, model, input, numberAttribute, output, isDevMode, DestroyRef, ChangeDetectionStrategy, Component, afterNextRender, afterRenderEffect, NgModule } from '@angular/core';
3
3
  import * as i1 from '@radix-ng/primitives/popper';
4
4
  import { RdxPopperAnchor, RdxPopperArrow, RdxPopper, RdxPopperContentWrapper, provideRdxPopperContentWrapper, provideRdxPopperContentConfig, DROPDOWN_COLLISION_AVOIDANCE, injectPopperContentWrapperContext, RdxPopperContent } from '@radix-ng/primitives/popper';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
6
  import * as i2 from '@radix-ng/primitives/core';
7
- import { useFilter, injectId, useListHighlight, useTransitionStatus, createContext, RdxFormUiControlBase, createFloatingRootContext, isItemEqualToValue, isNullish, createCancelableChangeEventDetails, itemToStringLabel, provideFloatingTree, provideFloatingRootContext, setupInternalBackdrop, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useAnchoredScrollLock, RdxFloatingNodeRegistration, rdxDevError } from '@radix-ng/primitives/core';
7
+ import { useFilter, injectId, useListHighlight, useTransitionStatus, createContext, RdxFormUiControlBase, createFloatingRootContext, useNativeFormControl, serializeNativeFormValue, isItemEqualToValue, isNullish, createCancelableChangeEventDetails, itemToStringLabel, provideFloatingTree, provideFloatingRootContext, setupInternalBackdrop, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useAnchoredScrollLock, RdxFloatingNodeRegistration, rdxDevError } from '@radix-ng/primitives/core';
8
8
  import { injectDirection } from '@radix-ng/primitives/direction-provider';
9
9
  import * as i1$1 from '@radix-ng/primitives/dismissable-layer';
10
10
  import { RdxFloatingInsideElement, RdxDismiss } from '@radix-ng/primitives/dismissable-layer';
@@ -66,7 +66,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
66
66
  */
67
67
  function useComboboxEngine(config) {
68
68
  const { injector } = config;
69
- const defaultFilter = useFilter();
69
+ // Locale-aware default filter. A `computed` so changing `locale` rebuilds the collator and
70
+ // re-filters the list — mirrors Base UI, where `useFilter({ locale })` re-memoizes on change.
71
+ const defaultFilter = computed(() => useFilter({ locale: config.locale() }), /* @ts-ignore */
72
+ ...(ngDevMode ? [{ debugName: "defaultFilter" }] : /* istanbul ignore next */ []));
70
73
  const listId = injectId(config.listIdPrefix);
71
74
  const labelId = signal(undefined, /* @ts-ignore */
72
75
  ...(ngDevMode ? [{ debugName: "labelId" }] : /* istanbul ignore next */ []));
@@ -95,34 +98,58 @@ function useComboboxEngine(config) {
95
98
  // Tracks whether the last interaction was the keyboard, so the highlight doesn't jump to an item
96
99
  // the cursor happens to rest on when arrow-key navigation scrolls the list under a still pointer.
97
100
  let keyboardActive = false;
98
- const _items = signal([], /* @ts-ignore */
99
- ...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
101
+ // Keep registrations in a stable map. Copying the growing array on every item mount/unmount makes
102
+ // registering N options O(n²) before filtering or DOM-order sorting even begins. The numeric tick is
103
+ // only the reactive invalidation channel; Angular batches the registrations from one render, so
104
+ // `orderedItems` materializes and sorts the final collection once for that batch. This is the same
105
+ // stable-map pattern used by Base UI and our CompositeList.
106
+ const itemRegistry = new Map();
107
+ const itemRegistryTick = signal(0, /* @ts-ignore */
108
+ ...(ngDevMode ? [{ debugName: "itemRegistryTick" }] : /* istanbul ignore next */ []));
100
109
  const orderedItems = computed(() => {
101
- const items = [..._items()];
102
- return items.sort((a, b) => domOrder(a.element, b.element));
110
+ itemRegistryTick();
111
+ return [...itemRegistry.values()]
112
+ .filter((item) => item.element.isConnected)
113
+ .sort((a, b) => domOrder(a.element, b.element));
103
114
  }, /* @ts-ignore */
104
115
  ...(ngDevMode ? [{ debugName: "orderedItems" }] : /* istanbul ignore next */ []));
105
- const matchesFilter = (item) => {
116
+ const visibleItems = computed(() => {
117
+ const items = orderedItems();
118
+ const limit = config.limit();
119
+ if (limit === 0) {
120
+ return [];
121
+ }
122
+ // Read root signals once per query, not once per item. The early paths also avoid
123
+ // allocating/filtering when every registered item is known to be visible.
106
124
  if (!config.filteringEnabled()) {
107
- return true;
125
+ return limit >= 0 ? items.slice(0, limit) : items;
108
126
  }
109
127
  const filter = config.filter();
110
128
  if (filter === null) {
111
- return true;
129
+ return limit >= 0 ? items.slice(0, limit) : items;
112
130
  }
113
131
  const query = config.query();
114
- // Custom filter: Base UI shape `(value, query, itemToString)`. Default: locale-aware contains
115
- // on the item's own text (the element content), no value→text round-trip.
116
- return filter
117
- ? filter(item.value(), query, config.itemToString)
118
- : defaultFilter.contains(item.textValue(), query);
119
- };
120
- const visibleItems = computed(() => {
121
- const matching = orderedItems().filter((item) => matchesFilter(item));
122
- const limit = config.limit();
123
- return limit >= 0 ? matching.slice(0, limit) : matching;
124
- }, /* @ts-ignore */
125
- ...(ngDevMode ? [{ debugName: "visibleItems" }] : /* istanbul ignore next */ []));
132
+ if (!filter && query.length === 0) {
133
+ return limit >= 0 ? items.slice(0, limit) : items;
134
+ }
135
+ const matching = [];
136
+ const contains = filter ? null : defaultFilter().contains;
137
+ for (const item of items) {
138
+ // Custom filter: Base UI shape `(value, query, itemToString)`. Default: locale-aware
139
+ // contains on the item's own text (the element content), no value→text round-trip.
140
+ const matches = filter
141
+ ? filter(item.value(), query, config.itemToString)
142
+ : contains(item.textValue(), query);
143
+ if (!matches) {
144
+ continue;
145
+ }
146
+ matching.push(item);
147
+ if (limit >= 0 && matching.length >= limit) {
148
+ break;
149
+ }
150
+ }
151
+ return matching;
152
+ }, { ...(ngDevMode ? { debugName: "visibleItems" } : /* istanbul ignore next */ {}), equal: sameItemOrder });
126
153
  const visibleSet = computed(() => new Set(visibleItems()), /* @ts-ignore */
127
154
  ...(ngDevMode ? [{ debugName: "visibleSet" }] : /* istanbul ignore next */ []));
128
155
  const isVisible = (item) => visibleSet().has(item);
@@ -147,7 +174,7 @@ function useComboboxEngine(config) {
147
174
  // Virtualized: no DOM to read text from, so resolve each value through `itemToString`.
148
175
  return cap(data.filter((value) => filter
149
176
  ? filter(value, query, config.itemToString)
150
- : defaultFilter.contains(config.itemToString(value), query)));
177
+ : defaultFilter().contains(config.itemToString(value), query)));
151
178
  }, /* @ts-ignore */
152
179
  ...(ngDevMode ? [{ debugName: "filteredItems" }] : /* istanbul ignore next */ []));
153
180
  const visibleCount = computed(() => (config.virtualized() ? filteredItems().length : visibleItems().length), /* @ts-ignore */
@@ -221,7 +248,13 @@ function useComboboxEngine(config) {
221
248
  };
222
249
  const recomputeInlinePreview = (label, query, reason) => {
223
250
  // Pointer hover must not rewrite the input (matches Base UI); only typing / keyboard nav complete it.
224
- if (!config.inlineMode() || suppressInline || !label || reason === 'pointer') {
251
+ if (!config.inlineMode() || !label || reason === 'pointer') {
252
+ inlinePreview.set(null);
253
+ return;
254
+ }
255
+ // Suppression belongs to the current edit only. Explicit keyboard navigation starts a new
256
+ // interaction and must still mirror the navigated label after a delete/cut edit.
257
+ if (suppressInline && reason !== 'keyboard') {
225
258
  inlinePreview.set(null);
226
259
  return;
227
260
  }
@@ -313,11 +346,14 @@ function useComboboxEngine(config) {
313
346
  pendingHighlightEdge.set(null);
314
347
  });
315
348
  }, { injector });
316
- // Inline completion: mirror the active item's label into the input. Tracks the DOM-ref highlight,
317
- // the virtualized index, the query, the reason, and `inlineMode` so virtualized navigation and a
318
- // `both → list` mode switch both recompute (and clear) the preview. No-op (null) when off (combobox).
349
+ // Inline completion: mirror the active item's label into the input. When inline mode is off, stop
350
+ // before reading query/highlight state so Combobox and list-mode Autocomplete do not subscribe this
351
+ // effect to the typing hot path. A `both → list` switch still clears the previous preview.
319
352
  effect(() => {
320
- config.inlineMode();
353
+ if (!config.inlineMode()) {
354
+ untracked(() => inlinePreview.set(null));
355
+ return;
356
+ }
321
357
  highlightedItem();
322
358
  highlightedIndex();
323
359
  const query = config.query();
@@ -456,10 +492,19 @@ function useComboboxEngine(config) {
456
492
  filteredItems,
457
493
  isVisible,
458
494
  registerItem(item) {
459
- _items.update((items) => [...items, item]);
495
+ if (itemRegistry.get(item.element) === item) {
496
+ return;
497
+ }
498
+ itemRegistry.set(item.element, item);
499
+ itemRegistryTick.update((tick) => tick + 1);
460
500
  },
461
501
  unregisterItem(item) {
462
- _items.update((items) => items.filter((i) => i !== item));
502
+ // A stale cleanup must not delete a newer registration for the same host element.
503
+ if (itemRegistry.get(item.element) !== item) {
504
+ return;
505
+ }
506
+ itemRegistry.delete(item.element);
507
+ itemRegistryTick.update((tick) => tick + 1);
463
508
  },
464
509
  highlight,
465
510
  highlightedItem,
@@ -600,6 +645,21 @@ function domOrder(a, b) {
600
645
  }
601
646
  return 0;
602
647
  }
648
+ /** Referential item-sequence equality used to keep unchanged filtering results stable across queries. */
649
+ function sameItemOrder(previous, next) {
650
+ if (previous === next) {
651
+ return true;
652
+ }
653
+ if (previous.length !== next.length) {
654
+ return false;
655
+ }
656
+ for (let index = 0; index < previous.length; index++) {
657
+ if (previous[index] !== next[index]) {
658
+ return false;
659
+ }
660
+ }
661
+ return true;
662
+ }
603
663
 
604
664
  // The engine stays private to the root (it owns mutable internals); the context factory — a free
605
665
  // function, so it can't reach a `private` field — reads it through this registry instead.
@@ -614,6 +674,9 @@ const context = () => {
614
674
  dir: root.dir,
615
675
  value: root.value,
616
676
  inputValue: root.inputValue,
677
+ name: root.name,
678
+ form: root.form,
679
+ inputOwnsFormValue: root.inputOwnsFormValue,
617
680
  open: root.open,
618
681
  present: root.present,
619
682
  multiple: root.multiple,
@@ -622,6 +685,8 @@ const context = () => {
622
685
  readonly: root.readOnly,
623
686
  requiredState: root.requiredState,
624
687
  invalidState: root.invalidState,
688
+ pendingState: root.formUi.pendingState,
689
+ validState: root.formUi.validState,
625
690
  touchedState: root.touchedState,
626
691
  dirtyState: root.dirtyState,
627
692
  openOnInputClick: root.openOnInputClick,
@@ -763,6 +828,9 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
763
828
  /** Whether the combobox is in multiple-selection mode. */
764
829
  this.multiple = computed(() => this.mode() === 'multiple', /* @ts-ignore */
765
830
  ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
831
+ /** Whether the visible text input owns native serialization in filter-only mode. */
832
+ this.inputOwnsFormValue = computed(() => this.mode() === 'none' && this.engine.inputLayout() !== 'inside', /* @ts-ignore */
833
+ ...(ngDevMode ? [{ debugName: "inputOwnsFormValue" }] : /* istanbul ignore next */ []));
766
834
  /** In `'none'` mode, whether pressing an item fills the input with its label. */
767
835
  this.fillInputOnItemPress = input(true, { ...(ngDevMode ? { debugName: "fillInputOnItemPress" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
768
836
  /** Text direction. */
@@ -774,6 +842,12 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
774
842
  this.readOnly = input(false, { ...(ngDevMode ? { debugName: "readOnly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
775
843
  /** Whether a value is required (for forms). */
776
844
  this.required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
845
+ /** Name used when serializing the committed selection into native `FormData`. */
846
+ this.name = input(/* @ts-ignore */
847
+ ...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
848
+ /** Id of an external form that owns this control. */
849
+ this.form = input(/* @ts-ignore */
850
+ ...(ngDevMode ? [undefined, { debugName: "form" }] : /* istanbul ignore next */ []));
777
851
  /** Whether keyboard navigation wraps at the list boundaries. */
778
852
  this.loopFocus = input(true, { ...(ngDevMode ? { debugName: "loopFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
779
853
  /**
@@ -821,6 +895,9 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
821
895
  */
822
896
  this.filter = input(undefined, /* @ts-ignore */
823
897
  ...(ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []));
898
+ /** Locale for the default `contains` filter's string comparison. Defaults to the runtime locale. */
899
+ this.locale = input(/* @ts-ignore */
900
+ ...(ngDevMode ? [undefined, { debugName: "locale" }] : /* istanbul ignore next */ []));
824
901
  /** Maximum number of matching items to show. `-1` (default) means no limit. */
825
902
  this.limit = input(-1, { ...(ngDevMode ? { debugName: "limit" } : /* istanbul ignore next */ {}), transform: numberAttribute });
826
903
  /**
@@ -849,6 +926,9 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
849
926
  /** Converts a value to its display label. Defaults to the matching item's text. */
850
927
  this.itemToStringLabel = input(/* @ts-ignore */
851
928
  ...(ngDevMode ? [undefined, { debugName: "itemToStringLabel" }] : /* istanbul ignore next */ []));
929
+ /** Converts an item value to the string submitted by a native form. */
930
+ this.itemToStringValue = input(/* @ts-ignore */
931
+ ...(ngDevMode ? [undefined, { debugName: "itemToStringValue" }] : /* istanbul ignore next */ []));
852
932
  /** Emits before the selection changes; call `eventDetails.cancel()` to veto it. */
853
933
  this.onValueChange = output();
854
934
  /** Emits before the input text changes; call `eventDetails.cancel()` to veto it. */
@@ -866,10 +946,52 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
866
946
  ...(ngDevMode ? [{ debugName: "cvaDisabled" }] : /* istanbul ignore next */ []));
867
947
  this.disabledState = computed(() => this.disabled() || this.cvaDisabled(), /* @ts-ignore */
868
948
  ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
949
+ this.nativeFormValue = computed(() => this.mode() === 'none' ? this.inputValue() : this.value(), /* @ts-ignore */
950
+ ...(ngDevMode ? [{ debugName: "nativeFormValue" }] : /* istanbul ignore next */ []));
951
+ this.nativeFormControl = useNativeFormControl({
952
+ name: this.name,
953
+ form: this.form,
954
+ disabled: this.disabledState,
955
+ value: this.nativeFormValue,
956
+ serialize: (value) => {
957
+ const itemToStringValue = this.itemToStringValue();
958
+ return itemToStringValue
959
+ ? serializeNativeFormValue(value, (entry) => itemToStringValue(entry))
960
+ : serializeNativeFormValue(value);
961
+ },
962
+ hasNativeControl: this.inputOwnsFormValue,
963
+ syncNativeControl: () => {
964
+ const input = this.engine.inputElement();
965
+ if (input && this.inputOwnsFormValue()) {
966
+ input.value = this.inputValue();
967
+ }
968
+ },
969
+ defaultValue: () => {
970
+ if (this.mode() === 'none') {
971
+ return this.inputValue();
972
+ }
973
+ const defaultValue = this.defaultValue();
974
+ return defaultValue === undefined ? this.value() : defaultValue;
975
+ },
976
+ onReset: (value) => {
977
+ if (this.mode() === 'none') {
978
+ this.setLabel(typeof value === 'string' ? value : '');
979
+ this.formUi.resetInteractionState?.();
980
+ return;
981
+ }
982
+ this.writeValue(value);
983
+ if (!this.resetNgControl(value)) {
984
+ this.onChange?.(value);
985
+ }
986
+ this.formUi.resetInteractionState?.();
987
+ }
988
+ });
869
989
  this.requiredState = computed(() => this.required(), /* @ts-ignore */
870
990
  ...(ngDevMode ? [{ debugName: "requiredState" }] : /* istanbul ignore next */ []));
871
991
  /** @ignore */
872
992
  this.invalidState = this.formUi.invalidState;
993
+ this.pendingState = this.formUi.pendingState;
994
+ this.validState = this.formUi.validState;
873
995
  /** @ignore */
874
996
  this.touchedState = this.formUi.touchedState;
875
997
  /** @ignore */
@@ -907,6 +1029,7 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
907
1029
  virtualized: this.virtualized,
908
1030
  items: this.items,
909
1031
  filter: this.filter,
1032
+ locale: this.locale,
910
1033
  limit: this.limit,
911
1034
  grid: this.grid,
912
1035
  rowOf: (element) => element.closest('[rdxComboboxRow]'),
@@ -1146,7 +1269,7 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
1146
1269
  /** Requests submit of the closest form when `submitOnItemClick` is enabled. */
1147
1270
  maybeSubmit() {
1148
1271
  if (this.submitOnItemClick()) {
1149
- this.engine.inputElement()?.form?.requestSubmit?.();
1272
+ this.nativeFormControl.requestSubmit();
1150
1273
  }
1151
1274
  }
1152
1275
  selectHighlighted(event = new Event('combobox.item-press')) {
@@ -1252,7 +1375,13 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
1252
1375
  }
1253
1376
  // ControlValueAccessor
1254
1377
  writeValue(value) {
1255
- untracked(() => this.value.set(value));
1378
+ untracked(() => {
1379
+ this.value.set(value);
1380
+ // A programmatic form write (including reset) must keep the visible text aligned with the
1381
+ // committed selection. User commits already set the exact item text and do not echo through
1382
+ // this CVA callback; this path handles form-owned writes only.
1383
+ this.revertInputValue();
1384
+ });
1256
1385
  }
1257
1386
  registerOnChange(fn) {
1258
1387
  this.onChange = fn;
@@ -1264,7 +1393,7 @@ class RdxComboboxRoot extends RdxFormUiControlBase {
1264
1393
  this.cvaDisabled.set(isDisabled);
1265
1394
  }
1266
1395
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxComboboxRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1267
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxComboboxRoot, isStandalone: true, selector: "[rdxComboboxRoot]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, inputValue: { classPropertyName: "inputValue", publicName: "inputValue", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, multipleInput: { classPropertyName: "multipleInput", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, fillInputOnItemPress: { classPropertyName: "fillInputOnItemPress", publicName: "fillInputOnItemPress", isSignal: true, isRequired: false, transformFunction: null }, dirInput: { classPropertyName: "dirInput", publicName: "dir", 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 }, loopFocus: { classPropertyName: "loopFocus", publicName: "loopFocus", isSignal: true, isRequired: false, transformFunction: null }, autoHighlight: { classPropertyName: "autoHighlight", publicName: "autoHighlight", isSignal: true, isRequired: false, transformFunction: null }, highlightItemOnHover: { classPropertyName: "highlightItemOnHover", publicName: "highlightItemOnHover", isSignal: true, isRequired: false, transformFunction: null }, keepHighlight: { classPropertyName: "keepHighlight", publicName: "keepHighlight", isSignal: true, isRequired: false, transformFunction: null }, openOnInputClick: { classPropertyName: "openOnInputClick", publicName: "openOnInputClick", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, submitOnItemClick: { classPropertyName: "submitOnItemClick", publicName: "submitOnItemClick", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, virtualized: { classPropertyName: "virtualized", publicName: "virtualized", isSignal: true, isRequired: false, transformFunction: null }, grid: { classPropertyName: "grid", publicName: "grid", 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: { value: "valueChange", inputValue: "inputValueChange", open: "openChange", onValueChange: "onValueChange", onInputValueChange: "onInputValueChange", onOpenChange: "onOpenChange", onItemHighlighted: "onItemHighlighted", onOpenChangeComplete: "onOpenChangeComplete" }, host: { properties: { "attr.data-disabled": "disabledState() ? \"\" : undefined" } }, providers: [
1396
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxComboboxRoot, isStandalone: true, selector: "[rdxComboboxRoot]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, inputValue: { classPropertyName: "inputValue", publicName: "inputValue", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, multipleInput: { classPropertyName: "multipleInput", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, fillInputOnItemPress: { classPropertyName: "fillInputOnItemPress", publicName: "fillInputOnItemPress", isSignal: true, isRequired: false, transformFunction: null }, dirInput: { classPropertyName: "dirInput", publicName: "dir", 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 }, loopFocus: { classPropertyName: "loopFocus", publicName: "loopFocus", isSignal: true, isRequired: false, transformFunction: null }, autoHighlight: { classPropertyName: "autoHighlight", publicName: "autoHighlight", isSignal: true, isRequired: false, transformFunction: null }, highlightItemOnHover: { classPropertyName: "highlightItemOnHover", publicName: "highlightItemOnHover", isSignal: true, isRequired: false, transformFunction: null }, keepHighlight: { classPropertyName: "keepHighlight", publicName: "keepHighlight", isSignal: true, isRequired: false, transformFunction: null }, openOnInputClick: { classPropertyName: "openOnInputClick", publicName: "openOnInputClick", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, submitOnItemClick: { classPropertyName: "submitOnItemClick", publicName: "submitOnItemClick", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, virtualized: { classPropertyName: "virtualized", publicName: "virtualized", isSignal: true, isRequired: false, transformFunction: null }, grid: { classPropertyName: "grid", publicName: "grid", 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: { value: "valueChange", inputValue: "inputValueChange", open: "openChange", onValueChange: "onValueChange", onInputValueChange: "onInputValueChange", onOpenChange: "onOpenChange", onItemHighlighted: "onItemHighlighted", onOpenChangeComplete: "onOpenChangeComplete" }, host: { properties: { "attr.data-disabled": "disabledState() ? \"\" : undefined" } }, providers: [
1268
1397
  provideComboboxRootContext(context),
1269
1398
  { provide: NG_VALUE_ACCESSOR, useExisting: RdxComboboxRoot, multi: true },
1270
1399
  // New floating foundation (ADR 0015/0017) — the dismissal capability reads this shared context.
@@ -1289,7 +1418,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
1289
1418
  '[attr.data-disabled]': 'disabledState() ? "" : undefined'
1290
1419
  }
1291
1420
  }]
1292
- }], ctorParameters: () => [], propDecorators: { 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 }] }], inputValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputValue", required: false }] }, { type: i0.Output, args: ["inputValueChange"] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], defaultOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultOpen", required: false }] }], multipleInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], fillInputOnItemPress: [{ type: i0.Input, args: [{ isSignal: true, alias: "fillInputOnItemPress", required: false }] }], dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", 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 }] }], loopFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "loopFocus", required: false }] }], autoHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoHighlight", required: false }] }], highlightItemOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightItemOnHover", required: false }] }], keepHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepHighlight", required: false }] }], openOnInputClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnInputClick", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], submitOnItemClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitOnItemClick", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], limit: [{ type: i0.Input, args: [{ isSignal: true, alias: "limit", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], virtualized: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualized", required: false }] }], grid: [{ type: i0.Input, args: [{ isSignal: true, alias: "grid", required: false }] }], isItemEqualToValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "isItemEqualToValue", required: false }] }], itemToStringLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemToStringLabel", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }], onInputValueChange: [{ type: i0.Output, args: ["onInputValueChange"] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onItemHighlighted: [{ type: i0.Output, args: ["onItemHighlighted"] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
1421
+ }], ctorParameters: () => [], propDecorators: { 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 }] }], inputValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputValue", required: false }] }, { type: i0.Output, args: ["inputValueChange"] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], defaultOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultOpen", required: false }] }], multipleInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], fillInputOnItemPress: [{ type: i0.Input, args: [{ isSignal: true, alias: "fillInputOnItemPress", required: false }] }], dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", 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 }] }], loopFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "loopFocus", required: false }] }], autoHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoHighlight", required: false }] }], highlightItemOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightItemOnHover", required: false }] }], keepHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepHighlight", required: false }] }], openOnInputClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnInputClick", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], submitOnItemClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitOnItemClick", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], limit: [{ type: i0.Input, args: [{ isSignal: true, alias: "limit", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], virtualized: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualized", required: false }] }], grid: [{ type: i0.Input, args: [{ isSignal: true, alias: "grid", 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 }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }], onInputValueChange: [{ type: i0.Output, args: ["onInputValueChange"] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onItemHighlighted: [{ type: i0.Output, args: ["onItemHighlighted"] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
1293
1422
 
1294
1423
  /**
1295
1424
  * An overlay rendered beneath the popup in `modal` mode. Place it inside the portal/presence; style
@@ -1620,18 +1749,38 @@ class RdxComboboxGroup {
1620
1749
  this.rootContext = injectComboboxRootContext();
1621
1750
  this.labelId = signal(undefined, /* @ts-ignore */
1622
1751
  ...(ngDevMode ? [{ debugName: "labelId" }] : /* istanbul ignore next */ []));
1623
- this.items = signal([], /* @ts-ignore */
1624
- ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
1625
- this.hasItems = computed(() => this.items().length > 0, /* @ts-ignore */
1752
+ // Group membership is unordered, so a stable Set avoids copying a growing array for every child
1753
+ // registration. The tick keeps the two derived host states reactive.
1754
+ this.items = new Set();
1755
+ this.itemsTick = signal(0, /* @ts-ignore */
1756
+ ...(ngDevMode ? [{ debugName: "itemsTick" }] : /* istanbul ignore next */ []));
1757
+ this.hasItems = computed(() => {
1758
+ this.itemsTick();
1759
+ return this.items.size > 0;
1760
+ }, /* @ts-ignore */
1626
1761
  ...(ngDevMode ? [{ debugName: "hasItems" }] : /* istanbul ignore next */ []));
1627
- this.hasVisibleItems = computed(() => this.items().some((item) => this.rootContext.isVisible(item)), /* @ts-ignore */
1762
+ this.hasVisibleItems = computed(() => {
1763
+ this.itemsTick();
1764
+ for (const item of this.items) {
1765
+ if (this.rootContext.isVisible(item)) {
1766
+ return true;
1767
+ }
1768
+ }
1769
+ return false;
1770
+ }, /* @ts-ignore */
1628
1771
  ...(ngDevMode ? [{ debugName: "hasVisibleItems" }] : /* istanbul ignore next */ []));
1629
1772
  }
1630
1773
  registerItem(item) {
1631
- this.items.update((items) => [...items, item]);
1774
+ if (this.items.has(item)) {
1775
+ return;
1776
+ }
1777
+ this.items.add(item);
1778
+ this.itemsTick.update((tick) => tick + 1);
1632
1779
  }
1633
1780
  unregisterItem(item) {
1634
- this.items.update((items) => items.filter((i) => i !== item));
1781
+ if (this.items.delete(item)) {
1782
+ this.itemsTick.update((tick) => tick + 1);
1783
+ }
1635
1784
  }
1636
1785
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxComboboxGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1637
1786
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: RdxComboboxGroup, isStandalone: true, selector: "[rdxComboboxGroup]", host: { attributes: { "role": "group" }, properties: { "attr.aria-labelledby": "labelId()", "hidden": "hasItems() && !hasVisibleItems()" } }, providers: [provideComboboxGroupContext(groupContext)], exportAs: ["rdxComboboxGroup"], ngImport: i0 }); }
@@ -1769,18 +1918,21 @@ class RdxComboboxInput {
1769
1918
  ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
1770
1919
  /** Marks the input as invalid independently of any Field state. */
1771
1920
  this.invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1772
- this.invalidState = computed(() => this.invalid() || this.rootContext.invalidState() || Boolean(this.fieldRootContext?.invalidState()), /* @ts-ignore */
1773
- ...(ngDevMode ? [{ debugName: "invalidState" }] : /* istanbul ignore next */ []));
1774
1921
  /**
1775
1922
  * Tri-state *displayed* validity: the enclosing Field's gated `validState` when inside a `rdxFieldRoot`
1776
1923
  * (so a field whose `validationMode` defers display (e.g. `onBlur`) keeps the input neutral until revealed), else the input's
1777
1924
  * own binary invalidity.
1778
1925
  */
1779
- this.displayValid = computed(() => this.fieldRootContext
1780
- ? this.fieldRootContext.validState()
1781
- : this.invalid() || this.rootContext.invalidState()
1782
- ? false
1783
- : true, /* @ts-ignore */
1926
+ this.displayValid = computed(() => {
1927
+ if (this.fieldRootContext) {
1928
+ return this.fieldRootContext.validState();
1929
+ }
1930
+ const rootValid = this.rootContext.validState();
1931
+ if (rootValid === null) {
1932
+ return null;
1933
+ }
1934
+ return this.invalid() ? false : rootValid;
1935
+ }, /* @ts-ignore */
1784
1936
  ...(ngDevMode ? [{ debugName: "displayValid" }] : /* istanbul ignore next */ []));
1785
1937
  this.disabledState = computed(() => this.rootContext.disabledState() || Boolean(this.fieldRootContext?.disabledState()), /* @ts-ignore */
1786
1938
  ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
@@ -1806,10 +1958,7 @@ class RdxComboboxInput {
1806
1958
  if (!this.fieldRootContext) {
1807
1959
  return undefined;
1808
1960
  }
1809
- const ids = [
1810
- ...this.fieldRootContext.descriptionIds(),
1811
- ...(this.fieldRootContext.invalidState() ? this.fieldRootContext.errorIds() : [])
1812
- ];
1961
+ const ids = [...this.fieldRootContext.descriptionIds(), ...this.fieldRootContext.errorIds()];
1813
1962
  return ids.length ? ids.join(' ') : undefined;
1814
1963
  }, /* @ts-ignore */
1815
1964
  ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
@@ -1986,7 +2135,7 @@ class RdxComboboxInput {
1986
2135
  }
1987
2136
  }
1988
2137
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxComboboxInput, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1989
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxComboboxInput, isStandalone: true, selector: "input[rdxComboboxInput]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "combobox", "autocomplete": "off", "aria-autocomplete": "list" }, listeners: { "input": "onInput($event)", "click": "onClick($event)", "focus": "onFocus()", "blur": "onBlur()", "keydown": "onKeydown($event)", "compositionstart": "composing = true", "compositionend": "onCompositionEnd($event)" }, properties: { "attr.id": "id()", "attr.aria-haspopup": "rootContext.grid() ? \"grid\" : \"listbox\"", "attr.aria-expanded": "rootContext.open()", "attr.aria-controls": "rootContext.listId", "attr.aria-labelledby": "rootContext.labelId()", "attr.aria-activedescendant": "rootContext.activeId()", "attr.aria-describedby": "describedBy()", "attr.aria-invalid": "displayValid() === false ? \"true\" : undefined", "attr.aria-required": "requiredState() ? \"true\" : undefined", "attr.aria-disabled": "disabledState() ? \"true\" : undefined", "attr.disabled": "disabledState() ? \"\" : undefined", "attr.readonly": "rootContext.readonly() ? \"\" : undefined", "attr.required": "requiredState() ? \"\" : undefined", "value": "rootContext.inputValue()", "attr.data-popup-open": "dataAttr(rootContext.open())", "attr.data-list-empty": "dataAttr(rootContext.visibleCount() === 0)", "attr.data-placeholder": "dataAttr(isEmptyValue())", "attr.data-invalid": "dataAttr(displayValid() === false)", "attr.data-valid": "dataAttr(displayValid() === true)", "attr.data-disabled": "dataAttr(disabledState())", "attr.data-required": "dataAttr(requiredState())", "attr.data-touched": "dataAttr(touchedState())", "attr.data-dirty": "dataAttr(dirtyState())", "attr.data-filled": "dataAttr(filledState())", "attr.data-focused": "dataAttr(focusedState())" } }, exportAs: ["rdxComboboxInput"], hostDirectives: [{ directive: i1.RdxPopperAnchor }, { directive: i1$1.RdxFloatingInsideElement }], ngImport: i0 }); }
2138
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxComboboxInput, isStandalone: true, selector: "input[rdxComboboxInput]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "combobox", "autocomplete": "off", "aria-autocomplete": "list" }, listeners: { "input": "onInput($event)", "click": "onClick($event)", "focus": "onFocus()", "blur": "onBlur()", "keydown": "onKeydown($event)", "compositionstart": "composing = true", "compositionend": "onCompositionEnd($event)" }, properties: { "attr.id": "id()", "attr.aria-haspopup": "rootContext.grid() ? \"grid\" : \"listbox\"", "attr.aria-expanded": "rootContext.open()", "attr.aria-controls": "rootContext.listId", "attr.aria-labelledby": "rootContext.labelId()", "attr.aria-activedescendant": "rootContext.activeId()", "attr.aria-describedby": "describedBy()", "attr.aria-invalid": "displayValid() === false ? \"true\" : undefined", "attr.aria-required": "requiredState() ? \"true\" : undefined", "attr.aria-disabled": "disabledState() ? \"true\" : undefined", "attr.disabled": "disabledState() ? \"\" : undefined", "attr.readonly": "rootContext.readonly() ? \"\" : undefined", "attr.required": "requiredState() ? \"\" : undefined", "attr.name": "rootContext.inputOwnsFormValue() ? rootContext.name() : undefined", "attr.form": "rootContext.form()", "value": "rootContext.inputValue()", "attr.data-popup-open": "dataAttr(rootContext.open())", "attr.data-list-empty": "dataAttr(rootContext.visibleCount() === 0)", "attr.data-placeholder": "dataAttr(isEmptyValue())", "attr.data-invalid": "dataAttr(displayValid() === false)", "attr.data-valid": "dataAttr(displayValid() === true)", "attr.data-disabled": "dataAttr(disabledState())", "attr.data-required": "dataAttr(requiredState())", "attr.data-touched": "dataAttr(touchedState())", "attr.data-dirty": "dataAttr(dirtyState())", "attr.data-filled": "dataAttr(filledState())", "attr.data-focused": "dataAttr(focusedState())" } }, exportAs: ["rdxComboboxInput"], hostDirectives: [{ directive: i1.RdxPopperAnchor }, { directive: i1$1.RdxFloatingInsideElement }], ngImport: i0 }); }
1990
2139
  }
1991
2140
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxComboboxInput, decorators: [{
1992
2141
  type: Directive,
@@ -2011,6 +2160,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2011
2160
  '[attr.disabled]': 'disabledState() ? "" : undefined',
2012
2161
  '[attr.readonly]': 'rootContext.readonly() ? "" : undefined',
2013
2162
  '[attr.required]': 'requiredState() ? "" : undefined',
2163
+ '[attr.name]': 'rootContext.inputOwnsFormValue() ? rootContext.name() : undefined',
2164
+ '[attr.form]': 'rootContext.form()',
2014
2165
  '[value]': 'rootContext.inputValue()',
2015
2166
  '[attr.data-popup-open]': 'dataAttr(rootContext.open())',
2016
2167
  '[attr.data-list-empty]': 'dataAttr(rootContext.visibleCount() === 0)',