@radix-ng/primitives 1.0.0-beta.0 → 1.0.0-beta.2

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 (117) hide show
  1. package/fesm2022/radix-ng-primitives-accordion.mjs +2 -2
  2. package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
  3. package/fesm2022/radix-ng-primitives-calendar.mjs +109 -84
  4. package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
  5. package/fesm2022/radix-ng-primitives-checkbox.mjs +2 -2
  6. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  7. package/fesm2022/radix-ng-primitives-collapsible.mjs +1 -1
  8. package/fesm2022/radix-ng-primitives-collapsible.mjs.map +1 -1
  9. package/fesm2022/radix-ng-primitives-combobox.mjs +1923 -0
  10. package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -0
  11. package/fesm2022/radix-ng-primitives-context-menu.mjs +1 -1
  12. package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
  13. package/fesm2022/radix-ng-primitives-core.mjs +591 -470
  14. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  15. package/fesm2022/radix-ng-primitives-cropper.mjs +287 -308
  16. package/fesm2022/radix-ng-primitives-cropper.mjs.map +1 -1
  17. package/fesm2022/radix-ng-primitives-date-field.mjs +66 -15
  18. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  19. package/fesm2022/radix-ng-primitives-dialog.mjs +1 -1
  20. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  21. package/fesm2022/radix-ng-primitives-drawer.mjs +7 -106
  22. package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -1
  23. package/fesm2022/radix-ng-primitives-editable.mjs +305 -24
  24. package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
  25. package/fesm2022/radix-ng-primitives-field.mjs +86 -6
  26. package/fesm2022/radix-ng-primitives-field.mjs.map +1 -1
  27. package/fesm2022/radix-ng-primitives-fieldset.mjs +1 -1
  28. package/fesm2022/radix-ng-primitives-fieldset.mjs.map +1 -1
  29. package/fesm2022/radix-ng-primitives-focus-scope.mjs +1 -1
  30. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  31. package/fesm2022/radix-ng-primitives-form.mjs +207 -0
  32. package/fesm2022/radix-ng-primitives-form.mjs.map +1 -0
  33. package/fesm2022/radix-ng-primitives-input.mjs +85 -4
  34. package/fesm2022/radix-ng-primitives-input.mjs.map +1 -1
  35. package/fesm2022/radix-ng-primitives-menu.mjs +413 -5
  36. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  37. package/fesm2022/radix-ng-primitives-menubar.mjs +1 -1
  38. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  39. package/fesm2022/radix-ng-primitives-meter.mjs +1 -1
  40. package/fesm2022/radix-ng-primitives-meter.mjs.map +1 -1
  41. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +1 -1
  42. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  43. package/fesm2022/radix-ng-primitives-number-field.mjs +2 -2
  44. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
  45. package/fesm2022/radix-ng-primitives-popover.mjs +1 -1
  46. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  47. package/fesm2022/radix-ng-primitives-popper.mjs +22 -5
  48. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  49. package/fesm2022/radix-ng-primitives-portal.mjs.map +1 -1
  50. package/fesm2022/radix-ng-primitives-preview-card.mjs +1 -1
  51. package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -1
  52. package/fesm2022/radix-ng-primitives-progress.mjs +1 -1
  53. package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -1
  54. package/fesm2022/radix-ng-primitives-roving-focus.mjs +1 -1
  55. package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
  56. package/fesm2022/radix-ng-primitives-scroll-area.mjs +923 -0
  57. package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -0
  58. package/fesm2022/radix-ng-primitives-select.mjs +421 -224
  59. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  60. package/fesm2022/radix-ng-primitives-slider.mjs +1 -1
  61. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  62. package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
  63. package/fesm2022/radix-ng-primitives-switch.mjs +3 -2
  64. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  65. package/fesm2022/radix-ng-primitives-tabs.mjs +12 -3
  66. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  67. package/fesm2022/radix-ng-primitives-time-field.mjs +27 -3
  68. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  69. package/fesm2022/radix-ng-primitives-toast.mjs +839 -0
  70. package/fesm2022/radix-ng-primitives-toast.mjs.map +1 -0
  71. package/fesm2022/radix-ng-primitives-toggle-group.mjs +1 -1
  72. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  73. package/fesm2022/radix-ng-primitives-toolbar.mjs +2 -2
  74. package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
  75. package/fesm2022/radix-ng-primitives-tooltip.mjs +11 -3
  76. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  77. package/package.json +18 -2
  78. package/schematics/ng-add/index.js +57 -0
  79. package/schematics/ng-add/index.js.map +1 -1
  80. package/schematics/ng-add/schema.d.ts +1 -0
  81. package/schematics/ng-add/schema.json +6 -0
  82. package/types/radix-ng-primitives-accordion.d.ts +3 -2
  83. package/types/radix-ng-primitives-calendar.d.ts +38 -18
  84. package/types/radix-ng-primitives-checkbox.d.ts +5 -5
  85. package/types/radix-ng-primitives-collapsible.d.ts +2 -1
  86. package/types/radix-ng-primitives-combobox.d.ts +1265 -0
  87. package/types/radix-ng-primitives-context-menu.d.ts +3 -2
  88. package/types/radix-ng-primitives-core.d.ts +187 -56
  89. package/types/radix-ng-primitives-cropper.d.ts +89 -56
  90. package/types/radix-ng-primitives-date-field.d.ts +11 -5
  91. package/types/radix-ng-primitives-dialog.d.ts +2 -1
  92. package/types/radix-ng-primitives-drawer.d.ts +5 -27
  93. package/types/radix-ng-primitives-editable.d.ts +90 -13
  94. package/types/radix-ng-primitives-field.d.ts +74 -4
  95. package/types/radix-ng-primitives-fieldset.d.ts +3 -2
  96. package/types/radix-ng-primitives-focus-scope.d.ts +2 -1
  97. package/types/radix-ng-primitives-form.d.ts +124 -0
  98. package/types/radix-ng-primitives-input.d.ts +75 -5
  99. package/types/radix-ng-primitives-menu.d.ts +16 -4
  100. package/types/radix-ng-primitives-menubar.d.ts +2 -1
  101. package/types/radix-ng-primitives-meter.d.ts +3 -2
  102. package/types/radix-ng-primitives-navigation-menu.d.ts +1 -1
  103. package/types/radix-ng-primitives-number-field.d.ts +6 -6
  104. package/types/radix-ng-primitives-popover.d.ts +2 -1
  105. package/types/radix-ng-primitives-popper.d.ts +19 -2
  106. package/types/radix-ng-primitives-preview-card.d.ts +1 -1
  107. package/types/radix-ng-primitives-progress.d.ts +3 -2
  108. package/types/radix-ng-primitives-roving-focus.d.ts +4 -3
  109. package/types/radix-ng-primitives-scroll-area.d.ts +253 -0
  110. package/types/radix-ng-primitives-select.d.ts +296 -136
  111. package/types/radix-ng-primitives-slider.d.ts +1 -1
  112. package/types/radix-ng-primitives-switch.d.ts +1 -1
  113. package/types/radix-ng-primitives-tabs.d.ts +1 -1
  114. package/types/radix-ng-primitives-toast.d.ts +378 -0
  115. package/types/radix-ng-primitives-toggle-group.d.ts +2 -1
  116. package/types/radix-ng-primitives-toolbar.d.ts +3 -2
  117. package/types/radix-ng-primitives-tooltip.d.ts +3 -2
@@ -1,19 +1,20 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, model, input, booleanAttribute, computed, signal, Directive, InjectionToken, ElementRef, afterNextRender, effect, ContentChild, linkedSignal, DestroyRef, numberAttribute, forwardRef } from '@angular/core';
3
- import { outputFromObservable, outputToObservable } from '@angular/core/rxjs-interop';
2
+ import { inject, model, input, booleanAttribute, output, computed, signal, untracked, effect, Directive, InjectionToken, ElementRef, Injector, DestroyRef, afterNextRender, ContentChild, linkedSignal, numberAttribute, forwardRef } from '@angular/core';
3
+ import { isEqual, getActiveElement, createContext, useTransitionStatus, isNullish, injectId, useListHighlight, useScrollLock, handleAndDispatchCustomEvent } from '@radix-ng/primitives/core';
4
+ import * as i1 from '@radix-ng/primitives/popper';
5
+ import { RdxPopper, RdxPopperContentWrapper, RdxPopperContent, RdxPopperAnchor } from '@radix-ng/primitives/popper';
4
6
  import * as i3 from '@radix-ng/primitives/collection';
5
7
  import { RdxCollectionProvider, RdxCollectionItem } from '@radix-ng/primitives/collection';
6
- import { isEqual, getActiveElement, createContext, isNullish, injectId, handleAndDispatchCustomEvent } from '@radix-ng/primitives/core';
8
+ import { outputFromObservable, outputToObservable } from '@angular/core/rxjs-interop';
7
9
  import * as i2 from '@radix-ng/primitives/dismissable-layer';
8
10
  import { RdxDismissableLayer, provideRdxDismissableLayerConfig } from '@radix-ng/primitives/dismissable-layer';
9
11
  import * as i1$1 from '@radix-ng/primitives/focus-scope';
10
12
  import { RdxFocusScope } from '@radix-ng/primitives/focus-scope';
11
- import * as i1 from '@radix-ng/primitives/popper';
12
- import { RdxPopper, RdxPopperContent, RdxPopperContentWrapper, RdxPopperAnchor } from '@radix-ng/primitives/popper';
13
13
  import * as i1$2 from '@radix-ng/primitives/portal';
14
14
  import { RdxPortal } from '@radix-ng/primitives/portal';
15
15
  import * as i1$3 from '@radix-ng/primitives/presence';
16
16
  import { provideRdxPresenceContext, RdxPresenceDirective } from '@radix-ng/primitives/presence';
17
+ import { injectFieldRootContext } from '@radix-ng/primitives/field';
17
18
 
18
19
  const OPEN_KEYS = [' ', 'Enter', 'ArrowUp', 'ArrowDown'];
19
20
  const SELECTION_KEYS = [' ', 'Enter'];
@@ -62,9 +63,14 @@ const context$2 = () => {
62
63
  dir: context.dir,
63
64
  value: context.value,
64
65
  multiple: context.multiple,
65
- by: context.by,
66
+ isItemEqualToValue: context.isItemEqualToValue,
67
+ itemToStringLabel: context.itemToStringLabel,
66
68
  open: context.open,
67
69
  disabled: context.disabled,
70
+ modal: context.modal,
71
+ isEmptyModelValue: context.isEmptyModelValue,
72
+ transitionStatus: context.transitionStatus,
73
+ registerTransitionElement: context.registerTransitionElement,
68
74
  optionsSet: context.optionsSet,
69
75
  onOptionAdd: (option) => {
70
76
  const existingOption = context.getOption(option());
@@ -91,23 +97,33 @@ const context$2 = () => {
91
97
  }
92
98
  };
93
99
  };
94
- const [injectSelectRootContext, provideSelectRootContext] = createContext('RdxSelectRootContext');
100
+ const [injectSelectRootContext, provideSelectRootContext] = createContext('RdxSelectRootContext', 'components/select');
95
101
  class RdxSelectRoot {
96
102
  constructor() {
97
103
  this.open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
98
104
  this.value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ []));
99
105
  this.multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
100
106
  this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
107
+ /** Whether the popup is modal: locks page scroll and makes outside content inert while open. */
108
+ this.modal = input(true, { ...(ngDevMode ? { debugName: "modal" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
101
109
  this.dir = input('ltr', ...(ngDevMode ? [{ debugName: "dir" }] : /* istanbul ignore next */ []));
102
- /** Use this to compare objects by a particular field, or pass your own comparison function for complete control over how objects are compared. */
103
- this.by = input(...(ngDevMode ? [undefined, { debugName: "by" }] : /* istanbul ignore next */ []));
110
+ /** How item values are compared for equality a function `(a, b) => boolean` or an object key. */
111
+ this.isItemEqualToValue = input(...(ngDevMode ? [undefined, { debugName: "isItemEqualToValue" }] : /* istanbul ignore next */ []));
112
+ /** Converts a value to its display label (used by `RdxSelectValue`). */
113
+ this.itemToStringLabel = input(...(ngDevMode ? [undefined, { debugName: "itemToStringLabel" }] : /* istanbul ignore next */ []));
114
+ /** Emits after the open/close transition (including any exit animation) finishes. */
115
+ this.onOpenChangeComplete = output();
116
+ this.transition = useTransitionStatus((open) => this.onOpenChangeComplete.emit(open));
117
+ /** Open/close transition phase, for `data-starting-style` / `data-ending-style`. */
118
+ this.transitionStatus = this.transition.status;
119
+ /** Registers the popup element whose animation determines transition completion. */
120
+ this.registerTransitionElement = this.transition.registerElement;
104
121
  this.isEmptyModelValue = computed(() => {
105
- if (this.multiple() && Array.isArray(this.value())) {
106
- return Array(this.value())?.length === 0;
107
- }
108
- else {
109
- return isNullish(this.value());
122
+ const value = this.value();
123
+ if (this.multiple() && Array.isArray(value)) {
124
+ return value.length === 0;
110
125
  }
126
+ return isNullish(value);
111
127
  }, ...(ngDevMode ? [{ debugName: "isEmptyModelValue" }] : /* istanbul ignore next */ []));
112
128
  this.optionsSet = signal(new Set(), ...(ngDevMode ? [{ debugName: "optionsSet" }] : /* istanbul ignore next */ []));
113
129
  // The native `select` only associates the correct default value if the corresponding
@@ -126,14 +142,24 @@ class RdxSelectRoot {
126
142
  x: 0,
127
143
  y: 0
128
144
  }, ...(ngDevMode ? [{ debugName: "triggerPointerDownPosRef" }] : /* istanbul ignore next */ []));
145
+ let previousOpen = untracked(this.open);
146
+ effect(() => {
147
+ const open = this.open();
148
+ if (open === previousOpen) {
149
+ return;
150
+ }
151
+ previousOpen = open;
152
+ untracked(() => this.transition.start(open));
153
+ });
129
154
  }
130
155
  getOption(value) {
131
- return Array.from(this.optionsSet()).find((option) => valueComparator(value, option.value, this.by()));
156
+ return Array.from(this.optionsSet()).find((option) => valueComparator(value, option.value, this.isItemEqualToValue()));
132
157
  }
133
158
  handleValueChange(value) {
134
159
  if (this.multiple()) {
135
- const array = Array.isArray(this.value()) ? [...Array(this.value())] : [];
136
- const index = array.findIndex((i) => compare(i, value, this.by()));
160
+ const current = this.value();
161
+ const array = Array.isArray(current) ? [...current] : [];
162
+ const index = array.findIndex((i) => compare(i, value, this.isItemEqualToValue()));
137
163
  index === -1 ? array.push(value) : array.splice(index, 1);
138
164
  this.value.set([...array]);
139
165
  }
@@ -142,7 +168,7 @@ class RdxSelectRoot {
142
168
  }
143
169
  }
144
170
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
145
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", 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 }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, by: { classPropertyName: "by", publicName: "by", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", value: "valueChange" }, providers: [provideSelectRootContext(context$2)], exportAs: ["rdxSelectRoot"], hostDirectives: [{ directive: i1.RdxPopper }], ngImport: i0 }); }
171
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", 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 }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", 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", onOpenChangeComplete: "onOpenChangeComplete" }, providers: [provideSelectRootContext(context$2)], exportAs: ["rdxSelectRoot"], hostDirectives: [{ directive: i1.RdxPopper }], ngImport: i0 }); }
146
172
  }
147
173
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectRoot, decorators: [{
148
174
  type: Directive,
@@ -152,25 +178,108 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
152
178
  providers: [provideSelectRootContext(context$2)],
153
179
  hostDirectives: [RdxPopper]
154
180
  }]
155
- }], 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"] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], by: [{ type: i0.Input, args: [{ isSignal: true, alias: "by", required: false }] }] } });
181
+ }], 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"] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], dir: [{ 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 }] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
182
+
183
+ /**
184
+ * An overlay rendered beneath the popup in `modal` mode. Place it inside the portal/presence; style
185
+ * it `position: fixed; inset: 0`. Exposes `data-open` / `data-closed` for animation.
186
+ *
187
+ * @group Components
188
+ */
189
+ class RdxSelectBackdrop {
190
+ constructor() {
191
+ this.rootContext = injectSelectRootContext();
192
+ }
193
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectBackdrop, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
194
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectBackdrop, isStandalone: true, selector: "[rdxSelectBackdrop]", host: { attributes: { "aria-hidden": "true" }, properties: { "attr.data-state": "rootContext.open() ? \"open\" : \"closed\"", "attr.data-open": "rootContext.open() ? \"\" : undefined", "attr.data-closed": "rootContext.open() ? undefined : \"\"" } }, exportAs: ["rdxSelectBackdrop"], ngImport: i0 }); }
195
+ }
196
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectBackdrop, decorators: [{
197
+ type: Directive,
198
+ args: [{
199
+ selector: '[rdxSelectBackdrop]',
200
+ exportAs: 'rdxSelectBackdrop',
201
+ host: {
202
+ 'aria-hidden': 'true',
203
+ '[attr.data-state]': 'rootContext.open() ? "open" : "closed"',
204
+ '[attr.data-open]': 'rootContext.open() ? "" : undefined',
205
+ '[attr.data-closed]': 'rootContext.open() ? undefined : ""'
206
+ }
207
+ }]
208
+ }] });
209
+
210
+ class RdxSelectGroup {
211
+ constructor() {
212
+ this.id = injectId('rdx-select-group-');
213
+ }
214
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
215
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectGroup, isStandalone: true, selector: "[rdxSelectGroup]", host: { attributes: { "role": "group" }, properties: { "attr.aria-labelledby": "id" } }, exportAs: ["rdxSelectGroup"], ngImport: i0 }); }
216
+ }
217
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectGroup, decorators: [{
218
+ type: Directive,
219
+ args: [{
220
+ selector: '[rdxSelectGroup]',
221
+ exportAs: 'rdxSelectGroup',
222
+ host: {
223
+ role: 'group',
224
+ '[attr.aria-labelledby]': 'id'
225
+ }
226
+ }]
227
+ }] });
228
+
229
+ class RdxSelectGroupLabel {
230
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectGroupLabel, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
231
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectGroupLabel, isStandalone: true, selector: "[rdxSelectGroupLabel]", ngImport: i0 }); }
232
+ }
233
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectGroupLabel, decorators: [{
234
+ type: Directive,
235
+ args: [{
236
+ selector: '[rdxSelectGroupLabel]',
237
+ host: {}
238
+ }]
239
+ }] });
240
+
241
+ /**
242
+ * Decorative icon inside the trigger (e.g. a chevron). Hidden from assistive technology.
243
+ *
244
+ * @group Components
245
+ */
246
+ class RdxSelectIcon {
247
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectIcon, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
248
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectIcon, isStandalone: true, selector: "[rdxSelectIcon]", host: { attributes: { "aria-hidden": "true" } }, exportAs: ["rdxSelectIcon"], ngImport: i0 }); }
249
+ }
250
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectIcon, decorators: [{
251
+ type: Directive,
252
+ args: [{
253
+ selector: '[rdxSelectIcon]',
254
+ exportAs: 'rdxSelectIcon',
255
+ host: {
256
+ 'aria-hidden': 'true'
257
+ }
258
+ }]
259
+ }] });
156
260
 
157
261
  const context$1 = () => {
158
- const context = inject(RdxSelectContent);
262
+ const context = inject(RdxSelectPopup);
159
263
  return {
160
264
  content: context.content,
161
265
  viewport: context.viewport,
162
266
  isPositioned: context.isPositioned,
163
267
  selectedItem: context.selectedItem,
164
268
  selectedItemText: context.selectedItemText,
269
+ highlightedItem: context.highlight.highlightedItem,
270
+ isHighlighted: (item) => context.highlight.highlightedItem() === item,
271
+ highlightItem: (item) => context.highlight.set(item),
272
+ isKeyboardActive: () => context.isKeyboardActive(),
273
+ setKeyboardActive: (value) => context.setKeyboardActive(value),
165
274
  onViewportChange: (node) => {
166
275
  context.viewport.set(node);
167
276
  },
168
277
  onItemLeave: () => {
169
- context.content()?.focus();
278
+ context.highlight.clear();
170
279
  },
171
280
  itemRefCallback: (node, value, disabled) => {
172
281
  const isFirstValidItem = !context.firstValidItemFoundRef() && !disabled;
173
- const isSelectedItem = valueComparator(context.rootContext.value(), value, context.rootContext.by());
282
+ const isSelectedItem = valueComparator(context.rootContext.value(), value, context.rootContext.isItemEqualToValue());
174
283
  if (isSelectedItem || isFirstValidItem) {
175
284
  context.selectedItem.set(node);
176
285
  }
@@ -180,20 +289,28 @@ const context$1 = () => {
180
289
  },
181
290
  itemTextRefCallback: (node, value, disabled) => {
182
291
  const isFirstValidItem = !context.firstValidItemFoundRef() && !disabled;
183
- const isSelectedItem = valueComparator(context.rootContext.value(), value, context.rootContext.by());
292
+ const isSelectedItem = valueComparator(context.rootContext.value(), value, context.rootContext.isItemEqualToValue());
184
293
  if (isSelectedItem || isFirstValidItem) {
185
294
  context.selectedItemText.set(node);
186
295
  }
187
296
  }
188
297
  };
189
298
  };
190
- const [injectSelectContentContext, provideSelectContentContext] = createContext('RdxSelectContent');
299
+ const [injectSelectPopupContext, provideSelectPopupContext] = createContext('RdxSelectPopup', 'components/select');
191
300
  const RDX_SELECT_POSITIONER_TOKEN = new InjectionToken('RDX_SELECT_POSITIONER_TOKEN');
192
- class RdxSelectContent {
301
+ /**
302
+ * The popup listbox. Holds DOM focus while open and navigates with the highlight model
303
+ * (`aria-activedescendant`) — items are not individually focusable. (Renamed to `RdxSelectPopup` in a
304
+ * later step; selector kept here during the navigation migration.)
305
+ *
306
+ * @group Components
307
+ */
308
+ class RdxSelectPopup {
193
309
  set positioner(port) {
194
310
  if (port) {
195
311
  port.placed.subscribe(() => {
196
- this.focusSelectedItem();
312
+ this.highlightSelectedItem();
313
+ this.scrollSelectedIntoView();
197
314
  this.isPositioned.set(true);
198
315
  });
199
316
  }
@@ -202,12 +319,23 @@ class RdxSelectContent {
202
319
  this.dismissableLayer = inject(RdxDismissableLayer);
203
320
  this.currentElement = inject(ElementRef);
204
321
  this.collection = inject(RdxCollectionProvider);
322
+ this.injector = inject(Injector);
205
323
  this.rootContext = injectSelectRootContext();
324
+ /** Highlight-model navigation over the collected items (DOM order). */
325
+ this.highlight = useListHighlight({
326
+ items: this.collection.items,
327
+ isNavigable: (item) => !item.disabled(),
328
+ getId: (item) => item.element.id,
329
+ injector: this.injector
330
+ });
206
331
  this.selectedItem = signal(undefined, ...(ngDevMode ? [{ debugName: "selectedItem" }] : /* istanbul ignore next */ []));
207
332
  this.selectedItemText = signal(undefined, ...(ngDevMode ? [{ debugName: "selectedItemText" }] : /* istanbul ignore next */ []));
208
333
  this.firstValidItemFoundRef = signal(false, ...(ngDevMode ? [{ debugName: "firstValidItemFoundRef" }] : /* istanbul ignore next */ []));
209
334
  this.viewport = signal(undefined, ...(ngDevMode ? [{ debugName: "viewport" }] : /* istanbul ignore next */ []));
210
335
  this.isPositioned = signal(false, ...(ngDevMode ? [{ debugName: "isPositioned" }] : /* istanbul ignore next */ []));
336
+ // Tracks whether the last interaction was the keyboard, so the highlight doesn't jump to an item
337
+ // the cursor happens to rest on when arrow-key navigation scrolls the list.
338
+ this.keyboardActive = false;
211
339
  /**
212
340
  * Event handler called when the escape key is down.
213
341
  * Can be prevented.
@@ -219,6 +347,11 @@ class RdxSelectContent {
219
347
  */
220
348
  this.pointerDownOutside = outputFromObservable(outputToObservable(this.dismissableLayer.pointerDownOutside));
221
349
  this.content = signal(null, ...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
350
+ // Lock page scroll while a modal popup is open (content mounts only while open).
351
+ useScrollLock(this.rootContext.modal);
352
+ // The popup's animation determines when the open/close transition (onOpenChangeComplete) is done.
353
+ const unregisterTransition = this.rootContext.registerTransitionElement(this.currentElement.nativeElement);
354
+ inject(DestroyRef).onDestroy(unregisterTransition);
222
355
  this.dismissableLayer.focusOutside.subscribe((e) => e.preventDefault());
223
356
  this.dismissableLayer.dismiss.subscribe(() => this.rootContext.onOpenChange(false));
224
357
  const focusScope = inject(RdxFocusScope);
@@ -229,8 +362,11 @@ class RdxSelectContent {
229
362
  this.rootContext.triggerElement()?.focus({ preventScroll: true });
230
363
  event.preventDefault();
231
364
  });
365
+ // Focus the popup itself (not an item) — the listbox is the focus owner; items are
366
+ // navigated virtually via aria-activedescendant.
232
367
  focusScope.mountAutoFocus.subscribe((event) => {
233
368
  event.preventDefault();
369
+ this.content()?.focus({ preventScroll: true });
234
370
  });
235
371
  this.content.set(this.currentElement.nativeElement.firstElementChild);
236
372
  });
@@ -275,56 +411,97 @@ class RdxSelectContent {
275
411
  });
276
412
  });
277
413
  }
278
- focusSelectedItem() {
279
- if (this.selectedItem() && this.content()) {
280
- focusFirst([this.selectedItem(), this.content()]);
414
+ /** Highlights the selected item (or the first enabled one) when the popup opens. */
415
+ highlightSelectedItem() {
416
+ const items = this.collection.items();
417
+ const selected = items.find((item) => valueComparator(this.rootContext.value(), item.value(), this.rootContext.isItemEqualToValue()));
418
+ if (selected) {
419
+ this.highlight.set(selected);
281
420
  }
421
+ else {
422
+ this.highlight.first();
423
+ }
424
+ }
425
+ scrollSelectedIntoView() {
426
+ this.selectedItem()?.scrollIntoView?.({ block: 'nearest' });
427
+ }
428
+ setKeyboardActive(value) {
429
+ this.keyboardActive = value;
430
+ }
431
+ isKeyboardActive() {
432
+ return this.keyboardActive;
282
433
  }
283
434
  handleKeyDown(event) {
284
435
  const keyEvent = event;
436
+ if (keyEvent.isComposing)
437
+ return;
285
438
  // select should not be navigated using tab key so we prevent it
286
- if (keyEvent.key === 'Tab')
439
+ if (keyEvent.key === 'Tab') {
287
440
  event.preventDefault();
288
- if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(keyEvent.key)) {
289
- const collectionItems = this.collection.items().map((i) => i.element);
290
- let candidateNodes = [...collectionItems];
291
- if (['ArrowUp', 'End'].includes(keyEvent.key))
292
- candidateNodes = candidateNodes.slice().reverse();
293
- if (['ArrowUp', 'ArrowDown'].includes(keyEvent.key)) {
294
- const currentElement = event.target;
295
- const currentIndex = candidateNodes.indexOf(currentElement);
296
- candidateNodes = candidateNodes.slice(currentIndex + 1);
441
+ return;
442
+ }
443
+ if (SELECTION_KEYS.includes(keyEvent.key)) {
444
+ event.preventDefault();
445
+ const item = this.highlight.highlightedItem();
446
+ if (item && !item.disabled()) {
447
+ this.rootContext.onValueChange(item.value());
448
+ if (!this.rootContext.multiple())
449
+ this.rootContext.onOpenChange(false);
297
450
  }
298
- setTimeout(() => focusFirst(candidateNodes));
451
+ return;
452
+ }
453
+ if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(keyEvent.key)) {
299
454
  event.preventDefault();
455
+ this.keyboardActive = true;
456
+ switch (keyEvent.key) {
457
+ case 'ArrowDown':
458
+ this.highlight.next();
459
+ break;
460
+ case 'ArrowUp':
461
+ this.highlight.previous();
462
+ break;
463
+ case 'Home':
464
+ this.highlight.first();
465
+ break;
466
+ case 'End':
467
+ this.highlight.last();
468
+ break;
469
+ }
300
470
  }
301
471
  }
302
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectContent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
303
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectContent, isStandalone: true, selector: "[rdxSelectContent]", outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside" }, host: { attributes: { "role": "listbox" }, listeners: { "keydown": "handleKeyDown($event)" }, properties: { "attr.data-state": "rootContext.open() ? \"open\" : \"closed\"", "dir": "rootContext.dir()", "style": "{\n display: 'flex',\n flexDirection: 'column',\n outline: 'none'\n }" } }, providers: [
304
- provideSelectContentContext(context$1),
472
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPopup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
473
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectPopup, isStandalone: true, selector: "[rdxSelectPopup]", outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside" }, host: { attributes: { "role": "listbox", "tabindex": "-1" }, listeners: { "keydown": "handleKeyDown($event)" }, properties: { "attr.aria-activedescendant": "highlight.activeId()", "attr.aria-multiselectable": "rootContext.multiple() ? \"true\" : undefined", "attr.data-state": "rootContext.open() ? \"open\" : \"closed\"", "attr.data-open": "rootContext.open() ? \"\" : undefined", "attr.data-closed": "rootContext.open() ? undefined : \"\"", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "dir": "rootContext.dir()", "style": "{\n display: 'flex',\n flexDirection: 'column',\n outline: 'none'\n }" } }, providers: [
474
+ provideSelectPopupContext(context$1),
305
475
  provideRdxDismissableLayerConfig(() => {
306
476
  return {
307
- disableOutsidePointerEvents: signal(true)
477
+ disableOutsidePointerEvents: injectSelectRootContext().modal
308
478
  };
309
479
  })
310
480
  ], queries: [{ propertyName: "positioner", first: true, predicate: RDX_SELECT_POSITIONER_TOKEN, descendants: true }], hostDirectives: [{ directive: i1$1.RdxFocusScope }, { directive: i2.RdxDismissableLayer }, { directive: i3.RdxCollectionProvider }], ngImport: i0 }); }
311
481
  }
312
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectContent, decorators: [{
482
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPopup, decorators: [{
313
483
  type: Directive,
314
484
  args: [{
315
- selector: '[rdxSelectContent]',
485
+ selector: '[rdxSelectPopup]',
316
486
  hostDirectives: [RdxFocusScope, RdxDismissableLayer, RdxCollectionProvider],
317
487
  providers: [
318
- provideSelectContentContext(context$1),
488
+ provideSelectPopupContext(context$1),
319
489
  provideRdxDismissableLayerConfig(() => {
320
490
  return {
321
- disableOutsidePointerEvents: signal(true)
491
+ disableOutsidePointerEvents: injectSelectRootContext().modal
322
492
  };
323
493
  })
324
494
  ],
325
495
  host: {
326
496
  role: 'listbox',
497
+ tabindex: '-1',
498
+ '[attr.aria-activedescendant]': 'highlight.activeId()',
499
+ '[attr.aria-multiselectable]': 'rootContext.multiple() ? "true" : undefined',
327
500
  '[attr.data-state]': 'rootContext.open() ? "open" : "closed"',
501
+ '[attr.data-open]': 'rootContext.open() ? "" : undefined',
502
+ '[attr.data-closed]': 'rootContext.open() ? undefined : ""',
503
+ '[attr.data-starting-style]': 'rootContext.transitionStatus() === "starting" ? "" : undefined',
504
+ '[attr.data-ending-style]': 'rootContext.transitionStatus() === "ending" ? "" : undefined',
328
505
  '[dir]': 'rootContext.dir()',
329
506
  '(keydown)': 'handleKeyDown($event)',
330
507
  '[style]': `{
@@ -339,25 +516,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
339
516
  args: [RDX_SELECT_POSITIONER_TOKEN, { descendants: true }]
340
517
  }] } });
341
518
 
342
- class RdxSelectGroup {
343
- constructor() {
344
- this.id = injectId('rdx-select-group-');
345
- }
346
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
347
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectGroup, isStandalone: true, selector: "[rdxSelectGroup]", host: { attributes: { "role": "group" }, properties: { "attr.aria-labelledby": "id" } }, exportAs: ["rdxSelectGroup"], ngImport: i0 }); }
348
- }
349
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectGroup, decorators: [{
350
- type: Directive,
351
- args: [{
352
- selector: '[rdxSelectGroup]',
353
- exportAs: 'rdxSelectGroup',
354
- host: {
355
- role: 'group',
356
- '[attr.aria-labelledby]': 'id'
357
- }
358
- }]
359
- }] });
360
-
361
519
  const context = () => {
362
520
  const context = inject(RdxSelectItem);
363
521
  return {
@@ -370,30 +528,33 @@ const context = () => {
370
528
  }
371
529
  };
372
530
  };
373
- const [injectSelectItemContext, provideSelectItemContext] = createContext('RdxSelectItemContext');
531
+ const [injectSelectItemContext, provideSelectItemContext] = createContext('RdxSelectItemContext', 'components/select');
374
532
  class RdxSelectItem {
375
533
  constructor() {
376
534
  this.rootContext = injectSelectRootContext();
377
- this.contentContext = injectSelectContentContext();
535
+ this.contentContext = injectSelectPopupContext();
536
+ this.collectionItem = inject(RdxCollectionItem);
378
537
  this.currentElement = inject(ElementRef);
379
538
  this.value = input(...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ []));
380
539
  this.textValue = input('', ...(ngDevMode ? [{ debugName: "textValue" }] : /* istanbul ignore next */ []));
381
540
  this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
382
541
  this.textValue$ = linkedSignal(this.textValue, ...(ngDevMode ? [{ debugName: "textValue$" }] : /* istanbul ignore next */ []));
383
- this.isSelected = computed(() => valueComparator(this.rootContext.value(), this.value(), this.rootContext.by()), ...(ngDevMode ? [{ debugName: "isSelected" }] : /* istanbul ignore next */ []));
384
- this.isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
542
+ this.isSelected = computed(() => valueComparator(this.rootContext.value(), this.value(), this.rootContext.isItemEqualToValue()), ...(ngDevMode ? [{ debugName: "isSelected" }] : /* istanbul ignore next */ []));
543
+ /** Highlighted via the highlight model (keyboard / hover), not DOM focus. */
544
+ this.isHighlighted = computed(() => this.contentContext.isHighlighted(this.collectionItem), ...(ngDevMode ? [{ debugName: "isHighlighted" }] : /* istanbul ignore next */ []));
545
+ /** Item id, referenced by the popup's `aria-activedescendant`. */
546
+ this.id = injectId('rdx-select-item-');
385
547
  this.textId = injectId('rdx-select-item-text-');
386
548
  this.afterNextRender = afterNextRender(() => {
387
549
  this.contentContext.itemRefCallback(this.currentElement.nativeElement, this.value(), this.disabled());
388
550
  });
389
551
  this.SELECT_SELECT = 'select.select';
390
552
  }
391
- onPointerDown(event) {
392
- event.currentTarget.focus({ preventScroll: true });
393
- }
394
553
  onPointerUp(event) {
395
554
  if (event.defaultPrevented)
396
555
  return;
556
+ if (this.disabled())
557
+ return;
397
558
  const eventDetail = { originalEvent: event, value: this.value() };
398
559
  handleAndDispatchCustomEvent(this.SELECT_SELECT, async (event) => {
399
560
  if (event.defaultPrevented)
@@ -407,19 +568,18 @@ class RdxSelectItem {
407
568
  onPointerLeave(event) {
408
569
  if (event.defaultPrevented)
409
570
  return;
410
- if (event.currentTarget === getActiveElement())
411
- this.contentContext.onItemLeave?.();
571
+ this.contentContext.onItemLeave?.();
412
572
  }
413
573
  onPointerMove(event) {
414
574
  if (event.defaultPrevented)
415
575
  return;
416
- if (this.disabled()) {
417
- this.contentContext.onItemLeave?.();
576
+ // Ignore pointer events synthesized by keyboard-driven scrolling (don't steal the highlight).
577
+ if (this.contentContext.isKeyboardActive()) {
578
+ this.contentContext.setKeyboardActive(false);
579
+ return;
418
580
  }
419
- else {
420
- // even though safari doesn't support this option, it's acceptable
421
- // as it only means it might scroll a few pixels when using the pointer.
422
- event.currentTarget?.focus({ preventScroll: true });
581
+ if (!this.disabled()) {
582
+ this.contentContext.highlightItem(this.collectionItem);
423
583
  }
424
584
  }
425
585
  handleKeyDown(event) {
@@ -427,52 +587,35 @@ class RdxSelectItem {
427
587
  if (event.defaultPrevented)
428
588
  return;
429
589
  if (SELECTION_KEYS.includes(keyEvent.key))
430
- this.handleSelectCustomEvent(keyEvent);
431
- // prevent page scroll if using the space key to select an item
432
- if (keyEvent.key === ' ')
433
- event.preventDefault();
434
- }
435
- async handleSelectCustomEvent(event) {
436
- if (event.defaultPrevented)
437
- return;
438
- const eventDetail = { originalEvent: event, value: this.value() };
439
- handleAndDispatchCustomEvent(this.SELECT_SELECT, async (event) => {
440
- if (event.defaultPrevented)
441
- return;
442
- if (!this.disabled()) {
443
- this.rootContext.onValueChange(this.value());
444
- if (!this.rootContext.multiple())
445
- this.rootContext.onOpenChange(false);
446
- }
447
- }, eventDetail);
590
+ this.onPointerUp(keyEvent);
448
591
  }
449
592
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
450
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSelectItem, isStandalone: true, selector: "[rdxSelectItem]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, textValue: { classPropertyName: "textValue", publicName: "textValue", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "option" }, listeners: { "focus": "isFocused.set(true)", "blur": "isFocused.set(false)", "pointerdown": "onPointerDown($event)", "pointerup": "onPointerUp($event)", "pointerleave": "onPointerLeave($event)", "pointermove": "onPointerMove($event)", "keydown": "handleKeyDown($event)" }, properties: { "attr.tabindex": "disabled() ? undefined : -1", "attr.aria-selected": "isSelected() ? \"checked\" : \"unchecked\"", "attr.data-state": "isSelected() ? \"checked\" : \"unchecked\"", "attr.data-highlighted": "isFocused() ? \"\" : undefined" } }, providers: [provideSelectItemContext(context)], hostDirectives: [{ directive: i3.RdxCollectionItem, inputs: ["value", "value"] }], ngImport: i0 }); }
593
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSelectItem, isStandalone: true, selector: "[rdxSelectItem]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, textValue: { classPropertyName: "textValue", publicName: "textValue", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "option" }, listeners: { "pointerup": "onPointerUp($event)", "pointerleave": "onPointerLeave($event)", "pointermove": "onPointerMove($event)" }, properties: { "attr.id": "id", "attr.aria-selected": "isSelected()", "attr.aria-disabled": "disabled() ? \"true\" : undefined", "attr.data-state": "isSelected() ? \"checked\" : \"unchecked\"", "attr.data-selected": "isSelected() ? \"\" : undefined", "attr.data-highlighted": "isHighlighted() ? \"\" : undefined", "attr.data-disabled": "disabled() ? \"\" : undefined" } }, providers: [provideSelectItemContext(context)], exportAs: ["rdxSelectItem"], hostDirectives: [{ directive: i3.RdxCollectionItem, inputs: ["value", "value", "disabled", "disabled"] }], ngImport: i0 }); }
451
594
  }
452
595
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectItem, decorators: [{
453
596
  type: Directive,
454
597
  args: [{
455
598
  selector: '[rdxSelectItem]',
599
+ exportAs: 'rdxSelectItem',
456
600
  providers: [provideSelectItemContext(context)],
457
601
  hostDirectives: [
458
602
  {
459
603
  directive: RdxCollectionItem,
460
- inputs: ['value']
604
+ inputs: ['value', 'disabled']
461
605
  }
462
606
  ],
463
607
  host: {
464
608
  role: 'option',
465
- '[attr.tabindex]': 'disabled() ? undefined : -1',
466
- '[attr.aria-selected]': 'isSelected() ? "checked" : "unchecked"',
609
+ '[attr.id]': 'id',
610
+ '[attr.aria-selected]': 'isSelected()',
611
+ '[attr.aria-disabled]': 'disabled() ? "true" : undefined',
467
612
  '[attr.data-state]': 'isSelected() ? "checked" : "unchecked"',
468
- '[attr.data-highlighted]': 'isFocused() ? "" : undefined',
469
- '(focus)': 'isFocused.set(true)',
470
- '(blur)': 'isFocused.set(false)',
471
- '(pointerdown)': 'onPointerDown($event)',
613
+ '[attr.data-selected]': 'isSelected() ? "" : undefined',
614
+ '[attr.data-highlighted]': 'isHighlighted() ? "" : undefined',
615
+ '[attr.data-disabled]': 'disabled() ? "" : undefined',
472
616
  '(pointerup)': 'onPointerUp($event)',
473
617
  '(pointerleave)': 'onPointerLeave($event)',
474
- '(pointermove)': 'onPointerMove($event)',
475
- '(keydown)': 'handleKeyDown($event)'
618
+ '(pointermove)': 'onPointerMove($event)'
476
619
  }
477
620
  }]
478
621
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], textValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "textValue", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
@@ -499,7 +642,7 @@ class RdxSelectItemText {
499
642
  constructor() {
500
643
  this.elementRef = inject((ElementRef));
501
644
  this.rootContext = injectSelectRootContext();
502
- this.contentContext = injectSelectContentContext();
645
+ this.contentContext = injectSelectPopupContext();
503
646
  this.itemContext = injectSelectItemContext();
504
647
  this.optionProps = computed(() => {
505
648
  return {
@@ -531,38 +674,87 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
531
674
  }]
532
675
  }], ctorParameters: () => [] });
533
676
 
534
- class RdxSelectLabel {
535
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectLabel, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
536
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectLabel, isStandalone: true, selector: "[rdxSelectLabel]", ngImport: i0 }); }
677
+ class RdxSelectList {
678
+ constructor() {
679
+ this.contentContext = injectSelectPopupContext();
680
+ this.elementRef = inject((ElementRef));
681
+ this.prevScrollTopRef = signal(0, ...(ngDevMode ? [{ debugName: "prevScrollTopRef" }] : /* istanbul ignore next */ []));
682
+ afterNextRender(() => {
683
+ this.contentContext?.onViewportChange(this.elementRef.nativeElement);
684
+ });
685
+ }
686
+ handleScroll(event) {
687
+ const viewport = event.currentTarget;
688
+ this.prevScrollTopRef.set(viewport.scrollTop);
689
+ }
690
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectList, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
691
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectList, isStandalone: true, selector: "[rdxSelectList]", host: { attributes: { "role": "presentation" }, listeners: { "scroll": "handleScroll($event)" }, properties: { "attr.data-rdx-select-list": "\"\"", "style": "{\n position: 'relative',\n flex: 1,\n overflow: 'hidden auto',\n scrollbarWidth: 'none'\n }" } }, ngImport: i0 }); }
537
692
  }
538
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectLabel, decorators: [{
693
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectList, decorators: [{
539
694
  type: Directive,
540
695
  args: [{
541
- selector: '[rdxSelectLabel]',
542
- host: {}
696
+ selector: '[rdxSelectList]',
697
+ host: {
698
+ role: 'presentation',
699
+ '[attr.data-rdx-select-list]': '""',
700
+ '[style]': `{
701
+ position: 'relative',
702
+ flex: 1,
703
+ overflow: 'hidden auto',
704
+ scrollbarWidth: 'none'
705
+ }`,
706
+ '(scroll)': 'handleScroll($event)'
707
+ }
543
708
  }]
544
- }] });
709
+ }], ctorParameters: () => [] });
545
710
 
546
- class RdxSelectPopperPositionContent {
711
+ class RdxSelectPortal {
547
712
  constructor() {
548
- this.rootContext = injectSelectRootContext();
713
+ /**
714
+ * Optional container to portal the content into. Defaults to `document.body` when not set.
715
+ */
716
+ this.container = input(...(ngDevMode ? [undefined, { debugName: "container" }] : /* istanbul ignore next */ []));
549
717
  }
550
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPopperPositionContent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
551
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectPopperPositionContent, isStandalone: true, selector: "[rdxSelectPopperPositionContent]", host: { attributes: { "role": "listbox" }, properties: { "id": "rootContext.contentId" } }, hostDirectives: [{ directive: i1.RdxPopperContent }], ngImport: i0 }); }
718
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPortal, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
719
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSelectPortal, isStandalone: true, selector: "[rdxSelectPortal]", inputs: { container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null } }, hostDirectives: [{ directive: i1$2.RdxPortal, inputs: ["container", "container"] }], ngImport: i0 }); }
552
720
  }
553
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPopperPositionContent, decorators: [{
721
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPortal, decorators: [{
554
722
  type: Directive,
555
723
  args: [{
556
- selector: '[rdxSelectPopperPositionContent]',
557
- hostDirectives: [RdxPopperContent],
558
- host: {
559
- role: 'listbox',
560
- '[id]': 'rootContext.contentId'
561
- }
724
+ selector: '[rdxSelectPortal]',
725
+ hostDirectives: [
726
+ {
727
+ directive: RdxPortal,
728
+ inputs: ['container']
729
+ }
730
+ ]
731
+ }]
732
+ }], propDecorators: { container: [{ type: i0.Input, args: [{ isSignal: true, alias: "container", required: false }] }] } });
733
+
734
+ class RdxSelectPortalPresence {
735
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPortalPresence, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
736
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectPortalPresence, isStandalone: true, selector: "ng-template[rdxSelectPortalPresence]", providers: [
737
+ provideRdxPresenceContext(() => {
738
+ const context = injectSelectRootContext();
739
+ return { present: context.open };
740
+ })
741
+ ], hostDirectives: [{ directive: i1$3.RdxPresenceDirective }], ngImport: i0 }); }
742
+ }
743
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPortalPresence, decorators: [{
744
+ type: Directive,
745
+ args: [{
746
+ selector: 'ng-template[rdxSelectPortalPresence]',
747
+ hostDirectives: [RdxPresenceDirective],
748
+ providers: [
749
+ provideRdxPresenceContext(() => {
750
+ const context = injectSelectRootContext();
751
+ return { present: context.open };
752
+ })
753
+ ]
562
754
  }]
563
755
  }] });
564
756
 
565
- class RdxSelectPopperPositionWrapper {
757
+ class RdxSelectPositioner {
566
758
  constructor() {
567
759
  /**
568
760
  * The preferred side of the anchor to render against when open.
@@ -619,22 +811,22 @@ class RdxSelectPopperPositionWrapper {
619
811
  */
620
812
  this.placed = outputFromObservable(outputToObservable(inject(RdxPopperContentWrapper).placed));
621
813
  }
622
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPopperPositionWrapper, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
623
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSelectPopperPositionWrapper, isStandalone: true, selector: "[rdxSelectPopperPositionWrapper]", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, alignOffset: { classPropertyName: "alignOffset", publicName: "alignOffset", isSignal: true, isRequired: false, transformFunction: null }, arrowPadding: { classPropertyName: "arrowPadding", publicName: "arrowPadding", isSignal: true, isRequired: false, transformFunction: null }, avoidCollisions: { classPropertyName: "avoidCollisions", publicName: "avoidCollisions", isSignal: true, isRequired: false, transformFunction: null }, collisionBoundary: { classPropertyName: "collisionBoundary", publicName: "collisionBoundary", isSignal: true, isRequired: false, transformFunction: null }, collisionPadding: { classPropertyName: "collisionPadding", publicName: "collisionPadding", isSignal: true, isRequired: false, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null }, hideWhenDetached: { classPropertyName: "hideWhenDetached", publicName: "hideWhenDetached", isSignal: true, isRequired: false, transformFunction: null }, updatePositionStrategy: { classPropertyName: "updatePositionStrategy", publicName: "updatePositionStrategy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { placed: "placed" }, host: { properties: { "style": "{\n 'boxSizing': 'border-box',\n '--radix-tooltip-content-transform-origin': 'var(--radix-popper-transform-origin)',\n '--radix-tooltip-content-available-width': 'var(--radix-popper-available-width)',\n '--radix-tooltip-content-available-height': 'var(--radix-popper-available-height)',\n '--radix-tooltip-trigger-width': 'var(--radix-popper-anchor-width)',\n '--radix-tooltip-trigger-height': 'var(--radix-popper-anchor-height)',\n }" } }, providers: [
814
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPositioner, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
815
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSelectPositioner, isStandalone: true, selector: "[rdxSelectPositioner]", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, alignOffset: { classPropertyName: "alignOffset", publicName: "alignOffset", isSignal: true, isRequired: false, transformFunction: null }, arrowPadding: { classPropertyName: "arrowPadding", publicName: "arrowPadding", isSignal: true, isRequired: false, transformFunction: null }, avoidCollisions: { classPropertyName: "avoidCollisions", publicName: "avoidCollisions", isSignal: true, isRequired: false, transformFunction: null }, collisionBoundary: { classPropertyName: "collisionBoundary", publicName: "collisionBoundary", isSignal: true, isRequired: false, transformFunction: null }, collisionPadding: { classPropertyName: "collisionPadding", publicName: "collisionPadding", isSignal: true, isRequired: false, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null }, hideWhenDetached: { classPropertyName: "hideWhenDetached", publicName: "hideWhenDetached", isSignal: true, isRequired: false, transformFunction: null }, updatePositionStrategy: { classPropertyName: "updatePositionStrategy", publicName: "updatePositionStrategy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { placed: "placed" }, host: { properties: { "style": "{\n 'boxSizing': 'border-box',\n '--radix-tooltip-content-transform-origin': 'var(--radix-popper-transform-origin)',\n '--radix-tooltip-content-available-width': 'var(--radix-popper-available-width)',\n '--radix-tooltip-content-available-height': 'var(--radix-popper-available-height)',\n '--radix-tooltip-trigger-width': 'var(--radix-popper-anchor-width)',\n '--radix-tooltip-trigger-height': 'var(--radix-popper-anchor-height)',\n }" } }, providers: [
624
816
  {
625
817
  provide: RDX_SELECT_POSITIONER_TOKEN,
626
- useExisting: forwardRef(() => RdxSelectPopperPositionWrapper)
818
+ useExisting: forwardRef(() => RdxSelectPositioner)
627
819
  }
628
820
  ], hostDirectives: [{ directive: i1.RdxPopperContentWrapper, inputs: ["side", "side", "sideOffset", "sideOffset", "align", "align", "alignOffset", "alignOffset", "arrowPadding", "arrowPadding", "avoidCollisions", "avoidCollisions", "collisionBoundary", "collisionBoundary", "collisionPadding", "collisionPadding", "sticky", "sticky", "hideWhenDetached", "hideWhenDetached", "updatePositionStrategy", "updatePositionStrategy"] }], ngImport: i0 }); }
629
821
  }
630
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPopperPositionWrapper, decorators: [{
822
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPositioner, decorators: [{
631
823
  type: Directive,
632
824
  args: [{
633
- selector: '[rdxSelectPopperPositionWrapper]',
825
+ selector: '[rdxSelectPositioner]',
634
826
  providers: [
635
827
  {
636
828
  provide: RDX_SELECT_POSITIONER_TOKEN,
637
- useExisting: forwardRef(() => RdxSelectPopperPositionWrapper)
829
+ useExisting: forwardRef(() => RdxSelectPositioner)
638
830
  }
639
831
  ],
640
832
  hostDirectives: [
@@ -669,60 +861,75 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
669
861
  }]
670
862
  }], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], sideOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "sideOffset", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], alignOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignOffset", required: false }] }], arrowPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowPadding", required: false }] }], avoidCollisions: [{ type: i0.Input, args: [{ isSignal: true, alias: "avoidCollisions", required: false }] }], collisionBoundary: [{ type: i0.Input, args: [{ isSignal: true, alias: "collisionBoundary", required: false }] }], collisionPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "collisionPadding", required: false }] }], sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }], hideWhenDetached: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideWhenDetached", required: false }] }], updatePositionStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "updatePositionStrategy", required: false }] }], placed: [{ type: i0.Output, args: ["placed"] }] } });
671
863
 
672
- class RdxSelectPortal {
864
+ class RdxSelectPositionerContent {
673
865
  constructor() {
674
- /**
675
- * Optional container to portal the content into. Defaults to `document.body` when not set.
676
- */
677
- this.container = input(...(ngDevMode ? [undefined, { debugName: "container" }] : /* istanbul ignore next */ []));
866
+ this.rootContext = injectSelectRootContext();
678
867
  }
679
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPortal, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
680
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSelectPortal, isStandalone: true, selector: "[rdxSelectPortal]", inputs: { container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null } }, hostDirectives: [{ directive: i1$2.RdxPortal, inputs: ["container", "container"] }], ngImport: i0 }); }
868
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPositionerContent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
869
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectPositionerContent, isStandalone: true, selector: "[rdxSelectPositionerContent]", host: { attributes: { "role": "listbox" }, properties: { "id": "rootContext.contentId" } }, hostDirectives: [{ directive: i1.RdxPopperContent }], ngImport: i0 }); }
681
870
  }
682
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPortal, decorators: [{
871
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPositionerContent, decorators: [{
683
872
  type: Directive,
684
873
  args: [{
685
- selector: '[rdxSelectPortal]',
686
- hostDirectives: [
687
- {
688
- directive: RdxPortal,
689
- inputs: ['container']
690
- }
691
- ]
874
+ selector: '[rdxSelectPositionerContent]',
875
+ hostDirectives: [RdxPopperContent],
876
+ host: {
877
+ role: 'listbox',
878
+ '[id]': 'rootContext.contentId'
879
+ }
692
880
  }]
693
- }], propDecorators: { container: [{ type: i0.Input, args: [{ isSignal: true, alias: "container", required: false }] }] } });
881
+ }] });
694
882
 
695
- class RdxSelectPortalPresence {
696
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPortalPresence, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
697
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectPortalPresence, isStandalone: true, selector: "ng-template[rdxSelectPortalPresence]", providers: [
698
- provideRdxPresenceContext(() => {
699
- const context = injectSelectRootContext();
700
- return { present: context.open };
701
- })
702
- ], hostDirectives: [{ directive: i1$3.RdxPresenceDirective }], ngImport: i0 }); }
883
+ /**
884
+ * A visual divider between groups of items.
885
+ *
886
+ * @group Components
887
+ */
888
+ class RdxSelectSeparator {
889
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectSeparator, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
890
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectSeparator, isStandalone: true, selector: "[rdxSelectSeparator]", host: { attributes: { "role": "separator", "aria-hidden": "true" } }, exportAs: ["rdxSelectSeparator"], ngImport: i0 }); }
703
891
  }
704
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectPortalPresence, decorators: [{
892
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectSeparator, decorators: [{
705
893
  type: Directive,
706
894
  args: [{
707
- selector: 'ng-template[rdxSelectPortalPresence]',
708
- hostDirectives: [RdxPresenceDirective],
709
- providers: [
710
- provideRdxPresenceContext(() => {
711
- const context = injectSelectRootContext();
712
- return { present: context.open };
713
- })
714
- ]
895
+ selector: '[rdxSelectSeparator]',
896
+ exportAs: 'rdxSelectSeparator',
897
+ host: {
898
+ role: 'separator',
899
+ 'aria-hidden': 'true'
900
+ }
715
901
  }]
716
902
  }] });
717
903
 
904
+ const attr = (value) => (value ? '' : undefined);
718
905
  class RdxSelectTrigger {
719
906
  constructor() {
720
907
  this.rootContext = injectSelectRootContext();
721
908
  this.elementRef = inject(ElementRef);
909
+ this.fieldRootContext = injectFieldRootContext(true);
910
+ /** The trigger id; Field labels and descriptions reference it for accessible relationships. */
911
+ this.id = input(injectId('rdx-select-trigger-'), ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
722
912
  this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
723
- this.isDisabled = computed(() => this.rootContext.disabled() || this.disabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
913
+ this.isDisabled = computed(() => this.rootContext.disabled() || this.disabled() || Boolean(this.fieldRootContext?.disabledState()), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
914
+ this.invalidState = computed(() => Boolean(this.fieldRootContext?.invalidState()), ...(ngDevMode ? [{ debugName: "invalidState" }] : /* istanbul ignore next */ []));
915
+ this.requiredState = computed(() => Boolean(this.fieldRootContext?.requiredState()), ...(ngDevMode ? [{ debugName: "requiredState" }] : /* istanbul ignore next */ []));
916
+ this.filledState = computed(() => !this.rootContext.isEmptyModelValue() || Boolean(this.fieldRootContext?.filledState()), ...(ngDevMode ? [{ debugName: "filledState" }] : /* istanbul ignore next */ []));
917
+ this.focusedState = computed(() => Boolean(this.fieldRootContext?.focusedState()), ...(ngDevMode ? [{ debugName: "focusedState" }] : /* istanbul ignore next */ []));
918
+ this.describedBy = computed(() => {
919
+ if (!this.fieldRootContext) {
920
+ return undefined;
921
+ }
922
+ const ids = [
923
+ ...this.fieldRootContext.descriptionIds(),
924
+ ...(this.fieldRootContext.invalidState() ? this.fieldRootContext.errorIds() : [])
925
+ ];
926
+ return ids.length ? ids.join(' ') : undefined;
927
+ }, ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
928
+ this.dataAttr = attr;
724
929
  afterNextRender(() => {
725
930
  this.rootContext.onTriggerChange(this.elementRef);
931
+ this.fieldRootContext?.setControlId(this.id());
932
+ this.fieldRootContext?.setFilled(!this.rootContext.isEmptyModelValue());
726
933
  });
727
934
  }
728
935
  handleOpen() {
@@ -778,8 +985,15 @@ class RdxSelectTrigger {
778
985
  event.preventDefault();
779
986
  }
780
987
  }
988
+ onFocus() {
989
+ this.fieldRootContext?.setFocused(true);
990
+ }
991
+ onBlur() {
992
+ this.fieldRootContext?.setFocused(false);
993
+ this.fieldRootContext?.setTouched(true);
994
+ }
781
995
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
782
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSelectTrigger, isStandalone: true, selector: "button[rdxSelectTrigger]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "combobox", "type": "button" }, listeners: { "click": "onClickHandler($event)", "pointerdown": "onPointerDown($event)", "pointerup": "onPointerUp($event)", "keydown": "onKeydown($event)" }, properties: { "attr.disabled": "isDisabled() ? \"\" : undefined", "dir": "rootContext.dir()", "attr.data-state": "rootContext.open() ? \"open\" : \"closed\"", "attr.data-disabled": "isDisabled() ? \"\" : undefined" } }, hostDirectives: [{ directive: i1.RdxPopperAnchor }], ngImport: i0 }); }
996
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxSelectTrigger, isStandalone: true, selector: "button[rdxSelectTrigger]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "combobox", "type": "button" }, listeners: { "click": "onClickHandler($event)", "pointerdown": "onPointerDown($event)", "pointerup": "onPointerUp($event)", "keydown": "onKeydown($event)", "focus": "onFocus()", "blur": "onBlur()" }, properties: { "attr.id": "id()", "attr.aria-describedby": "describedBy()", "attr.aria-invalid": "invalidState() ? \"true\" : undefined", "attr.aria-required": "requiredState() ? \"true\" : undefined", "attr.disabled": "isDisabled() ? \"\" : undefined", "dir": "rootContext.dir()", "attr.data-state": "rootContext.open() ? \"open\" : \"closed\"", "attr.data-popup-open": "dataAttr(rootContext.open())", "attr.data-placeholder": "dataAttr(rootContext.isEmptyModelValue())", "attr.data-disabled": "dataAttr(isDisabled())", "attr.data-invalid": "dataAttr(invalidState())", "attr.data-valid": "dataAttr(!invalidState())", "attr.data-required": "dataAttr(requiredState())", "attr.data-filled": "dataAttr(filledState())", "attr.data-focused": "dataAttr(focusedState())" } }, hostDirectives: [{ directive: i1.RdxPopperAnchor }], ngImport: i0 }); }
783
997
  }
784
998
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectTrigger, decorators: [{
785
999
  type: Directive,
@@ -789,17 +1003,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
789
1003
  host: {
790
1004
  role: 'combobox',
791
1005
  type: 'button',
1006
+ '[attr.id]': 'id()',
1007
+ '[attr.aria-describedby]': 'describedBy()',
1008
+ '[attr.aria-invalid]': 'invalidState() ? "true" : undefined',
1009
+ '[attr.aria-required]': 'requiredState() ? "true" : undefined',
792
1010
  '[attr.disabled]': 'isDisabled() ? "" : undefined',
793
1011
  '[dir]': 'rootContext.dir()',
794
1012
  '[attr.data-state]': 'rootContext.open() ? "open" : "closed"',
795
- '[attr.data-disabled]': 'isDisabled() ? "" : undefined',
1013
+ '[attr.data-popup-open]': 'dataAttr(rootContext.open())',
1014
+ '[attr.data-placeholder]': 'dataAttr(rootContext.isEmptyModelValue())',
1015
+ '[attr.data-disabled]': 'dataAttr(isDisabled())',
1016
+ '[attr.data-invalid]': 'dataAttr(invalidState())',
1017
+ '[attr.data-valid]': 'dataAttr(!invalidState())',
1018
+ '[attr.data-required]': 'dataAttr(requiredState())',
1019
+ '[attr.data-filled]': 'dataAttr(filledState())',
1020
+ '[attr.data-focused]': 'dataAttr(focusedState())',
796
1021
  '(click)': 'onClickHandler($event)',
797
1022
  '(pointerdown)': 'onPointerDown($event)',
798
1023
  '(pointerup)': 'onPointerUp($event)',
799
- '(keydown)': 'onKeydown($event)'
1024
+ '(keydown)': 'onKeydown($event)',
1025
+ '(focus)': 'onFocus()',
1026
+ '(blur)': 'onBlur()'
800
1027
  }
801
1028
  }]
802
- }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
1029
+ }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
803
1030
 
804
1031
  class RdxSelectValue {
805
1032
  constructor() {
@@ -810,16 +1037,17 @@ class RdxSelectValue {
810
1037
  return this.selectedLabel().length ? this.selectedLabel().join(', ') : this.placeholder();
811
1038
  }, ...(ngDevMode ? [{ debugName: "slotText" }] : /* istanbul ignore next */ []));
812
1039
  this.selectedLabel = computed(() => {
813
- // eslint-disable-next-line no-useless-assignment
814
- let list = [];
815
1040
  const options = Array.from(this.rootContext.optionsSet());
816
- const getOption = (value) => options.find((option) => valueComparator(value, option.value, this.rootContext.by()));
817
- if (Array.isArray(this.rootContext.value())) {
818
- list = Array(this.rootContext.value()).map((value) => getOption(value)?.textContent ?? '');
819
- }
820
- else {
821
- list = [getOption(this.rootContext.value())?.textContent ?? ''];
822
- }
1041
+ const customLabel = this.rootContext.itemToStringLabel();
1042
+ const labelFor = (value) => {
1043
+ if (customLabel && value !== undefined && value !== null) {
1044
+ return customLabel(value);
1045
+ }
1046
+ const option = options.find((o) => valueComparator(value, o.value, this.rootContext.isItemEqualToValue()));
1047
+ return option?.textContent ?? '';
1048
+ };
1049
+ const value = this.rootContext.value();
1050
+ const list = Array.isArray(value) ? value.map((v) => labelFor(v)) : [labelFor(value)];
823
1051
  return list.filter(Boolean);
824
1052
  }, ...(ngDevMode ? [{ debugName: "selectedLabel" }] : /* istanbul ignore next */ []));
825
1053
  afterNextRender(() => {
@@ -840,60 +1068,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
840
1068
  }]
841
1069
  }], ctorParameters: () => [], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }] } });
842
1070
 
843
- class RdxSelectViewport {
844
- constructor() {
845
- this.contentContext = injectSelectContentContext();
846
- this.elementRef = inject((ElementRef));
847
- this.prevScrollTopRef = signal(0, ...(ngDevMode ? [{ debugName: "prevScrollTopRef" }] : /* istanbul ignore next */ []));
848
- afterNextRender(() => {
849
- this.contentContext?.onViewportChange(this.elementRef.nativeElement);
850
- });
851
- }
852
- handleScroll(event) {
853
- const viewport = event.currentTarget;
854
- this.prevScrollTopRef.set(viewport.scrollTop);
855
- }
856
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectViewport, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
857
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxSelectViewport, isStandalone: true, selector: "[rdxSelectViewport]", host: { attributes: { "role": "presentation" }, listeners: { "scroll": "handleScroll($event)" }, properties: { "attr.data-rdx-select-viewport": "\"\"", "style": "{\n position: 'relative',\n flex: 1,\n overflow: 'hidden auto',\n scrollbarWidth: 'none'\n }" } }, ngImport: i0 }); }
858
- }
859
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxSelectViewport, decorators: [{
860
- type: Directive,
861
- args: [{
862
- selector: '[rdxSelectViewport]',
863
- host: {
864
- role: 'presentation',
865
- '[attr.data-rdx-select-viewport]': '""',
866
- '[style]': `{
867
- position: 'relative',
868
- flex: 1,
869
- overflow: 'hidden auto',
870
- scrollbarWidth: 'none'
871
- }`,
872
- '(scroll)': 'handleScroll($event)'
873
- }
874
- }]
875
- }], ctorParameters: () => [] });
876
-
877
1071
  const _importsSelect = [
878
1072
  RdxSelectRoot,
879
1073
  RdxSelectPortal,
880
1074
  RdxSelectTrigger,
881
1075
  RdxSelectValue,
882
- RdxSelectContent,
883
- RdxSelectViewport,
1076
+ RdxSelectPopup,
1077
+ RdxSelectList,
884
1078
  RdxSelectItemIndicator,
885
1079
  RdxSelectItem,
886
1080
  RdxSelectItemText,
887
- RdxSelectLabel,
1081
+ RdxSelectGroupLabel,
888
1082
  RdxSelectGroup,
889
- RdxSelectPopperPositionContent,
890
- RdxSelectPopperPositionWrapper,
891
- RdxSelectPortalPresence
1083
+ RdxSelectPositionerContent,
1084
+ RdxSelectPositioner,
1085
+ RdxSelectPortalPresence,
1086
+ RdxSelectIcon,
1087
+ RdxSelectSeparator,
1088
+ RdxSelectBackdrop
892
1089
  ];
893
1090
 
894
1091
  /**
895
1092
  * Generated bundle index. Do not edit.
896
1093
  */
897
1094
 
898
- export { CONTENT_MARGIN, OPEN_KEYS, RDX_SELECT_POSITIONER_TOKEN, RdxSelectContent, RdxSelectGroup, RdxSelectItem, RdxSelectItemIndicator, RdxSelectItemText, RdxSelectLabel, RdxSelectPopperPositionContent, RdxSelectPopperPositionWrapper, RdxSelectPortal, RdxSelectPortalPresence, RdxSelectRoot, RdxSelectTrigger, RdxSelectValue, RdxSelectViewport, SELECTION_KEYS, _importsSelect, compare, focusFirst, injectSelectContentContext, injectSelectItemContext, injectSelectRootContext, provideSelectContentContext, provideSelectItemContext, provideSelectRootContext, shouldShowPlaceholder, valueComparator };
1095
+ export { CONTENT_MARGIN, OPEN_KEYS, RDX_SELECT_POSITIONER_TOKEN, RdxSelectBackdrop, RdxSelectGroup, RdxSelectGroupLabel, RdxSelectIcon, RdxSelectItem, RdxSelectItemIndicator, RdxSelectItemText, RdxSelectList, RdxSelectPopup, RdxSelectPortal, RdxSelectPortalPresence, RdxSelectPositioner, RdxSelectPositionerContent, RdxSelectRoot, RdxSelectSeparator, RdxSelectTrigger, RdxSelectValue, SELECTION_KEYS, _importsSelect, compare, focusFirst, injectSelectItemContext, injectSelectPopupContext, injectSelectRootContext, provideSelectItemContext, provideSelectPopupContext, provideSelectRootContext, shouldShowPlaceholder, valueComparator };
899
1096
  //# sourceMappingURL=radix-ng-primitives-select.mjs.map