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

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 (178) hide show
  1. package/fesm2022/radix-ng-primitives-accordion.mjs +105 -38
  2. package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
  3. package/fesm2022/radix-ng-primitives-alert-dialog.mjs +221 -129
  4. package/fesm2022/radix-ng-primitives-alert-dialog.mjs.map +1 -1
  5. package/fesm2022/radix-ng-primitives-arrow.mjs +20 -4
  6. package/fesm2022/radix-ng-primitives-arrow.mjs.map +1 -1
  7. package/fesm2022/radix-ng-primitives-aspect-ratio.mjs.map +1 -1
  8. package/fesm2022/radix-ng-primitives-avatar.mjs +54 -61
  9. package/fesm2022/radix-ng-primitives-avatar.mjs.map +1 -1
  10. package/fesm2022/radix-ng-primitives-button.mjs +123 -0
  11. package/fesm2022/radix-ng-primitives-button.mjs.map +1 -0
  12. package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
  13. package/fesm2022/radix-ng-primitives-checkbox.mjs +378 -54
  14. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  15. package/fesm2022/radix-ng-primitives-collapsible.mjs +182 -81
  16. package/fesm2022/radix-ng-primitives-collapsible.mjs.map +1 -1
  17. package/fesm2022/radix-ng-primitives-collection.mjs +40 -57
  18. package/fesm2022/radix-ng-primitives-collection.mjs.map +1 -1
  19. package/fesm2022/radix-ng-primitives-config.mjs.map +1 -1
  20. package/fesm2022/radix-ng-primitives-context-menu.mjs +140 -424
  21. package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
  22. package/fesm2022/radix-ng-primitives-core.mjs +735 -744
  23. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  24. package/fesm2022/radix-ng-primitives-cropper.mjs +1 -0
  25. package/fesm2022/radix-ng-primitives-cropper.mjs.map +1 -1
  26. package/fesm2022/radix-ng-primitives-date-field.mjs +51 -45
  27. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  28. package/fesm2022/radix-ng-primitives-dialog.mjs +655 -327
  29. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  30. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs +70 -46
  31. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs.map +1 -1
  32. package/fesm2022/radix-ng-primitives-drawer.mjs +1059 -0
  33. package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -0
  34. package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
  35. package/fesm2022/radix-ng-primitives-field.mjs +363 -0
  36. package/fesm2022/radix-ng-primitives-field.mjs.map +1 -0
  37. package/fesm2022/radix-ng-primitives-fieldset.mjs +79 -0
  38. package/fesm2022/radix-ng-primitives-fieldset.mjs.map +1 -0
  39. package/fesm2022/radix-ng-primitives-focus-scope.mjs +23 -8
  40. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  41. package/fesm2022/radix-ng-primitives-input.mjs +172 -0
  42. package/fesm2022/radix-ng-primitives-input.mjs.map +1 -0
  43. package/fesm2022/radix-ng-primitives-label.mjs +6 -6
  44. package/fesm2022/radix-ng-primitives-label.mjs.map +1 -1
  45. package/fesm2022/radix-ng-primitives-menu.mjs +1480 -344
  46. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  47. package/fesm2022/radix-ng-primitives-menubar.mjs +290 -162
  48. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  49. package/fesm2022/radix-ng-primitives-meter.mjs +271 -0
  50. package/fesm2022/radix-ng-primitives-meter.mjs.map +1 -0
  51. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +1052 -1553
  52. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  53. package/fesm2022/radix-ng-primitives-number-field.mjs +1102 -367
  54. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
  55. package/fesm2022/radix-ng-primitives-pagination.mjs.map +1 -1
  56. package/fesm2022/radix-ng-primitives-popover.mjs +978 -989
  57. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  58. package/fesm2022/radix-ng-primitives-popper.mjs +91 -41
  59. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  60. package/fesm2022/radix-ng-primitives-portal.mjs +34 -10
  61. package/fesm2022/radix-ng-primitives-portal.mjs.map +1 -1
  62. package/fesm2022/radix-ng-primitives-presence.mjs +134 -246
  63. package/fesm2022/radix-ng-primitives-presence.mjs.map +1 -1
  64. package/fesm2022/radix-ng-primitives-preview-card.mjs +997 -0
  65. package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -0
  66. package/fesm2022/radix-ng-primitives-progress.mjs +223 -84
  67. package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -1
  68. package/fesm2022/radix-ng-primitives-radio.mjs +191 -51
  69. package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
  70. package/fesm2022/radix-ng-primitives-roving-focus.mjs +96 -50
  71. package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
  72. package/fesm2022/radix-ng-primitives-select.mjs +791 -509
  73. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  74. package/fesm2022/radix-ng-primitives-separator.mjs +12 -35
  75. package/fesm2022/radix-ng-primitives-separator.mjs.map +1 -1
  76. package/fesm2022/radix-ng-primitives-slider.mjs +969 -717
  77. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  78. package/fesm2022/radix-ng-primitives-stepper.mjs +15 -19
  79. package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
  80. package/fesm2022/radix-ng-primitives-switch.mjs +125 -113
  81. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  82. package/fesm2022/radix-ng-primitives-tabs.mjs +381 -108
  83. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  84. package/fesm2022/radix-ng-primitives-time-field.mjs +55 -46
  85. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  86. package/fesm2022/radix-ng-primitives-toggle-group.mjs +121 -247
  87. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  88. package/fesm2022/radix-ng-primitives-toggle.mjs +98 -61
  89. package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
  90. package/fesm2022/radix-ng-primitives-toolbar.mjs +303 -92
  91. package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
  92. package/fesm2022/radix-ng-primitives-tooltip.mjs +690 -1071
  93. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  94. package/fesm2022/radix-ng-primitives-visually-hidden.mjs +25 -66
  95. package/fesm2022/radix-ng-primitives-visually-hidden.mjs.map +1 -1
  96. package/meter/README.md +3 -0
  97. package/navigation-menu/README.md +2 -1
  98. package/package.json +31 -18
  99. package/portal/README.md +2 -0
  100. package/preview-card/README.md +3 -0
  101. package/schematics/collection.json +1 -0
  102. package/schematics/ng-add/index.d.ts +3 -2
  103. package/schematics/ng-add/index.js +62 -31
  104. package/schematics/ng-add/index.js.map +1 -1
  105. package/schematics/ng-add/package-config.d.ts +4 -2
  106. package/schematics/ng-add/package-config.js +10 -2
  107. package/schematics/ng-add/package-config.js.map +1 -1
  108. package/schematics/ng-add/schema.d.ts +3 -0
  109. package/schematics/ng-add/schema.js +3 -0
  110. package/schematics/ng-add/schema.js.map +1 -0
  111. package/schematics/ng-add/schema.json +14 -0
  112. package/select/README.md +2 -0
  113. package/types/radix-ng-primitives-accordion.d.ts +48 -14
  114. package/types/radix-ng-primitives-alert-dialog.d.ts +95 -38
  115. package/types/radix-ng-primitives-arrow.d.ts +1 -1
  116. package/types/radix-ng-primitives-aspect-ratio.d.ts +1 -1
  117. package/types/radix-ng-primitives-avatar.d.ts +7 -11
  118. package/types/radix-ng-primitives-button.d.ts +73 -0
  119. package/types/radix-ng-primitives-calendar.d.ts +1 -2
  120. package/types/radix-ng-primitives-checkbox.d.ts +201 -32
  121. package/types/radix-ng-primitives-collapsible.d.ts +112 -39
  122. package/types/radix-ng-primitives-collection.d.ts +38 -34
  123. package/types/radix-ng-primitives-config.d.ts +1 -1
  124. package/types/radix-ng-primitives-context-menu.d.ts +60 -116
  125. package/types/radix-ng-primitives-core.d.ts +307 -236
  126. package/types/radix-ng-primitives-cropper.d.ts +2 -2
  127. package/types/radix-ng-primitives-date-field.d.ts +38 -23
  128. package/types/radix-ng-primitives-dialog.d.ts +282 -165
  129. package/types/radix-ng-primitives-dismissable-layer.d.ts +15 -7
  130. package/types/radix-ng-primitives-drawer.d.ts +448 -0
  131. package/types/radix-ng-primitives-editable.d.ts +1 -1
  132. package/types/radix-ng-primitives-field.d.ts +373 -0
  133. package/types/radix-ng-primitives-fieldset.d.ts +48 -0
  134. package/types/radix-ng-primitives-focus-scope.d.ts +13 -5
  135. package/types/radix-ng-primitives-input.d.ts +87 -0
  136. package/types/radix-ng-primitives-label.d.ts +0 -1
  137. package/types/radix-ng-primitives-menu.d.ts +572 -99
  138. package/types/radix-ng-primitives-menubar.d.ts +60 -50
  139. package/types/radix-ng-primitives-meter.d.ts +193 -0
  140. package/types/radix-ng-primitives-navigation-menu.d.ts +422 -340
  141. package/types/radix-ng-primitives-number-field.d.ts +405 -145
  142. package/types/radix-ng-primitives-pagination.d.ts +2 -2
  143. package/types/radix-ng-primitives-popover.d.ts +365 -351
  144. package/types/radix-ng-primitives-popper.d.ts +49 -9
  145. package/types/radix-ng-primitives-portal.d.ts +14 -6
  146. package/types/radix-ng-primitives-presence.d.ts +28 -76
  147. package/types/radix-ng-primitives-preview-card.d.ts +359 -0
  148. package/types/radix-ng-primitives-progress.d.ts +174 -48
  149. package/types/radix-ng-primitives-radio.d.ts +55 -25
  150. package/types/radix-ng-primitives-roving-focus.d.ts +30 -21
  151. package/types/radix-ng-primitives-select.d.ts +475 -177
  152. package/types/radix-ng-primitives-separator.d.ts +7 -32
  153. package/types/radix-ng-primitives-slider.d.ts +315 -201
  154. package/types/radix-ng-primitives-stepper.d.ts +5 -7
  155. package/types/radix-ng-primitives-switch.d.ts +86 -71
  156. package/types/radix-ng-primitives-tabs.d.ts +213 -79
  157. package/types/radix-ng-primitives-time-field.d.ts +42 -27
  158. package/types/radix-ng-primitives-toggle-group.d.ts +85 -164
  159. package/types/radix-ng-primitives-toggle.d.ts +43 -53
  160. package/types/radix-ng-primitives-toolbar.d.ts +163 -38
  161. package/types/radix-ng-primitives-tooltip.d.ts +347 -384
  162. package/types/radix-ng-primitives-visually-hidden.d.ts +19 -19
  163. package/dropdown-menu/README.md +0 -1
  164. package/fesm2022/radix-ng-primitives-dropdown-menu.mjs +0 -581
  165. package/fesm2022/radix-ng-primitives-dropdown-menu.mjs.map +0 -1
  166. package/fesm2022/radix-ng-primitives-hover-card.mjs +0 -1238
  167. package/fesm2022/radix-ng-primitives-hover-card.mjs.map +0 -1
  168. package/fesm2022/radix-ng-primitives-select2.mjs +0 -897
  169. package/fesm2022/radix-ng-primitives-select2.mjs.map +0 -1
  170. package/fesm2022/radix-ng-primitives-tooltip2.mjs +0 -735
  171. package/fesm2022/radix-ng-primitives-tooltip2.mjs.map +0 -1
  172. package/hover-card/README.md +0 -3
  173. package/select2/README.md +0 -3
  174. package/tooltip2/README.md +0 -3
  175. package/types/radix-ng-primitives-dropdown-menu.d.ts +0 -171
  176. package/types/radix-ng-primitives-hover-card.d.ts +0 -471
  177. package/types/radix-ng-primitives-select2.d.ts +0 -511
  178. package/types/radix-ng-primitives-tooltip2.d.ts +0 -325
@@ -1,180 +1,453 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, model, input, output, Directive, inject, computed, booleanAttribute, effect, NgModule } from '@angular/core';
3
- import { provideToken } from '@radix-ng/primitives/core';
2
+ import { inject, DestroyRef, signal, effect, afterNextRender, untracked, Directive, ElementRef, input, booleanAttribute, computed, model, output, NgModule } from '@angular/core';
3
+ import { createContext, useTransitionStatus, injectId } from '@radix-ng/primitives/core';
4
4
  import * as i1 from '@radix-ng/primitives/roving-focus';
5
5
  import { RdxRovingFocusGroupDirective, RdxRovingFocusItemDirective } from '@radix-ng/primitives/roving-focus';
6
+ import * as i1$1 from '@radix-ng/primitives/presence';
7
+ import { provideRdxPresenceContext, RdxPresenceDirective } from '@radix-ng/primitives/presence';
6
8
 
7
- const RDX_TABS_ROOT_TOKEN = new InjectionToken('RdxTabsRootDirective');
8
- class RdxTabsRootDirective {
9
+ const [injectTabsRootContext, provideTabsRootContext] = createContext('RdxTabsRootContext');
10
+
11
+ function makeTabId(baseId, value) {
12
+ return `${baseId}-tab-${value}`;
13
+ }
14
+ function makePanelId(baseId, value) {
15
+ return `${baseId}-panel-${value}`;
16
+ }
17
+
18
+ /**
19
+ * A visual element that tracks the position and size of the active tab. Exposes the active tab
20
+ * geometry as CSS variables (`--active-tab-{top,right,bottom,left,width,height}`) so it can be
21
+ * animated with CSS.
22
+ *
23
+ * @see https://base-ui.com/react/components/tabs
24
+ */
25
+ class RdxTabsIndicator {
9
26
  constructor() {
10
- /**
11
- * The controlled value of the tab to activate. Should be used in conjunction with `onValueChange`.
12
- */
13
- this.value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ []));
14
- this.defaultValue = input(...(ngDevMode ? [undefined, { debugName: "defaultValue" }] : /* istanbul ignore next */ []));
15
- /**
16
- * When automatic, tabs are activated when receiving focus. When manual, tabs are activated when clicked.
17
- */
18
- this.activationMode = input('automatic', ...(ngDevMode ? [{ debugName: "activationMode" }] : /* istanbul ignore next */ []));
19
- /**
20
- * The orientation of the component.
21
- */
22
- this.orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
23
- this.dir = input('ltr', ...(ngDevMode ? [{ debugName: "dir" }] : /* istanbul ignore next */ []));
24
- /**
25
- * Event handler called when the value changes.
26
- */
27
- this.onValueChange = output();
27
+ this.rootContext = injectTabsRootContext();
28
+ this.destroyRef = inject(DestroyRef);
29
+ /** @ignore */
30
+ this.geometry = signal(null, ...(ngDevMode ? [{ debugName: "geometry" }] : /* istanbul ignore next */ []));
31
+ // Re-measure whenever the selection, orientation or the list element changes.
32
+ effect(() => {
33
+ this.rootContext.value();
34
+ this.rootContext.orientation();
35
+ this.rootContext.tabListElement();
36
+ this.scheduleMeasure();
37
+ });
38
+ afterNextRender(() => {
39
+ const list = untracked(this.rootContext.tabListElement);
40
+ if (!list || typeof ResizeObserver === 'undefined') {
41
+ this.measure();
42
+ return;
43
+ }
44
+ const observer = new ResizeObserver(() => this.measure());
45
+ observer.observe(list);
46
+ this.destroyRef.onDestroy(() => observer.disconnect());
47
+ this.measure();
48
+ });
28
49
  }
29
- ngOnInit() {
30
- if (this.defaultValue()) {
31
- this.value.set(this.defaultValue());
50
+ scheduleMeasure() {
51
+ if (typeof requestAnimationFrame === 'undefined') {
52
+ this.measure();
53
+ return;
32
54
  }
55
+ requestAnimationFrame(() => this.measure());
33
56
  }
34
- select(value) {
35
- this.value.set(value);
36
- this.onValueChange.emit(value);
37
- }
38
- /** @ignore */
39
- getBaseId() {
40
- return `tabs-${Math.random().toString(36).substr(2, 9)}`;
57
+ measure() {
58
+ const list = untracked(this.rootContext.tabListElement);
59
+ const value = untracked(this.rootContext.value);
60
+ if (!list || value == null || typeof document === 'undefined') {
61
+ this.geometry.set(null);
62
+ return;
63
+ }
64
+ const tab = document.getElementById(makeTabId(this.rootContext.baseId, value));
65
+ if (!tab) {
66
+ this.geometry.set(null);
67
+ return;
68
+ }
69
+ const listRect = list.getBoundingClientRect();
70
+ const tabRect = tab.getBoundingClientRect();
71
+ this.geometry.set({
72
+ top: tabRect.top - listRect.top,
73
+ right: listRect.right - tabRect.right,
74
+ bottom: listRect.bottom - tabRect.bottom,
75
+ left: tabRect.left - listRect.left,
76
+ width: tabRect.width,
77
+ height: tabRect.height
78
+ });
41
79
  }
42
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsRootDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
43
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxTabsRootDirective, isStandalone: true, selector: "[rdxTabsRoot]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, activationMode: { classPropertyName: "activationMode", publicName: "activationMode", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onValueChange: "onValueChange" }, host: { properties: { "attr.data-orientation": "orientation()", "attr.dir": "dir()" } }, providers: [provideToken(RDX_TABS_ROOT_TOKEN, RdxTabsRootDirective)], ngImport: i0 }); }
80
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsIndicator, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
81
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxTabsIndicator, isStandalone: true, selector: "[rdxTabsIndicator]", host: { properties: { "attr.data-orientation": "rootContext.orientation()", "attr.data-activation-direction": "rootContext.activationDirection()", "style.--active-tab-top.px": "geometry()?.top", "style.--active-tab-right.px": "geometry()?.right", "style.--active-tab-bottom.px": "geometry()?.bottom", "style.--active-tab-left.px": "geometry()?.left", "style.--active-tab-width.px": "geometry()?.width", "style.--active-tab-height.px": "geometry()?.height" } }, exportAs: ["rdxTabsIndicator"], ngImport: i0 }); }
44
82
  }
45
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsRootDirective, decorators: [{
83
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsIndicator, decorators: [{
46
84
  type: Directive,
47
85
  args: [{
48
- selector: '[rdxTabsRoot]',
49
- providers: [provideToken(RDX_TABS_ROOT_TOKEN, RdxTabsRootDirective)],
86
+ selector: '[rdxTabsIndicator]',
87
+ exportAs: 'rdxTabsIndicator',
50
88
  host: {
51
- '[attr.data-orientation]': 'orientation()',
52
- '[attr.dir]': 'dir()'
89
+ '[attr.data-orientation]': 'rootContext.orientation()',
90
+ '[attr.data-activation-direction]': 'rootContext.activationDirection()',
91
+ '[style.--active-tab-top.px]': 'geometry()?.top',
92
+ '[style.--active-tab-right.px]': 'geometry()?.right',
93
+ '[style.--active-tab-bottom.px]': 'geometry()?.bottom',
94
+ '[style.--active-tab-left.px]': 'geometry()?.left',
95
+ '[style.--active-tab-width.px]': 'geometry()?.width',
96
+ '[style.--active-tab-height.px]': 'geometry()?.height'
53
97
  }
54
98
  }]
55
- }], 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 }] }], activationMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "activationMode", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }] } });
99
+ }], ctorParameters: () => [] });
56
100
 
57
- function makeTriggerId(baseId, value) {
58
- return `${baseId}-trigger-${value}`;
59
- }
60
- function makeContentId(baseId, value) {
61
- return `${baseId}-content-${value}`;
101
+ /**
102
+ * Groups the individual tab buttons and manages keyboard navigation.
103
+ *
104
+ * @see https://base-ui.com/react/components/tabs
105
+ */
106
+ class RdxTabsList {
107
+ constructor() {
108
+ this.rootContext = injectTabsRootContext();
109
+ this.elementRef = inject(ElementRef);
110
+ this.rovingFocusGroup = inject(RdxRovingFocusGroupDirective, { self: true });
111
+ /**
112
+ * Whether a tab is activated when it receives focus (automatic activation).
113
+ * When `false`, tabs are only activated on click or Enter/Space.
114
+ *
115
+ * @default false
116
+ */
117
+ this.activateOnFocus = input(false, { ...(ngDevMode ? { debugName: "activateOnFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
118
+ /**
119
+ * Whether keyboard navigation should loop from the last tab back to the first.
120
+ *
121
+ * @default true
122
+ */
123
+ this.loopFocus = input(true, { ...(ngDevMode ? { debugName: "loopFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
124
+ this.rootContext.setTabListElement(this.elementRef.nativeElement);
125
+ effect(() => {
126
+ this.rovingFocusGroup.setOrientation(this.rootContext.orientation());
127
+ this.rovingFocusGroup.setLoop(this.loopFocus());
128
+ });
129
+ effect(() => this.rootContext.setActivateOnFocus(this.activateOnFocus()));
130
+ }
131
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsList, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
132
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxTabsList, isStandalone: true, selector: "[rdxTabsList]", inputs: { activateOnFocus: { classPropertyName: "activateOnFocus", publicName: "activateOnFocus", isSignal: true, isRequired: false, transformFunction: null }, loopFocus: { classPropertyName: "loopFocus", publicName: "loopFocus", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "tablist" }, properties: { "attr.aria-orientation": "rootContext.orientation()", "attr.data-orientation": "rootContext.orientation()", "attr.data-activation-direction": "rootContext.activationDirection()" } }, exportAs: ["rdxTabsList"], hostDirectives: [{ directive: i1.RdxRovingFocusGroupDirective }], ngImport: i0 }); }
62
133
  }
134
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsList, decorators: [{
135
+ type: Directive,
136
+ args: [{
137
+ selector: '[rdxTabsList]',
138
+ exportAs: 'rdxTabsList',
139
+ hostDirectives: [RdxRovingFocusGroupDirective],
140
+ host: {
141
+ role: 'tablist',
142
+ '[attr.aria-orientation]': 'rootContext.orientation()',
143
+ '[attr.data-orientation]': 'rootContext.orientation()',
144
+ '[attr.data-activation-direction]': 'rootContext.activationDirection()'
145
+ }
146
+ }]
147
+ }], ctorParameters: () => [], propDecorators: { activateOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "activateOnFocus", required: false }] }], loopFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "loopFocus", required: false }] }] } });
63
148
 
64
- class RdxTabsContentDirective {
149
+ const panelPresenceContext = () => ({ present: inject(RdxTabsPanel).present });
150
+ /**
151
+ * A panel displayed when its corresponding tab is active.
152
+ *
153
+ * By default the panel stays in the DOM and is toggled with the `hidden` attribute. To unmount the
154
+ * contents while inactive (Base UI's default `keepMounted: false`), nest a `*rdxTabsPanelPresence`
155
+ * structural directive inside it; set `keepMounted` to keep the contents mounted regardless.
156
+ *
157
+ * @see https://base-ui.com/react/components/tabs
158
+ */
159
+ class RdxTabsPanel {
65
160
  constructor() {
66
- this.tabsContext = inject(RDX_TABS_ROOT_TOKEN);
161
+ this.elementRef = inject(ElementRef);
162
+ this.rootContext = injectTabsRootContext();
67
163
  /**
68
- * A unique value that associates the content with a trigger.
164
+ * A unique value that associates the panel with a tab.
69
165
  */
70
166
  this.value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
71
- this.contentId = computed(() => makeContentId(this.tabsContext.getBaseId(), this.value()), ...(ngDevMode ? [{ debugName: "contentId" }] : /* istanbul ignore next */ []));
72
- this.triggerId = computed(() => makeTriggerId(this.tabsContext.getBaseId(), this.value()), ...(ngDevMode ? [{ debugName: "triggerId" }] : /* istanbul ignore next */ []));
73
- this.selected = computed(() => this.tabsContext.value() === this.value(), ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
167
+ /**
168
+ * Keep the panel contents mounted in the DOM while inactive (the contents are still hidden).
169
+ * Only relevant together with `*rdxTabsPanelPresence`, which otherwise unmounts them.
170
+ *
171
+ * @default false
172
+ */
173
+ this.keepMounted = input(false, { ...(ngDevMode ? { debugName: "keepMounted" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
174
+ this.transition = useTransitionStatus(() => { });
175
+ /** Reactive enter/exit transition phase (`'starting'` | `'ending'` | `undefined`). */
176
+ this.transitionStatus = this.transition.status;
177
+ /** @ignore */
178
+ this.panelId = computed(() => makePanelId(this.rootContext.baseId, this.value()), ...(ngDevMode ? [{ debugName: "panelId" }] : /* istanbul ignore next */ []));
179
+ /** @ignore */
180
+ this.tabId = computed(() => makeTabId(this.rootContext.baseId, this.value()), ...(ngDevMode ? [{ debugName: "tabId" }] : /* istanbul ignore next */ []));
181
+ /** Whether this panel's tab is currently selected. */
182
+ this.active = computed(() => this.rootContext.value() === this.value(), ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
183
+ /** `true` once a `*rdxTabsPanelPresence` child takes over mounting. */
184
+ this.hasPresence = signal(false, ...(ngDevMode ? [{ debugName: "hasPresence" }] : /* istanbul ignore next */ []));
185
+ /**
186
+ * Whether the contents should be present for `*rdxTabsPanelPresence`. Flips with `active` so the
187
+ * presence directive owns the exit-animation timing (it keeps the node mounted until its exit
188
+ * `@keyframes` finishes); `keepMounted` keeps them mounted regardless.
189
+ */
190
+ this.present = computed(() => this.keepMounted() || this.active(), ...(ngDevMode ? [{ debugName: "present" }] : /* istanbul ignore next */ []));
191
+ /**
192
+ * The `hidden` attribute value. The panel is shown while active or while its exit transition
193
+ * runs. When a presence child unmounts the contents we no longer force `hidden` (the empty
194
+ * element renders nothing), unless `keepMounted` keeps the inactive contents around.
195
+ */
196
+ this.hidden = computed(() => !this.active() && this.transitionStatus() !== 'ending' && (!this.hasPresence() || this.keepMounted()), ...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
197
+ /** @ignore Index of the panel, derived from the order of its associated tab. */
198
+ this.index = computed(() => {
199
+ const list = this.rootContext.tabListElement();
200
+ if (!list) {
201
+ return null;
202
+ }
203
+ const tabs = Array.from(list.querySelectorAll('[role="tab"]'));
204
+ const position = tabs.findIndex((tab) => tab.id === makeTabId(this.rootContext.baseId, this.value()));
205
+ return position === -1 ? null : position;
206
+ }, ...(ngDevMode ? [{ debugName: "index" }] : /* istanbul ignore next */ []));
207
+ this.previousActive = false;
208
+ this.isFirstRun = true;
209
+ const unregister = this.transition.registerElement(this.elementRef.nativeElement);
210
+ inject(DestroyRef).onDestroy(unregister);
211
+ effect(() => {
212
+ const active = this.active();
213
+ // Settle the initial state without playing an enter transition.
214
+ if (this.isFirstRun) {
215
+ this.isFirstRun = false;
216
+ this.previousActive = active;
217
+ return;
218
+ }
219
+ if (active !== this.previousActive) {
220
+ this.previousActive = active;
221
+ untracked(() => this.transition.start(active));
222
+ }
223
+ });
74
224
  }
75
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
76
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxTabsContentDirective, isStandalone: true, selector: "[rdxTabsContent]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "tabpanel", "tabindex": "0" }, properties: { "id": "contentId()", "attr.aria-labelledby": "triggerId()", "attr.data-state": "selected() ? \"active\" : \"inactive\"", "attr.data-orientation": "tabsContext.orientation()", "hidden": "!selected()" } }, ngImport: i0 }); }
225
+ /** @ignore Called by `RdxTabsPanelPresence` so the panel stops forcing `hidden`. */
226
+ markHasPresence() {
227
+ this.hasPresence.set(true);
228
+ }
229
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsPanel, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
230
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxTabsPanel, isStandalone: true, selector: "[rdxTabsPanel]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, keepMounted: { classPropertyName: "keepMounted", publicName: "keepMounted", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "tabpanel" }, properties: { "id": "panelId()", "attr.tabindex": "active() ? 0 : undefined", "attr.aria-labelledby": "tabId()", "attr.data-orientation": "rootContext.orientation()", "attr.data-activation-direction": "rootContext.activationDirection()", "attr.data-index": "index()", "attr.data-hidden": "active() ? undefined : \"\"", "attr.data-starting-style": "transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-ending-style": "transitionStatus() === \"ending\" ? \"\" : undefined", "hidden": "hidden()" } }, providers: [provideRdxPresenceContext(panelPresenceContext)], exportAs: ["rdxTabsPanel"], ngImport: i0 }); }
77
231
  }
78
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsContentDirective, decorators: [{
232
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsPanel, decorators: [{
79
233
  type: Directive,
80
234
  args: [{
81
- selector: '[rdxTabsContent]',
235
+ selector: '[rdxTabsPanel]',
236
+ exportAs: 'rdxTabsPanel',
237
+ providers: [provideRdxPresenceContext(panelPresenceContext)],
82
238
  host: {
83
239
  role: 'tabpanel',
84
- tabindex: '0',
85
- '[id]': 'contentId()',
86
- '[attr.aria-labelledby]': 'triggerId()',
87
- '[attr.data-state]': 'selected() ? "active" : "inactive"',
88
- '[attr.data-orientation]': 'tabsContext.orientation()',
89
- '[hidden]': '!selected()'
240
+ '[id]': 'panelId()',
241
+ '[attr.tabindex]': 'active() ? 0 : undefined',
242
+ '[attr.aria-labelledby]': 'tabId()',
243
+ '[attr.data-orientation]': 'rootContext.orientation()',
244
+ '[attr.data-activation-direction]': 'rootContext.activationDirection()',
245
+ '[attr.data-index]': 'index()',
246
+ '[attr.data-hidden]': 'active() ? undefined : ""',
247
+ '[attr.data-starting-style]': 'transitionStatus() === "starting" ? "" : undefined',
248
+ '[attr.data-ending-style]': 'transitionStatus() === "ending" ? "" : undefined',
249
+ '[hidden]': 'hidden()'
90
250
  }
91
251
  }]
92
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }] } });
252
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], keepMounted: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepMounted", required: false }] }] } });
93
253
 
94
- class RdxTabsListDirective {
254
+ /**
255
+ * Structural directive that mounts the tab panel contents only while the panel is active,
256
+ * unmounting them once the exit animation finishes. Apply it inside an `[rdxTabsPanel]` to get
257
+ * Base UI's default unmounting behavior; combine with `keepMounted` on the panel to keep the
258
+ * contents mounted instead.
259
+ *
260
+ * The presence state is read from the parent panel through {@link RdxPresenceDirective}.
261
+ */
262
+ class RdxTabsPanelPresence {
95
263
  constructor() {
96
- this.tabsContext = inject(RDX_TABS_ROOT_TOKEN);
264
+ inject(RdxTabsPanel).markHasPresence();
97
265
  }
98
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsListDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
99
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxTabsListDirective, isStandalone: true, selector: "[rdxTabsList]", host: { attributes: { "role": "tablist" }, properties: { "attr.aria-orientation": "tabsContext.orientation()", "attr.data-orientation": "tabsContext.orientation()" } }, hostDirectives: [{ directive: i1.RdxRovingFocusGroupDirective, inputs: ["dir", "dir", "orientation", "orientation", "loop", "loop"] }], ngImport: i0 }); }
266
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsPanelPresence, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
267
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxTabsPanelPresence, isStandalone: true, selector: "ng-template[rdxTabsPanelPresence]", hostDirectives: [{ directive: i1$1.RdxPresenceDirective }], ngImport: i0 }); }
100
268
  }
101
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsListDirective, decorators: [{
269
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsPanelPresence, decorators: [{
102
270
  type: Directive,
103
271
  args: [{
104
- selector: '[rdxTabsList]',
105
- hostDirectives: [{ directive: RdxRovingFocusGroupDirective, inputs: ['dir', 'orientation', 'loop'] }],
272
+ selector: 'ng-template[rdxTabsPanelPresence]',
273
+ hostDirectives: [RdxPresenceDirective]
274
+ }]
275
+ }], ctorParameters: () => [] });
276
+
277
+ const rootContext = () => {
278
+ const root = inject(RdxTabsRoot);
279
+ return {
280
+ baseId: root.baseId,
281
+ value: root.value,
282
+ orientation: root.orientation,
283
+ activationDirection: root.activationDirection.asReadonly(),
284
+ activateOnFocus: root.activateOnFocus.asReadonly(),
285
+ tabListElement: root.tabListElement.asReadonly(),
286
+ setValue: (value) => root.setValue(value),
287
+ setActivateOnFocus: (value) => root.activateOnFocus.set(value),
288
+ setTabListElement: (element) => root.tabListElement.set(element)
289
+ };
290
+ };
291
+ /**
292
+ * Groups the tabs and the corresponding panels.
293
+ *
294
+ * @see https://base-ui.com/react/components/tabs
295
+ */
296
+ class RdxTabsRoot {
297
+ constructor() {
298
+ /** @ignore */
299
+ this.baseId = injectId('rdx-tabs-');
300
+ /**
301
+ * The value of the currently selected tab. Use together with `(onValueChange)` for controlled state.
302
+ */
303
+ this.value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ []));
304
+ /**
305
+ * The value of the tab that should be initially selected when uncontrolled.
306
+ */
307
+ this.defaultValue = input(...(ngDevMode ? [undefined, { debugName: "defaultValue" }] : /* istanbul ignore next */ []));
308
+ /**
309
+ * The orientation the tabs are laid out. Controls arrow-key navigation
310
+ * (left/right vs. up/down).
311
+ *
312
+ * @default 'horizontal'
313
+ */
314
+ this.orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
315
+ /**
316
+ * Event emitted when the selected tab changes.
317
+ */
318
+ this.onValueChange = output();
319
+ /** @ignore Set by `[rdxTabsList]`. */
320
+ this.activateOnFocus = signal(false, ...(ngDevMode ? [{ debugName: "activateOnFocus" }] : /* istanbul ignore next */ []));
321
+ /** @ignore Set by `[rdxTabsList]`. */
322
+ this.tabListElement = signal(null, ...(ngDevMode ? [{ debugName: "tabListElement" }] : /* istanbul ignore next */ []));
323
+ /** @ignore */
324
+ this.activationDirection = signal('none', ...(ngDevMode ? [{ debugName: "activationDirection" }] : /* istanbul ignore next */ []));
325
+ effect(() => {
326
+ const initial = this.defaultValue();
327
+ if (initial !== undefined && untracked(this.value) === undefined) {
328
+ this.value.set(initial);
329
+ }
330
+ });
331
+ }
332
+ /** @ignore */
333
+ setValue(value) {
334
+ const previous = this.value();
335
+ if (previous === value) {
336
+ return;
337
+ }
338
+ this.activationDirection.set(this.computeDirection(previous, value));
339
+ this.value.set(value);
340
+ this.onValueChange.emit(value);
341
+ }
342
+ computeDirection(previous, next) {
343
+ const list = this.tabListElement();
344
+ if (!list || previous === undefined || previous === null) {
345
+ return 'none';
346
+ }
347
+ const tabs = Array.from(list.querySelectorAll('[role="tab"]'));
348
+ const previousIndex = tabs.findIndex((tab) => tab.id === makeTabId(this.baseId, previous));
349
+ const nextIndex = tabs.findIndex((tab) => tab.id === makeTabId(this.baseId, next));
350
+ if (previousIndex === -1 || nextIndex === -1 || previousIndex === nextIndex) {
351
+ return 'none';
352
+ }
353
+ const horizontal = this.orientation() === 'horizontal';
354
+ if (nextIndex > previousIndex) {
355
+ return horizontal ? 'right' : 'down';
356
+ }
357
+ return horizontal ? 'left' : 'up';
358
+ }
359
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
360
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxTabsRoot, isStandalone: true, selector: "[rdxTabsRoot]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onValueChange: "onValueChange" }, host: { properties: { "attr.data-orientation": "orientation()", "attr.data-activation-direction": "activationDirection()" } }, providers: [provideTabsRootContext(rootContext)], exportAs: ["rdxTabsRoot"], ngImport: i0 }); }
361
+ }
362
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsRoot, decorators: [{
363
+ type: Directive,
364
+ args: [{
365
+ selector: '[rdxTabsRoot]',
366
+ exportAs: 'rdxTabsRoot',
367
+ providers: [provideTabsRootContext(rootContext)],
106
368
  host: {
107
- role: 'tablist',
108
- '[attr.aria-orientation]': 'tabsContext.orientation()',
109
- '[attr.data-orientation]': 'tabsContext.orientation()'
369
+ '[attr.data-orientation]': 'orientation()',
370
+ '[attr.data-activation-direction]': 'activationDirection()'
110
371
  }
111
372
  }]
112
- }] });
373
+ }], 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 }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }] } });
113
374
 
114
- class RdxTabsTriggerDirective {
375
+ /**
376
+ * An individual interactive tab button that activates its corresponding panel.
377
+ *
378
+ * @see https://base-ui.com/react/components/tabs
379
+ */
380
+ class RdxTabsTab {
115
381
  constructor() {
116
- this.rdxRovingFocusItemDirective = inject(RdxRovingFocusItemDirective);
117
- this.tabsContext = inject(RDX_TABS_ROOT_TOKEN);
382
+ this.rootContext = injectTabsRootContext();
383
+ this.rovingFocusItem = inject(RdxRovingFocusItemDirective);
118
384
  /**
119
- * A unique value that associates the trigger with a content.
385
+ * A unique value that associates the tab with a panel.
120
386
  */
121
387
  this.value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
122
388
  /**
123
- * When true, prevents the user from interacting with the tab.
389
+ * When `true`, prevents the user from interacting with the tab.
124
390
  */
125
391
  this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
126
- this.contentId = computed(() => makeContentId(this.tabsContext.getBaseId(), this.value()), ...(ngDevMode ? [{ debugName: "contentId" }] : /* istanbul ignore next */ []));
127
- this.triggerId = computed(() => makeTriggerId(this.tabsContext.getBaseId(), this.value()), ...(ngDevMode ? [{ debugName: "triggerId" }] : /* istanbul ignore next */ []));
128
- this.isSelected = computed(() => this.tabsContext.value() === this.value(), ...(ngDevMode ? [{ debugName: "isSelected" }] : /* istanbul ignore next */ []));
129
- effect(() => this.rdxRovingFocusItemDirective.setActive(this.isSelected()));
392
+ /** @ignore */
393
+ this.tabId = computed(() => makeTabId(this.rootContext.baseId, this.value()), ...(ngDevMode ? [{ debugName: "tabId" }] : /* istanbul ignore next */ []));
394
+ /** @ignore */
395
+ this.panelId = computed(() => makePanelId(this.rootContext.baseId, this.value()), ...(ngDevMode ? [{ debugName: "panelId" }] : /* istanbul ignore next */ []));
396
+ /** @ignore */
397
+ this.active = computed(() => this.rootContext.value() === this.value(), ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
398
+ effect(() => {
399
+ this.rovingFocusItem.setActive(this.active());
400
+ this.rovingFocusItem.setFocusable(!this.disabled());
401
+ });
130
402
  }
403
+ /** @ignore */
131
404
  onMouseDown(event) {
132
- const mouseEvent = event;
133
- // only call handler if it's the left button (mousedown gets triggered by all mouse buttons)
134
- // but not when the control key is pressed (avoiding MacOS right click)
135
- if (!this.disabled() && mouseEvent.button === 0 && !mouseEvent.ctrlKey) {
136
- this.tabsContext?.select(this.value());
405
+ // Only the primary button selects; ignore Ctrl-click (macOS right-click emulation).
406
+ if (!this.disabled() && event.button === 0 && !event.ctrlKey) {
407
+ this.rootContext.setValue(this.value());
137
408
  }
138
409
  else {
139
- // prevent focus to avoid accidental activation
410
+ // Prevent focus to avoid accidental activation.
140
411
  event.preventDefault();
141
412
  }
142
413
  }
414
+ /** @ignore */
143
415
  onKeyDown(event) {
144
- const keyEvent = event;
145
- if ([' ', 'Enter'].includes(keyEvent.key)) {
146
- this.tabsContext?.select(this.value());
416
+ if (!this.disabled() && (event.key === ' ' || event.key === 'Enter')) {
417
+ this.rootContext.setValue(this.value());
147
418
  }
148
419
  }
420
+ /** @ignore */
149
421
  onFocus() {
150
- const isAutomaticActivation = this.tabsContext.activationMode() !== 'manual';
151
- if (!this.isSelected() && !this.disabled() && isAutomaticActivation) {
152
- this.tabsContext?.select(this.value());
422
+ if (!this.active() && !this.disabled() && this.rootContext.activateOnFocus()) {
423
+ this.rootContext.setValue(this.value());
153
424
  }
154
425
  }
155
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
156
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxTabsTriggerDirective, isStandalone: true, selector: "[rdxTabsTrigger]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button", "role": "tab" }, listeners: { "mousedown": "onMouseDown($event)", "keydown": "onKeyDown($event)", "focus": "onFocus()" }, properties: { "id": "triggerId()", "attr.aria-selected": "isSelected()", "attr.aria-controls": "contentId()", "attr.data-disabled": "disabled() ? '' : undefined", "attr.disabled": "disabled() ? \"\" : undefined", "attr.data-state": "isSelected() ? 'active' : 'inactive'", "attr.data-orientation": "tabsContext.orientation()" } }, hostDirectives: [{ directive: i1.RdxRovingFocusItemDirective, inputs: ["focusable", "focusable", "active", "active", "allowShiftKey", "allowShiftKey"] }], ngImport: i0 }); }
426
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsTab, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
427
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxTabsTab, isStandalone: true, selector: "[rdxTabsTab]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button", "role": "tab" }, listeners: { "mousedown": "onMouseDown($event)", "keydown": "onKeyDown($event)", "focus": "onFocus()" }, properties: { "id": "tabId()", "attr.aria-selected": "active()", "attr.aria-controls": "panelId()", "attr.data-orientation": "rootContext.orientation()", "attr.data-activation-direction": "rootContext.activationDirection()", "attr.data-active": "active() ? \"\" : undefined", "attr.data-disabled": "disabled() ? \"\" : undefined", "attr.disabled": "disabled() ? \"\" : undefined" } }, exportAs: ["rdxTabsTab"], hostDirectives: [{ directive: i1.RdxRovingFocusItemDirective, inputs: ["allowShiftKey", "allowShiftKey"] }], ngImport: i0 }); }
157
428
  }
158
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsTriggerDirective, decorators: [{
429
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsTab, decorators: [{
159
430
  type: Directive,
160
431
  args: [{
161
- selector: '[rdxTabsTrigger]',
432
+ selector: '[rdxTabsTab]',
433
+ exportAs: 'rdxTabsTab',
162
434
  hostDirectives: [
163
435
  {
164
436
  directive: RdxRovingFocusItemDirective,
165
- inputs: ['focusable', 'active', 'allowShiftKey']
437
+ inputs: ['allowShiftKey']
166
438
  }
167
439
  ],
168
440
  host: {
169
441
  type: 'button',
170
442
  role: 'tab',
171
- '[id]': 'triggerId()',
172
- '[attr.aria-selected]': 'isSelected()',
173
- '[attr.aria-controls]': 'contentId()',
174
- '[attr.data-disabled]': "disabled() ? '' : undefined",
443
+ '[id]': 'tabId()',
444
+ '[attr.aria-selected]': 'active()',
445
+ '[attr.aria-controls]': 'panelId()',
446
+ '[attr.data-orientation]': 'rootContext.orientation()',
447
+ '[attr.data-activation-direction]': 'rootContext.activationDirection()',
448
+ '[attr.data-active]': 'active() ? "" : undefined',
449
+ '[attr.data-disabled]': 'disabled() ? "" : undefined',
175
450
  '[attr.disabled]': 'disabled() ? "" : undefined',
176
- '[attr.data-state]': "isSelected() ? 'active' : 'inactive'",
177
- '[attr.data-orientation]': 'tabsContext.orientation()',
178
451
  '(mousedown)': 'onMouseDown($event)',
179
452
  '(keydown)': 'onKeyDown($event)',
180
453
  '(focus)': 'onFocus()'
@@ -182,10 +455,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
182
455
  }]
183
456
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
184
457
 
185
- const tabsImports = [RdxTabsRootDirective, RdxTabsContentDirective, RdxTabsListDirective, RdxTabsTriggerDirective];
458
+ const tabsImports = [RdxTabsRoot, RdxTabsList, RdxTabsTab, RdxTabsPanel, RdxTabsPanelPresence, RdxTabsIndicator];
186
459
  class RdxTabsModule {
187
460
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
188
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsModule, imports: [RdxTabsRootDirective, RdxTabsContentDirective, RdxTabsListDirective, RdxTabsTriggerDirective], exports: [RdxTabsRootDirective, RdxTabsContentDirective, RdxTabsListDirective, RdxTabsTriggerDirective] }); }
461
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsModule, imports: [RdxTabsRoot, RdxTabsList, RdxTabsTab, RdxTabsPanel, RdxTabsPanelPresence, RdxTabsIndicator], exports: [RdxTabsRoot, RdxTabsList, RdxTabsTab, RdxTabsPanel, RdxTabsPanelPresence, RdxTabsIndicator] }); }
189
462
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsModule }); }
190
463
  }
191
464
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsModule, decorators: [{
@@ -200,5 +473,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
200
473
  * Generated bundle index. Do not edit.
201
474
  */
202
475
 
203
- export { RDX_TABS_ROOT_TOKEN, RdxTabsContentDirective, RdxTabsListDirective, RdxTabsModule, RdxTabsRootDirective, RdxTabsTriggerDirective };
476
+ export { RdxTabsIndicator, RdxTabsList, RdxTabsModule, RdxTabsPanel, RdxTabsPanelPresence, RdxTabsRoot, RdxTabsTab, injectTabsRootContext, provideTabsRootContext, tabsImports };
204
477
  //# sourceMappingURL=radix-ng-primitives-tabs.mjs.map