@radix-ng/primitives 1.0.4 → 1.0.6

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 (126) hide show
  1. package/fesm2022/radix-ng-primitives-accordion.mjs +35 -27
  2. package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
  3. package/fesm2022/radix-ng-primitives-alert-dialog.mjs +34 -34
  4. package/fesm2022/radix-ng-primitives-arrow.mjs +3 -3
  5. package/fesm2022/radix-ng-primitives-aspect-ratio.mjs +5 -4
  6. package/fesm2022/radix-ng-primitives-aspect-ratio.mjs.map +1 -1
  7. package/fesm2022/radix-ng-primitives-autocomplete.mjs +175 -125
  8. package/fesm2022/radix-ng-primitives-autocomplete.mjs.map +1 -1
  9. package/fesm2022/radix-ng-primitives-avatar.mjs +25 -19
  10. package/fesm2022/radix-ng-primitives-avatar.mjs.map +1 -1
  11. package/fesm2022/radix-ng-primitives-button.mjs +11 -7
  12. package/fesm2022/radix-ng-primitives-button.mjs.map +1 -1
  13. package/fesm2022/radix-ng-primitives-calendar.mjs +140 -90
  14. package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
  15. package/fesm2022/radix-ng-primitives-checkbox.mjs +61 -40
  16. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  17. package/fesm2022/radix-ng-primitives-collapsible.mjs +35 -24
  18. package/fesm2022/radix-ng-primitives-collapsible.mjs.map +1 -1
  19. package/fesm2022/radix-ng-primitives-combobox.mjs +278 -177
  20. package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -1
  21. package/fesm2022/radix-ng-primitives-composite.mjs +76 -35
  22. package/fesm2022/radix-ng-primitives-composite.mjs.map +1 -1
  23. package/fesm2022/radix-ng-primitives-config.mjs +7 -5
  24. package/fesm2022/radix-ng-primitives-config.mjs.map +1 -1
  25. package/fesm2022/radix-ng-primitives-context-menu.mjs +48 -22
  26. package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
  27. package/fesm2022/radix-ng-primitives-core.mjs +44 -28
  28. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  29. package/fesm2022/radix-ng-primitives-cropper.mjs +73 -45
  30. package/fesm2022/radix-ng-primitives-cropper.mjs.map +1 -1
  31. package/fesm2022/radix-ng-primitives-date-field.mjs +70 -40
  32. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  33. package/fesm2022/radix-ng-primitives-dialog.mjs +93 -67
  34. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  35. package/fesm2022/radix-ng-primitives-direction-provider.mjs +5 -4
  36. package/fesm2022/radix-ng-primitives-direction-provider.mjs.map +1 -1
  37. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs +20 -16
  38. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs.map +1 -1
  39. package/fesm2022/radix-ng-primitives-drawer.mjs +107 -81
  40. package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -1
  41. package/fesm2022/radix-ng-primitives-editable.mjs +53 -39
  42. package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
  43. package/fesm2022/radix-ng-primitives-field.mjs +69 -42
  44. package/fesm2022/radix-ng-primitives-field.mjs.map +1 -1
  45. package/fesm2022/radix-ng-primitives-fieldset.mjs +8 -7
  46. package/fesm2022/radix-ng-primitives-fieldset.mjs.map +1 -1
  47. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs +77 -40
  48. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs.map +1 -1
  49. package/fesm2022/radix-ng-primitives-focus-guards.mjs +3 -3
  50. package/fesm2022/radix-ng-primitives-focus-scope.mjs +7 -5
  51. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  52. package/fesm2022/radix-ng-primitives-form.mjs +25 -16
  53. package/fesm2022/radix-ng-primitives-form.mjs.map +1 -1
  54. package/fesm2022/radix-ng-primitives-input.mjs +41 -22
  55. package/fesm2022/radix-ng-primitives-input.mjs.map +1 -1
  56. package/fesm2022/radix-ng-primitives-label.mjs +7 -5
  57. package/fesm2022/radix-ng-primitives-label.mjs.map +1 -1
  58. package/fesm2022/radix-ng-primitives-menu.mjs +274 -154
  59. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  60. package/fesm2022/radix-ng-primitives-menubar.mjs +35 -17
  61. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  62. package/fesm2022/radix-ng-primitives-meter.mjs +41 -30
  63. package/fesm2022/radix-ng-primitives-meter.mjs.map +1 -1
  64. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +220 -183
  65. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  66. package/fesm2022/radix-ng-primitives-number-field.mjs +87 -59
  67. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
  68. package/fesm2022/radix-ng-primitives-pagination.mjs +48 -38
  69. package/fesm2022/radix-ng-primitives-pagination.mjs.map +1 -1
  70. package/fesm2022/radix-ng-primitives-popover.mjs +150 -107
  71. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  72. package/fesm2022/radix-ng-primitives-popper.mjs +79 -47
  73. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  74. package/fesm2022/radix-ng-primitives-portal.mjs +20 -13
  75. package/fesm2022/radix-ng-primitives-portal.mjs.map +1 -1
  76. package/fesm2022/radix-ng-primitives-presence.mjs +3 -3
  77. package/fesm2022/radix-ng-primitives-preview-card.mjs +119 -74
  78. package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -1
  79. package/fesm2022/radix-ng-primitives-progress.mjs +43 -31
  80. package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -1
  81. package/fesm2022/radix-ng-primitives-radio.mjs +177 -168
  82. package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
  83. package/fesm2022/radix-ng-primitives-scroll-area.mjs +54 -38
  84. package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -1
  85. package/fesm2022/radix-ng-primitives-select.mjs +595 -102
  86. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  87. package/fesm2022/radix-ng-primitives-separator.mjs +7 -5
  88. package/fesm2022/radix-ng-primitives-separator.mjs.map +1 -1
  89. package/fesm2022/radix-ng-primitives-slider.mjs +101 -63
  90. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  91. package/fesm2022/radix-ng-primitives-stepper.mjs +53 -39
  92. package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
  93. package/fesm2022/radix-ng-primitives-switch.mjs +44 -25
  94. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  95. package/fesm2022/radix-ng-primitives-tabs.mjs +72 -47
  96. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  97. package/fesm2022/radix-ng-primitives-time-field.mjs +72 -41
  98. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  99. package/fesm2022/radix-ng-primitives-toast.mjs +75 -56
  100. package/fesm2022/radix-ng-primitives-toast.mjs.map +1 -1
  101. package/fesm2022/radix-ng-primitives-toggle-group.mjs +29 -19
  102. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  103. package/fesm2022/radix-ng-primitives-toggle.mjs +16 -11
  104. package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
  105. package/fesm2022/radix-ng-primitives-toolbar.mjs +38 -30
  106. package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
  107. package/fesm2022/radix-ng-primitives-tooltip.mjs +118 -63
  108. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  109. package/fesm2022/radix-ng-primitives-visually-hidden.mjs +31 -20
  110. package/fesm2022/radix-ng-primitives-visually-hidden.mjs.map +1 -1
  111. package/package.json +2 -2
  112. package/types/radix-ng-primitives-autocomplete.d.ts +3 -1
  113. package/types/radix-ng-primitives-combobox.d.ts +28 -9
  114. package/types/radix-ng-primitives-composite.d.ts +2 -0
  115. package/types/radix-ng-primitives-context-menu.d.ts +2 -0
  116. package/types/radix-ng-primitives-dialog.d.ts +6 -3
  117. package/types/radix-ng-primitives-floating-focus-manager.d.ts +11 -0
  118. package/types/radix-ng-primitives-menu.d.ts +47 -15
  119. package/types/radix-ng-primitives-menubar.d.ts +6 -1
  120. package/types/radix-ng-primitives-navigation-menu.d.ts +8 -6
  121. package/types/radix-ng-primitives-popover.d.ts +12 -4
  122. package/types/radix-ng-primitives-preview-card.d.ts +18 -5
  123. package/types/radix-ng-primitives-radio.d.ts +100 -65
  124. package/types/radix-ng-primitives-select.d.ts +186 -391
  125. package/types/radix-ng-primitives-switch.d.ts +3 -2
  126. package/types/radix-ng-primitives-tooltip.d.ts +17 -3
@@ -1,42 +1,72 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, ElementRef, model, input, booleanAttribute, output, signal, computed, effect, Directive, Renderer2, DestroyRef } from '@angular/core';
2
+ import { inject, ElementRef, model, input, booleanAttribute, output, signal, computed, effect, untracked, Directive } from '@angular/core';
3
3
  import * as i1 from '@radix-ng/primitives/composite';
4
4
  import { RdxCompositeRoot, RdxCompositeItem } from '@radix-ng/primitives/composite';
5
- import { createCancelableChangeEventDetails, provideValueAccessor, provideToken } from '@radix-ng/primitives/core';
6
- import * as i1$1 from '@radix-ng/primitives/visually-hidden';
7
- import { RdxVisuallyHiddenDirective } from '@radix-ng/primitives/visually-hidden';
8
-
9
- const RDX_RADIO_GROUP = new InjectionToken('RdxRadioGroup');
5
+ import { createContext, createCancelableChangeEventDetails, provideValueAccessor } from '@radix-ng/primitives/core';
10
6
 
7
+ const rootContext = () => {
8
+ const root = inject(RdxRadioGroupDirective);
9
+ return {
10
+ value: root.value,
11
+ disabledState: root.disabledState,
12
+ readonly: root.readonly,
13
+ required: root.required,
14
+ name: root.name,
15
+ form: root.form,
16
+ select: (value, event, reason) => root.select(value, event, reason),
17
+ setArrowNavigation: (value) => root.setArrowNavigation(value),
18
+ isArrowNavigation: () => root.isArrowNavigation()
19
+ };
20
+ };
21
+ const [injectRadioRootContext, provideRadioRootContext] = createContext('RadioRootContext', 'components/radio');
11
22
  class RdxRadioGroupDirective {
12
23
  constructor() {
13
24
  this.elementRef = inject(ElementRef);
14
25
  this.compositeRoot = inject(RdxCompositeRoot, { self: true });
15
- this.value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
16
- this.defaultValue = input(...(ngDevMode ? [undefined, { debugName: "defaultValue" }] : /* istanbul ignore next */ []));
17
- this.name = input(...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
18
- this.form = input(...(ngDevMode ? [undefined, { debugName: "form" }] : /* istanbul ignore next */ []));
26
+ /**
27
+ * The selected value. Deliberately typed as `string` (not Base UI's generic `Value`):
28
+ * a radio group maps onto native radio inputs whose form value is a string, so values are
29
+ * the option identifiers. Use the string key of your option as the value.
30
+ */
31
+ this.value = model(null, /* @ts-ignore */
32
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
33
+ this.defaultValue = input(/* @ts-ignore */
34
+ ...(ngDevMode ? [undefined, { debugName: "defaultValue" }] : /* istanbul ignore next */ []));
35
+ this.name = input(/* @ts-ignore */
36
+ ...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
37
+ this.form = input(/* @ts-ignore */
38
+ ...(ngDevMode ? [undefined, { debugName: "form" }] : /* istanbul ignore next */ []));
19
39
  this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
20
- this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
40
+ /**
41
+ * Whether the user should be unable to select a different radio button. Bound in templates as
42
+ * `readOnly` (Base UI spelling); the TS member stays `readonly` for cross-primitive consistency.
43
+ */
44
+ this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), alias: 'readOnly', transform: booleanAttribute });
21
45
  this.required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
22
46
  /**
23
47
  * Event handler called when the value changes.
24
48
  */
25
49
  this.onValueChange = output();
26
- this.disable = signal(this.disabled(), ...(ngDevMode ? [{ debugName: "disable" }] : /* istanbul ignore next */ []));
27
- this.disabledState = computed(() => this.disable() || this.disabled(), ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
28
- this.arrowNavigation = signal(false, ...(ngDevMode ? [{ debugName: "arrowNavigation" }] : /* istanbul ignore next */ []));
29
- this.itemMetadata = computed(() => Array.from(this.compositeRoot.itemMap().values()).filter(isRadioItemMetadata), ...(ngDevMode ? [{ debugName: "itemMetadata" }] : /* istanbul ignore next */ []));
50
+ this.disable = signal(false, /* @ts-ignore */
51
+ ...(ngDevMode ? [{ debugName: "disable" }] : /* istanbul ignore next */ []));
52
+ this.disabledState = computed(() => this.disable() || this.disabled(), /* @ts-ignore */
53
+ ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
54
+ this.arrowNavigation = signal(false, /* @ts-ignore */
55
+ ...(ngDevMode ? [{ debugName: "arrowNavigation" }] : /* istanbul ignore next */ []));
56
+ this.itemMetadata = computed(() => Array.from(this.compositeRoot.itemMap().values()).filter(isRadioItemMetadata), /* @ts-ignore */
57
+ ...(ngDevMode ? [{ debugName: "itemMetadata" }] : /* istanbul ignore next */ []));
30
58
  this.disabledIndices = computed(() => this.itemMetadata()
31
59
  .filter((metadata) => metadata.disabled)
32
- .map((metadata) => metadata.index), ...(ngDevMode ? [{ debugName: "disabledIndices" }] : /* istanbul ignore next */ []));
60
+ .map((metadata) => metadata.index), /* @ts-ignore */
61
+ ...(ngDevMode ? [{ debugName: "disabledIndices" }] : /* istanbul ignore next */ []));
33
62
  this.activeIndex = computed(() => {
34
63
  const value = this.value();
35
64
  if (value === null) {
36
65
  return -1;
37
66
  }
38
67
  return this.itemMetadata().find((metadata) => metadata.value === value)?.index ?? -1;
39
- }, ...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
68
+ }, /* @ts-ignore */
69
+ ...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
40
70
  /**
41
71
  * The callback function to call when the value of the radio group changes.
42
72
  */
@@ -50,9 +80,15 @@ class RdxRadioGroupDirective {
50
80
  this.onTouched = () => {
51
81
  /* Empty */
52
82
  };
83
+ let hasAppliedDefault = false;
53
84
  effect(() => {
54
- if (this.value() === null && this.defaultValue() !== undefined) {
55
- this.value.set(this.defaultValue());
85
+ const defaultValue = this.defaultValue();
86
+ if (hasAppliedDefault || defaultValue === undefined) {
87
+ return;
88
+ }
89
+ hasAppliedDefault = true;
90
+ if (untracked(this.value) === null) {
91
+ this.value.set(defaultValue);
56
92
  }
57
93
  });
58
94
  effect(() => {
@@ -133,21 +169,25 @@ class RdxRadioGroupDirective {
133
169
  if (this.disabledState())
134
170
  return;
135
171
  }
136
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxRadioGroupDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
137
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxRadioGroupDirective, isStandalone: true, selector: "[rdxRadioRoot]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", 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 }, 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 } }, outputs: { value: "valueChange", onValueChange: "onValueChange" }, host: { attributes: { "role": "radiogroup" }, listeners: { "keydown": "onKeydown()" }, properties: { "attr.aria-required": "required() ? \"true\" : undefined", "attr.aria-disabled": "disabledState() ? \"true\" : undefined", "attr.aria-readonly": "readonly() ? \"true\" : undefined", "attr.data-disabled": "disabledState() ? \"\" : undefined", "attr.data-readonly": "readonly() ? \"\" : undefined", "attr.data-required": "required() ? \"\" : undefined" } }, providers: [
138
- provideValueAccessor(RdxRadioGroupDirective),
139
- { provide: RDX_RADIO_GROUP, useExisting: RdxRadioGroupDirective }
140
- ], exportAs: ["rdxRadioRoot"], hostDirectives: [{ directive: i1.RdxCompositeRoot }], ngImport: i0 }); }
172
+ /**
173
+ * Marks the control touched when focus leaves the whole group (Base UI `RadioGroup` parity and the
174
+ * ADR 0004 CVA strategy) — moving focus between items stays inside, so `relatedTarget` is checked.
175
+ */
176
+ onFocusOut(event) {
177
+ const next = event.relatedTarget;
178
+ if (!this.elementRef.nativeElement.contains(next)) {
179
+ this.onTouched();
180
+ }
181
+ }
182
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxRadioGroupDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
183
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxRadioGroupDirective, isStandalone: true, selector: "[rdxRadioRoot]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", 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 }, 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 } }, outputs: { value: "valueChange", onValueChange: "onValueChange" }, host: { attributes: { "role": "radiogroup" }, listeners: { "keydown": "onKeydown()", "focusout": "onFocusOut($event)" }, properties: { "attr.aria-required": "required() ? \"true\" : undefined", "attr.aria-disabled": "disabledState() ? \"true\" : undefined", "attr.aria-readonly": "readonly() ? \"true\" : undefined", "attr.data-disabled": "disabledState() ? \"\" : undefined" } }, providers: [provideValueAccessor(RdxRadioGroupDirective), provideRadioRootContext(rootContext)], exportAs: ["rdxRadioRoot"], hostDirectives: [{ directive: i1.RdxCompositeRoot }], ngImport: i0 }); }
141
184
  }
142
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxRadioGroupDirective, decorators: [{
185
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxRadioGroupDirective, decorators: [{
143
186
  type: Directive,
144
187
  args: [{
145
188
  selector: '[rdxRadioRoot]',
146
189
  exportAs: 'rdxRadioRoot',
147
- providers: [
148
- provideValueAccessor(RdxRadioGroupDirective),
149
- { provide: RDX_RADIO_GROUP, useExisting: RdxRadioGroupDirective }
150
- ],
190
+ providers: [provideValueAccessor(RdxRadioGroupDirective), provideRadioRootContext(rootContext)],
151
191
  hostDirectives: [RdxCompositeRoot],
152
192
  host: {
153
193
  role: 'radiogroup',
@@ -155,65 +195,68 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
155
195
  '[attr.aria-disabled]': 'disabledState() ? "true" : undefined',
156
196
  '[attr.aria-readonly]': 'readonly() ? "true" : undefined',
157
197
  '[attr.data-disabled]': 'disabledState() ? "" : undefined',
158
- '[attr.data-readonly]': 'readonly() ? "" : undefined',
159
- '[attr.data-required]': 'required() ? "" : undefined',
160
- '(keydown)': 'onKeydown()'
198
+ '(keydown)': 'onKeydown()',
199
+ '(focusout)': 'onFocusOut($event)'
161
200
  }
162
201
  }]
163
- }], 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 }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", 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 }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }] } });
202
+ }], 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 }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", 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 }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }] } });
164
203
  function isRadioItemMetadata(metadata) {
165
204
  return typeof metadata['disabled'] === 'boolean' && typeof metadata['value'] === 'string';
166
205
  }
167
206
 
168
- const RdxRadioItemToken = new InjectionToken('RadioItemToken');
169
- function injectRadioItem() {
170
- return inject(RdxRadioItemToken);
171
- }
207
+ const itemContext = () => {
208
+ const item = inject(RdxRadioItemDirective);
209
+ return {
210
+ value: item.value,
211
+ checkedState: item.checkedState,
212
+ disabledState: item.disabledState,
213
+ readonlyState: item.readonlyState,
214
+ requiredState: item.requiredState
215
+ };
216
+ };
217
+ const [injectRadioItemContext, provideRadioItemContext] = createContext('RadioItemContext', 'components/radio');
172
218
  class RdxRadioItemDirective {
173
219
  constructor() {
174
- this.radioGroup = inject(RDX_RADIO_GROUP);
175
- this.elementRef = inject(ElementRef);
176
- this.renderer = inject(Renderer2);
220
+ this.rootContext = injectRadioRootContext();
177
221
  this.compositeItem = inject(RdxCompositeItem, { self: true });
178
- this.destroyRef = inject(DestroyRef);
179
- this.inputElement = this.renderer.createElement('input');
180
- this.value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
181
- this.id = input(...(ngDevMode ? [undefined, { debugName: "id" }] : /* istanbul ignore next */ []));
222
+ this.elementRef = inject(ElementRef);
223
+ this.value = input.required(/* @ts-ignore */
224
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
225
+ this.id = input(/* @ts-ignore */
226
+ ...(ngDevMode ? [undefined, { debugName: "id" }] : /* istanbul ignore next */ []));
182
227
  this.required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
183
228
  this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
184
- this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
185
- this.nativeButton = input(false, { ...(ngDevMode ? { debugName: "nativeButton" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
186
- this.nativeButtonState = computed(() => this.nativeButton(), ...(ngDevMode ? [{ debugName: "nativeButtonState" }] : /* istanbul ignore next */ []));
187
- this.disabledState = computed(() => this.radioGroup.disabledState() || this.disabled(), ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
188
- this.readonlyState = computed(() => this.radioGroup.readonly() || this.readonly(), ...(ngDevMode ? [{ debugName: "readonlyState" }] : /* istanbul ignore next */ []));
189
- this.requiredState = computed(() => this.radioGroup.required() || this.required(), ...(ngDevMode ? [{ debugName: "requiredState" }] : /* istanbul ignore next */ []));
190
- this.checkedState = computed(() => this.radioGroup.value() === this.value(), ...(ngDevMode ? [{ debugName: "checkedState" }] : /* istanbul ignore next */ []));
229
+ /**
230
+ * Whether the user should be unable to select this radio button. Bound in templates as
231
+ * `readOnly` (Base UI spelling); the TS member stays `readonly` for cross-primitive consistency.
232
+ */
233
+ this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), alias: 'readOnly', transform: booleanAttribute });
234
+ /**
235
+ * Whether the host is a native `<button>`. Detected from the host tag (unlike Base UI's explicit
236
+ * `nativeButton` prop, the rendered element is statically known in Angular templates), and used to
237
+ * apply `type="button"` and the native `disabled` attribute.
238
+ */
239
+ this.isNativeButton = this.elementRef.nativeElement.tagName === 'BUTTON';
240
+ this.disabledState = computed(() => this.rootContext.disabledState() || this.disabled(), /* @ts-ignore */
241
+ ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
242
+ this.readonlyState = computed(() => this.rootContext.readonly() || this.readonly(), /* @ts-ignore */
243
+ ...(ngDevMode ? [{ debugName: "readonlyState" }] : /* istanbul ignore next */ []));
244
+ this.requiredState = computed(() => this.rootContext.required() || this.required(), /* @ts-ignore */
245
+ ...(ngDevMode ? [{ debugName: "requiredState" }] : /* istanbul ignore next */ []));
246
+ this.checkedState = computed(() => this.rootContext.value() === this.value(), /* @ts-ignore */
247
+ ...(ngDevMode ? [{ debugName: "checkedState" }] : /* istanbul ignore next */ []));
191
248
  this.ARROW_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
192
- this.createHiddenInput();
193
- const unlistenInputChange = this.renderer.listen(this.inputElement, 'change', (event) => {
194
- if (this.inputElement.checked) {
195
- this.radioGroup.select(this.value(), event);
196
- }
197
- });
198
- this.destroyRef.onDestroy(() => {
199
- unlistenInputChange();
200
- const parent = this.inputElement.parentNode;
201
- if (parent) {
202
- this.renderer.removeChild(parent, this.inputElement);
203
- }
204
- });
205
249
  effect(() => {
206
250
  this.compositeItem.setMetadata({
207
251
  disabled: this.disabledState(),
208
252
  value: this.value()
209
253
  });
210
- this.syncHiddenInput();
211
254
  });
212
255
  }
213
256
  /** @ignore */
214
257
  onClick(event) {
215
258
  if (!this.disabledState() && !this.readonlyState()) {
216
- this.radioGroup.select(this.value(), event);
259
+ this.rootContext.select(this.value(), event);
217
260
  }
218
261
  }
219
262
  /** @ignore */
@@ -228,91 +271,37 @@ class RdxRadioItemDirective {
228
271
  return;
229
272
  }
230
273
  if (this.isAllowedArrowKey(keyEvent.key)) {
231
- this.radioGroup.setArrowNavigation(true);
274
+ this.rootContext.setArrowNavigation(true);
232
275
  }
233
276
  }
234
277
  /** @ignore */
235
278
  onKeyUp() {
236
- this.radioGroup.setArrowNavigation(false);
279
+ this.rootContext.setArrowNavigation(false);
237
280
  }
238
281
  /** @ignore */
239
282
  onFocus(event) {
240
283
  queueMicrotask(() => {
241
- if (this.radioGroup.isArrowNavigation()) {
242
- this.radioGroup.select(this.value(), event);
243
- this.radioGroup.setArrowNavigation(false);
284
+ if (this.rootContext.isArrowNavigation()) {
285
+ this.rootContext.select(this.value(), event);
286
+ this.rootContext.setArrowNavigation(false);
244
287
  }
245
288
  });
246
289
  }
247
290
  isAllowedArrowKey(key) {
248
- if (!this.ARROW_KEYS.includes(key)) {
249
- return false;
250
- }
251
- return true;
252
- }
253
- createHiddenInput() {
254
- const host = this.elementRef.nativeElement;
255
- const parent = host.parentNode;
256
- this.renderer.setAttribute(this.inputElement, 'type', 'radio');
257
- this.renderer.setAttribute(this.inputElement, 'tabindex', '-1');
258
- this.renderer.setAttribute(this.inputElement, 'aria-hidden', 'true');
259
- this.renderer.setStyle(this.inputElement, 'position', 'absolute');
260
- this.renderer.setStyle(this.inputElement, 'pointer-events', 'none');
261
- this.renderer.setStyle(this.inputElement, 'opacity', '0');
262
- this.renderer.setStyle(this.inputElement, 'margin', '0');
263
- this.renderer.setStyle(this.inputElement, 'inset', '0');
264
- this.renderer.setStyle(this.inputElement, 'transform', 'translateX(-100%)');
265
- if (parent) {
266
- this.renderer.insertBefore(parent, this.inputElement, host.nextSibling);
267
- }
268
- }
269
- syncHiddenInput() {
270
- const checked = this.checkedState();
271
- this.inputElement.name = this.radioGroup.name() ?? '';
272
- this.inputElement.value = this.value();
273
- this.inputElement.checked = checked;
274
- this.inputElement.required = this.requiredState();
275
- this.inputElement.disabled = this.disabledState();
276
- this.setOptionalAttribute('name', this.radioGroup.name());
277
- this.setOptionalAttribute('form', this.radioGroup.form());
278
- this.setBooleanAttribute('checked', checked);
279
- this.setBooleanAttribute('required', this.requiredState());
280
- this.setBooleanAttribute('disabled', this.disabledState());
281
- this.renderer.setAttribute(this.inputElement, 'value', this.value());
282
- if (this.previousCheckedState === false && checked) {
283
- this.inputElement.dispatchEvent(new Event('input', { bubbles: true }));
284
- this.inputElement.dispatchEvent(new Event('change', { bubbles: true }));
285
- }
286
- this.previousCheckedState = checked;
287
- }
288
- setOptionalAttribute(name, value) {
289
- if (value) {
290
- this.renderer.setAttribute(this.inputElement, name, value);
291
- }
292
- else {
293
- this.renderer.removeAttribute(this.inputElement, name);
294
- }
291
+ return this.ARROW_KEYS.includes(key);
295
292
  }
296
- setBooleanAttribute(name, value) {
297
- if (value) {
298
- this.renderer.setAttribute(this.inputElement, name, '');
299
- }
300
- else {
301
- this.renderer.removeAttribute(this.inputElement, name);
302
- }
303
- }
304
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxRadioItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
305
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxRadioItemDirective, isStandalone: true, selector: "[rdxRadioItem]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", 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 }, nativeButton: { classPropertyName: "nativeButton", publicName: "nativeButton", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "radio" }, listeners: { "click": "onClick($event)", "keydown": "onKeyDown($event)", "keyup": "onKeyUp()", "focus": "onFocus($event)" }, properties: { "attr.type": "nativeButtonState() ? \"button\" : undefined", "attr.aria-checked": "checkedState()", "attr.aria-disabled": "disabledState() ? \"true\" : undefined", "attr.aria-readonly": "readonlyState() ? \"true\" : undefined", "attr.aria-required": "requiredState() ? \"true\" : undefined", "attr.data-composite-item-active": "checkedState() ? \"\" : undefined", "attr.data-checked": "checkedState() ? \"\" : undefined", "attr.data-unchecked": "!checkedState() ? \"\" : undefined", "attr.data-disabled": "disabledState() ? \"\" : undefined", "attr.data-readonly": "readonlyState() ? \"\" : undefined", "attr.data-required": "requiredState() ? \"\" : undefined", "attr.data-state": "checkedState() ? \"checked\" : \"unchecked\"", "attr.disabled": "nativeButtonState() && disabledState() ? \"\" : undefined" } }, providers: [provideToken(RdxRadioItemToken, RdxRadioItemDirective)], exportAs: ["rdxRadioItem"], hostDirectives: [{ directive: i1.RdxCompositeItem }], ngImport: i0 }); }
293
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxRadioItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
294
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxRadioItemDirective, isStandalone: true, selector: "[rdxRadioItem]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", 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 } }, host: { attributes: { "role": "radio" }, listeners: { "click": "onClick($event)", "keydown": "onKeyDown($event)", "keyup": "onKeyUp()", "focus": "onFocus($event)" }, properties: { "attr.type": "isNativeButton ? \"button\" : undefined", "attr.aria-checked": "checkedState()", "attr.aria-disabled": "disabledState() ? \"true\" : undefined", "attr.aria-readonly": "readonlyState() ? \"true\" : undefined", "attr.aria-required": "requiredState() ? \"true\" : undefined", "attr.data-composite-item-active": "checkedState() ? \"\" : undefined", "attr.data-checked": "checkedState() ? \"\" : undefined", "attr.data-unchecked": "!checkedState() ? \"\" : undefined", "attr.data-disabled": "disabledState() ? \"\" : undefined", "attr.data-readonly": "readonlyState() ? \"\" : undefined", "attr.data-required": "requiredState() ? \"\" : undefined", "attr.disabled": "isNativeButton && disabledState() ? \"\" : undefined" } }, providers: [provideRadioItemContext(itemContext)], exportAs: ["rdxRadioItem"], hostDirectives: [{ directive: i1.RdxCompositeItem }], ngImport: i0 }); }
306
295
  }
307
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxRadioItemDirective, decorators: [{
296
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxRadioItemDirective, decorators: [{
308
297
  type: Directive,
309
298
  args: [{
310
299
  selector: '[rdxRadioItem]',
311
300
  exportAs: 'rdxRadioItem',
312
- providers: [provideToken(RdxRadioItemToken, RdxRadioItemDirective)],
301
+ providers: [provideRadioItemContext(itemContext)],
313
302
  hostDirectives: [RdxCompositeItem],
314
303
  host: {
315
- '[attr.type]': 'nativeButtonState() ? "button" : undefined',
304
+ '[attr.type]': 'isNativeButton ? "button" : undefined',
316
305
  role: 'radio',
317
306
  '[attr.aria-checked]': 'checkedState()',
318
307
  '[attr.aria-disabled]': 'disabledState() ? "true" : undefined',
@@ -324,53 +313,68 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
324
313
  '[attr.data-disabled]': 'disabledState() ? "" : undefined',
325
314
  '[attr.data-readonly]': 'readonlyState() ? "" : undefined',
326
315
  '[attr.data-required]': 'requiredState() ? "" : undefined',
327
- '[attr.data-state]': 'checkedState() ? "checked" : "unchecked"',
328
- '[attr.disabled]': 'nativeButtonState() && disabledState() ? "" : undefined',
316
+ '[attr.disabled]': 'isNativeButton && disabledState() ? "" : undefined',
329
317
  '(click)': 'onClick($event)',
330
318
  '(keydown)': 'onKeyDown($event)',
331
319
  '(keyup)': 'onKeyUp()',
332
320
  '(focus)': 'onFocus($event)'
333
321
  }
334
322
  }]
335
- }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], nativeButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "nativeButton", required: false }] }] } });
323
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }] } });
336
324
 
337
325
  class RdxRadioIndicatorDirective {
338
326
  constructor() {
339
- this.radioGroup = inject(RDX_RADIO_GROUP);
340
- this.radioItem = inject(RdxRadioItemDirective);
327
+ this.itemContext = injectRadioItemContext();
328
+ /** Keep the indicator in the DOM when unchecked so CSS exit animations can play. */
329
+ this.keepMounted = input(false, { ...(ngDevMode ? { debugName: "keepMounted" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
330
+ this.isVisible = computed(() => this.itemContext.checkedState(), /* @ts-ignore */
331
+ ...(ngDevMode ? [{ debugName: "isVisible" }] : /* istanbul ignore next */ []));
341
332
  }
342
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxRadioIndicatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
343
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxRadioIndicatorDirective, isStandalone: true, selector: "[rdxRadioIndicator]", host: { properties: { "attr.data-checked": "radioItem.checkedState() ? \"\" : undefined", "attr.data-unchecked": "!radioItem.checkedState() ? \"\" : undefined", "attr.data-state": "radioItem.checkedState() ? \"checked\" : \"unchecked\"", "attr.data-disabled": "radioItem.disabledState() ? \"\" : undefined", "attr.data-readonly": "radioItem.readonlyState() ? \"\" : undefined", "attr.data-required": "radioItem.requiredState() ? \"\" : undefined", "hidden": "!radioItem.checkedState()", "style.pointer-events": "\"none\"" } }, exportAs: ["rdxRadioIndicator"], ngImport: i0 }); }
333
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxRadioIndicatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
334
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: RdxRadioIndicatorDirective, isStandalone: true, selector: "[rdxRadioIndicator]", inputs: { keepMounted: { classPropertyName: "keepMounted", publicName: "keepMounted", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-checked": "itemContext.checkedState() ? \"\" : undefined", "attr.data-unchecked": "!itemContext.checkedState() ? \"\" : undefined", "attr.data-disabled": "itemContext.disabledState() ? \"\" : undefined", "attr.data-readonly": "itemContext.readonlyState() ? \"\" : undefined", "attr.data-required": "itemContext.requiredState() ? \"\" : undefined", "attr.data-starting-style": "isVisible() ? \"\" : undefined", "attr.data-ending-style": "!isVisible() ? \"\" : undefined", "style.display": "!keepMounted() && !isVisible() ? \"none\" : null", "style.pointer-events": "\"none\"" } }, exportAs: ["rdxRadioIndicator"], ngImport: i0 }); }
344
335
  }
345
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxRadioIndicatorDirective, decorators: [{
336
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxRadioIndicatorDirective, decorators: [{
346
337
  type: Directive,
347
338
  args: [{
348
339
  selector: '[rdxRadioIndicator]',
349
340
  exportAs: 'rdxRadioIndicator',
350
341
  host: {
351
- '[attr.data-checked]': 'radioItem.checkedState() ? "" : undefined',
352
- '[attr.data-unchecked]': '!radioItem.checkedState() ? "" : undefined',
353
- '[attr.data-state]': 'radioItem.checkedState() ? "checked" : "unchecked"',
354
- '[attr.data-disabled]': 'radioItem.disabledState() ? "" : undefined',
355
- '[attr.data-readonly]': 'radioItem.readonlyState() ? "" : undefined',
356
- '[attr.data-required]': 'radioItem.requiredState() ? "" : undefined',
357
- '[hidden]': '!radioItem.checkedState()',
342
+ '[attr.data-checked]': 'itemContext.checkedState() ? "" : undefined',
343
+ '[attr.data-unchecked]': '!itemContext.checkedState() ? "" : undefined',
344
+ '[attr.data-disabled]': 'itemContext.disabledState() ? "" : undefined',
345
+ '[attr.data-readonly]': 'itemContext.readonlyState() ? "" : undefined',
346
+ '[attr.data-required]': 'itemContext.requiredState() ? "" : undefined',
347
+ '[attr.data-starting-style]': 'isVisible() ? "" : undefined',
348
+ '[attr.data-ending-style]': '!isVisible() ? "" : undefined',
349
+ '[style.display]': '!keepMounted() && !isVisible() ? "none" : null',
358
350
  '[style.pointer-events]': '"none"'
359
351
  }
360
352
  }]
361
- }] });
353
+ }], propDecorators: { keepMounted: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepMounted", required: false }] }] } });
362
354
 
355
+ /**
356
+ * The hidden native radio input that mirrors the item state for form submission, native validation,
357
+ * and `<label>` activation. Place it inside an `rdxRadioItem`.
358
+ *
359
+ * @see https://base-ui.com/react/components/radio
360
+ */
363
361
  class RdxRadioItemInputDirective {
364
362
  constructor() {
365
- this.radioItem = injectRadioItem();
366
- this.radioGroup = inject(RDX_RADIO_GROUP);
363
+ this.rootContext = injectRadioRootContext();
364
+ this.itemContext = injectRadioItemContext();
367
365
  this.input = inject(ElementRef).nativeElement;
368
- this.name = computed(() => this.radioGroup.name(), ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
369
- this.form = computed(() => this.radioGroup.form(), ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
370
- this.value = computed(() => this.radioItem.value() || undefined, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
371
- this.checked = computed(() => this.radioItem.checkedState(), ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
372
- this.required = computed(() => this.radioItem.requiredState(), ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
373
- this.disabled = computed(() => this.radioItem.disabledState(), ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
366
+ this.name = computed(() => this.rootContext.name(), /* @ts-ignore */
367
+ ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
368
+ this.form = computed(() => this.rootContext.form(), /* @ts-ignore */
369
+ ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
370
+ this.value = computed(() => this.itemContext.value() || undefined, /* @ts-ignore */
371
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
372
+ this.checked = computed(() => this.itemContext.checkedState(), /* @ts-ignore */
373
+ ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
374
+ this.required = computed(() => this.itemContext.requiredState(), /* @ts-ignore */
375
+ ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
376
+ this.disabled = computed(() => this.itemContext.disabledState(), /* @ts-ignore */
377
+ ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
374
378
  let isInitial = true;
375
379
  effect(() => {
376
380
  const checked = this.checked();
@@ -384,15 +388,26 @@ class RdxRadioItemInputDirective {
384
388
  }
385
389
  });
386
390
  }
387
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxRadioItemInputDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
388
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxRadioItemInputDirective, isStandalone: true, selector: "input[rdxRadioItemInput]", host: { attributes: { "type": "radio", "tabindex": "-1", "aria-hidden": "true" }, properties: { "attr.name": "name()", "attr.form": "form()", "attr.required": "required() ? \"\" : undefined", "attr.disabled": "disabled() ? \"\" : undefined", "attr.checked": "checked() ? \"\" : undefined", "checked": "checked()", "attr.value": "value()", "style": "{\n position: 'absolute',\n pointerEvents: 'none',\n opacity: 0,\n margin: 0,\n inset: 0,\n transform: 'translateX(-100%)',\n }" } }, exportAs: ["rdxRadioItemInput"], hostDirectives: [{ directive: i1$1.RdxVisuallyHiddenDirective, inputs: ["feature", "feature"] }], ngImport: i0 }); }
391
+ /**
392
+ * Selects this item when the native input is checked covers `<label>` activation,
393
+ * where clicking the label toggles the hidden radio input rather than the visible item.
394
+ * `select()` is a no-op when the value is already current, so the programmatic
395
+ * `change` dispatched above does not re-trigger selection.
396
+ * @ignore
397
+ */
398
+ onInputChange(event) {
399
+ if (this.input.checked) {
400
+ this.rootContext.select(this.itemContext.value(), event);
401
+ }
402
+ }
403
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxRadioItemInputDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
404
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: RdxRadioItemInputDirective, isStandalone: true, selector: "input[rdxRadioItemInput]", host: { attributes: { "type": "radio", "tabindex": "-1", "aria-hidden": "true" }, listeners: { "change": "onInputChange($event)" }, properties: { "attr.name": "name()", "attr.form": "form()", "attr.required": "required() ? \"\" : undefined", "attr.disabled": "disabled() ? \"\" : undefined", "attr.checked": "checked() ? \"\" : undefined", "checked": "checked()", "attr.value": "value()" }, styleAttribute: "transform: translateX(-100%); position: absolute; pointer-events: none; opacity: 0; margin: 0; inset: 0;" }, exportAs: ["rdxRadioItemInput"], ngImport: i0 }); }
389
405
  }
390
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxRadioItemInputDirective, decorators: [{
406
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxRadioItemInputDirective, decorators: [{
391
407
  type: Directive,
392
408
  args: [{
393
409
  selector: 'input[rdxRadioItemInput]',
394
410
  exportAs: 'rdxRadioItemInput',
395
- hostDirectives: [{ directive: RdxVisuallyHiddenDirective, inputs: ['feature'] }],
396
411
  host: {
397
412
  type: 'radio',
398
413
  tabindex: '-1',
@@ -404,14 +419,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
404
419
  '[attr.checked]': 'checked() ? "" : undefined',
405
420
  '[checked]': 'checked()',
406
421
  '[attr.value]': 'value()',
407
- '[style]': `{
408
- position: 'absolute',
409
- pointerEvents: 'none',
410
- opacity: 0,
411
- margin: 0,
412
- inset: 0,
413
- transform: 'translateX(-100%)',
414
- }`
422
+ '(change)': 'onInputChange($event)',
423
+ style: 'transform: translateX(-100%); position: absolute; pointer-events: none; opacity: 0; margin: 0; inset: 0;'
415
424
  }
416
425
  }]
417
426
  }], ctorParameters: () => [] });
@@ -420,5 +429,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
420
429
  * Generated bundle index. Do not edit.
421
430
  */
422
431
 
423
- export { RdxRadioGroupDirective, RdxRadioIndicatorDirective, RdxRadioItemDirective, RdxRadioItemInputDirective, RdxRadioItemToken, injectRadioItem };
432
+ export { RdxRadioGroupDirective, RdxRadioIndicatorDirective, RdxRadioItemDirective, RdxRadioItemInputDirective, injectRadioItemContext, injectRadioRootContext, provideRadioItemContext, provideRadioRootContext };
424
433
  //# sourceMappingURL=radix-ng-primitives-radio.mjs.map