@radix-ng/primitives 0.50.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 (207) hide show
  1. package/collection/README.md +1 -0
  2. package/fesm2022/radix-ng-primitives-accordion.mjs +134 -66
  3. package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
  4. package/fesm2022/radix-ng-primitives-alert-dialog.mjs +224 -132
  5. package/fesm2022/radix-ng-primitives-alert-dialog.mjs.map +1 -1
  6. package/fesm2022/radix-ng-primitives-arrow.mjs +26 -10
  7. package/fesm2022/radix-ng-primitives-arrow.mjs.map +1 -1
  8. package/fesm2022/radix-ng-primitives-aspect-ratio.mjs +6 -6
  9. package/fesm2022/radix-ng-primitives-aspect-ratio.mjs.map +1 -1
  10. package/fesm2022/radix-ng-primitives-avatar.mjs +68 -75
  11. package/fesm2022/radix-ng-primitives-avatar.mjs.map +1 -1
  12. package/fesm2022/radix-ng-primitives-button.mjs +123 -0
  13. package/fesm2022/radix-ng-primitives-button.mjs.map +1 -0
  14. package/fesm2022/radix-ng-primitives-calendar.mjs +104 -103
  15. package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
  16. package/fesm2022/radix-ng-primitives-checkbox.mjs +414 -80
  17. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  18. package/fesm2022/radix-ng-primitives-collapsible.mjs +193 -92
  19. package/fesm2022/radix-ng-primitives-collapsible.mjs.map +1 -1
  20. package/fesm2022/radix-ng-primitives-collection.mjs +72 -0
  21. package/fesm2022/radix-ng-primitives-collection.mjs.map +1 -0
  22. package/fesm2022/radix-ng-primitives-config.mjs +5 -5
  23. package/fesm2022/radix-ng-primitives-config.mjs.map +1 -1
  24. package/fesm2022/radix-ng-primitives-context-menu.mjs +143 -427
  25. package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
  26. package/fesm2022/radix-ng-primitives-core.mjs +757 -757
  27. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  28. package/fesm2022/radix-ng-primitives-cropper.mjs +55 -53
  29. package/fesm2022/radix-ng-primitives-cropper.mjs.map +1 -1
  30. package/fesm2022/radix-ng-primitives-date-field.mjs +93 -86
  31. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  32. package/fesm2022/radix-ng-primitives-dialog.mjs +658 -330
  33. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  34. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs +98 -76
  35. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs.map +1 -1
  36. package/fesm2022/radix-ng-primitives-drawer.mjs +1059 -0
  37. package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -0
  38. package/fesm2022/radix-ng-primitives-editable.mjs +20 -20
  39. package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
  40. package/fesm2022/radix-ng-primitives-field.mjs +363 -0
  41. package/fesm2022/radix-ng-primitives-field.mjs.map +1 -0
  42. package/fesm2022/radix-ng-primitives-fieldset.mjs +79 -0
  43. package/fesm2022/radix-ng-primitives-fieldset.mjs.map +1 -0
  44. package/fesm2022/radix-ng-primitives-focus-guards.mjs +3 -3
  45. package/fesm2022/radix-ng-primitives-focus-guards.mjs.map +1 -1
  46. package/fesm2022/radix-ng-primitives-focus-scope.mjs +29 -14
  47. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  48. package/fesm2022/radix-ng-primitives-input.mjs +172 -0
  49. package/fesm2022/radix-ng-primitives-input.mjs.map +1 -0
  50. package/fesm2022/radix-ng-primitives-label.mjs +11 -11
  51. package/fesm2022/radix-ng-primitives-label.mjs.map +1 -1
  52. package/fesm2022/radix-ng-primitives-menu.mjs +1484 -353
  53. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  54. package/fesm2022/radix-ng-primitives-menubar.mjs +290 -162
  55. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  56. package/fesm2022/radix-ng-primitives-meter.mjs +271 -0
  57. package/fesm2022/radix-ng-primitives-meter.mjs.map +1 -0
  58. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +1060 -1553
  59. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  60. package/fesm2022/radix-ng-primitives-number-field.mjs +1102 -366
  61. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
  62. package/fesm2022/radix-ng-primitives-pagination.mjs +51 -51
  63. package/fesm2022/radix-ng-primitives-pagination.mjs.map +1 -1
  64. package/fesm2022/radix-ng-primitives-popover.mjs +980 -995
  65. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  66. package/fesm2022/radix-ng-primitives-popper.mjs +137 -82
  67. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  68. package/fesm2022/radix-ng-primitives-portal.mjs +40 -16
  69. package/fesm2022/radix-ng-primitives-portal.mjs.map +1 -1
  70. package/fesm2022/radix-ng-primitives-presence.mjs +134 -246
  71. package/fesm2022/radix-ng-primitives-presence.mjs.map +1 -1
  72. package/fesm2022/radix-ng-primitives-preview-card.mjs +997 -0
  73. package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -0
  74. package/fesm2022/radix-ng-primitives-progress.mjs +231 -92
  75. package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -1
  76. package/fesm2022/radix-ng-primitives-radio.mjs +211 -70
  77. package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
  78. package/fesm2022/radix-ng-primitives-roving-focus.mjs +127 -77
  79. package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
  80. package/fesm2022/radix-ng-primitives-select.mjs +791 -511
  81. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  82. package/fesm2022/radix-ng-primitives-separator.mjs +16 -45
  83. package/fesm2022/radix-ng-primitives-separator.mjs.map +1 -1
  84. package/fesm2022/radix-ng-primitives-slider.mjs +976 -720
  85. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  86. package/fesm2022/radix-ng-primitives-stepper.mjs +69 -71
  87. package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
  88. package/fesm2022/radix-ng-primitives-switch.mjs +128 -124
  89. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  90. package/fesm2022/radix-ng-primitives-tabs.mjs +388 -115
  91. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  92. package/fesm2022/radix-ng-primitives-time-field.mjs +111 -117
  93. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  94. package/fesm2022/radix-ng-primitives-toggle-group.mjs +122 -248
  95. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  96. package/fesm2022/radix-ng-primitives-toggle.mjs +99 -62
  97. package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
  98. package/fesm2022/radix-ng-primitives-toolbar.mjs +307 -94
  99. package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
  100. package/fesm2022/radix-ng-primitives-tooltip.mjs +690 -1079
  101. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  102. package/fesm2022/radix-ng-primitives-visually-hidden.mjs +46 -87
  103. package/fesm2022/radix-ng-primitives-visually-hidden.mjs.map +1 -1
  104. package/fesm2022/radix-ng-primitives.mjs.map +1 -1
  105. package/meter/README.md +3 -0
  106. package/navigation-menu/README.md +2 -1
  107. package/package.json +85 -63
  108. package/portal/README.md +2 -0
  109. package/preview-card/README.md +3 -0
  110. package/schematics/collection.json +1 -0
  111. package/schematics/ng-add/index.d.ts +3 -2
  112. package/schematics/ng-add/index.js +62 -31
  113. package/schematics/ng-add/index.js.map +1 -1
  114. package/schematics/ng-add/package-config.d.ts +4 -2
  115. package/schematics/ng-add/package-config.js +10 -2
  116. package/schematics/ng-add/package-config.js.map +1 -1
  117. package/schematics/ng-add/schema.d.ts +3 -0
  118. package/schematics/ng-add/schema.js +3 -0
  119. package/schematics/ng-add/schema.js.map +1 -0
  120. package/schematics/ng-add/schema.json +14 -0
  121. package/select/README.md +2 -0
  122. package/{accordion/index.d.ts → types/radix-ng-primitives-accordion.d.ts} +102 -67
  123. package/types/radix-ng-primitives-alert-dialog.d.ts +114 -0
  124. package/{arrow/index.d.ts → types/radix-ng-primitives-arrow.d.ts} +1 -1
  125. package/{aspect-ratio/index.d.ts → types/radix-ng-primitives-aspect-ratio.d.ts} +1 -1
  126. package/{avatar/index.d.ts → types/radix-ng-primitives-avatar.d.ts} +7 -11
  127. package/types/radix-ng-primitives-button.d.ts +73 -0
  128. package/{calendar/index.d.ts → types/radix-ng-primitives-calendar.d.ts} +2 -3
  129. package/types/radix-ng-primitives-checkbox.d.ts +337 -0
  130. package/types/radix-ng-primitives-collapsible.d.ts +159 -0
  131. package/types/radix-ng-primitives-collection.d.ts +44 -0
  132. package/{config/index.d.ts → types/radix-ng-primitives-config.d.ts} +1 -1
  133. package/types/radix-ng-primitives-context-menu.d.ts +73 -0
  134. package/{core/index.d.ts → types/radix-ng-primitives-core.d.ts} +311 -236
  135. package/{cropper/index.d.ts → types/radix-ng-primitives-cropper.d.ts} +6 -5
  136. package/{date-field/index.d.ts → types/radix-ng-primitives-date-field.d.ts} +42 -27
  137. package/types/radix-ng-primitives-dialog.d.ts +323 -0
  138. package/{dismissable-layer/index.d.ts → types/radix-ng-primitives-dismissable-layer.d.ts} +15 -7
  139. package/types/radix-ng-primitives-drawer.d.ts +448 -0
  140. package/{editable/index.d.ts → types/radix-ng-primitives-editable.d.ts} +1 -1
  141. package/types/radix-ng-primitives-field.d.ts +373 -0
  142. package/types/radix-ng-primitives-fieldset.d.ts +48 -0
  143. package/{focus-scope/index.d.ts → types/radix-ng-primitives-focus-scope.d.ts} +13 -5
  144. package/types/radix-ng-primitives-input.d.ts +87 -0
  145. package/{label/index.d.ts → types/radix-ng-primitives-label.d.ts} +0 -1
  146. package/types/radix-ng-primitives-menu.d.ts +612 -0
  147. package/types/radix-ng-primitives-menubar.d.ts +66 -0
  148. package/types/radix-ng-primitives-meter.d.ts +193 -0
  149. package/types/radix-ng-primitives-navigation-menu.d.ts +488 -0
  150. package/types/radix-ng-primitives-number-field.d.ts +464 -0
  151. package/{pagination/index.d.ts → types/radix-ng-primitives-pagination.d.ts} +2 -2
  152. package/types/radix-ng-primitives-popover.d.ts +416 -0
  153. package/{popper/index.d.ts → types/radix-ng-primitives-popper.d.ts} +50 -9
  154. package/types/radix-ng-primitives-portal.d.ts +30 -0
  155. package/types/radix-ng-primitives-presence.d.ts +55 -0
  156. package/types/radix-ng-primitives-preview-card.d.ts +359 -0
  157. package/types/radix-ng-primitives-progress.d.ts +206 -0
  158. package/{radio/index.d.ts → types/radix-ng-primitives-radio.d.ts} +56 -26
  159. package/{roving-focus/index.d.ts → types/radix-ng-primitives-roving-focus.d.ts} +38 -27
  160. package/types/radix-ng-primitives-select.d.ts +512 -0
  161. package/types/radix-ng-primitives-separator.d.ts +38 -0
  162. package/types/radix-ng-primitives-slider.d.ts +377 -0
  163. package/{stepper/index.d.ts → types/radix-ng-primitives-stepper.d.ts} +21 -22
  164. package/types/radix-ng-primitives-switch.d.ts +121 -0
  165. package/types/radix-ng-primitives-tabs.d.ts +247 -0
  166. package/{time-field/index.d.ts → types/radix-ng-primitives-time-field.d.ts} +46 -31
  167. package/types/radix-ng-primitives-toggle-group.d.ts +116 -0
  168. package/types/radix-ng-primitives-toggle.d.ts +65 -0
  169. package/types/radix-ng-primitives-toolbar.d.ts +180 -0
  170. package/types/radix-ng-primitives-tooltip.d.ts +395 -0
  171. package/{visually-hidden/index.d.ts → types/radix-ng-primitives-visually-hidden.d.ts} +19 -19
  172. package/alert-dialog/index.d.ts +0 -57
  173. package/checkbox/index.d.ts +0 -164
  174. package/collapsible/index.d.ts +0 -85
  175. package/context-menu/index.d.ts +0 -129
  176. package/dialog/index.d.ts +0 -205
  177. package/dropdown-menu/README.md +0 -1
  178. package/dropdown-menu/index.d.ts +0 -171
  179. package/fesm2022/radix-ng-primitives-dropdown-menu.mjs +0 -583
  180. package/fesm2022/radix-ng-primitives-dropdown-menu.mjs.map +0 -1
  181. package/fesm2022/radix-ng-primitives-hover-card.mjs +0 -1246
  182. package/fesm2022/radix-ng-primitives-hover-card.mjs.map +0 -1
  183. package/fesm2022/radix-ng-primitives-tooltip2.mjs +0 -740
  184. package/fesm2022/radix-ng-primitives-tooltip2.mjs.map +0 -1
  185. package/hover-card/README.md +0 -3
  186. package/hover-card/index.d.ts +0 -472
  187. package/menu/index.d.ts +0 -139
  188. package/menubar/index.d.ts +0 -56
  189. package/navigation-menu/index.d.ts +0 -405
  190. package/number-field/index.d.ts +0 -203
  191. package/popover/index.d.ts +0 -403
  192. package/portal/index.d.ts +0 -22
  193. package/presence/index.d.ts +0 -103
  194. package/progress/index.d.ts +0 -79
  195. package/select/index.d.ts +0 -214
  196. package/separator/index.d.ts +0 -63
  197. package/slider/index.d.ts +0 -263
  198. package/switch/index.d.ts +0 -105
  199. package/tabs/index.d.ts +0 -112
  200. package/toggle/index.d.ts +0 -75
  201. package/toggle-group/index.d.ts +0 -194
  202. package/toolbar/index.d.ts +0 -55
  203. package/tooltip/index.d.ts +0 -433
  204. package/tooltip2/README.md +0 -3
  205. package/tooltip2/index.d.ts +0 -325
  206. /package/{focus-guards/index.d.ts → types/radix-ng-primitives-focus-guards.d.ts} +0 -0
  207. /package/{index.d.ts → types/radix-ng-primitives.d.ts} +0 -0
@@ -1,194 +1,467 @@
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" }] : []));
14
- this.defaultValue = input(...(ngDevMode ? [undefined, { debugName: "defaultValue" }] : []));
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" }] : []));
19
- /**
20
- * The orientation of the component.
21
- */
22
- this.orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
23
- this.dir = input('ltr', ...(ngDevMode ? [{ debugName: "dir" }] : []));
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: "20.3.3", ngImport: i0, type: RdxTabsRootDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
43
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.3", 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: "20.3.3", 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
- }] });
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();
163
+ /**
164
+ * A unique value that associates the panel with a tab.
165
+ */
166
+ this.value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* 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 */ []));
67
191
  /**
68
- * A unique value that associates the content with a trigger.
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.
69
195
  */
70
- this.value = input.required(...(ngDevMode ? [{ debugName: "value" }] : []));
71
- this.contentId = computed(() => makeContentId(this.tabsContext.getBaseId(), this.value()), ...(ngDevMode ? [{ debugName: "contentId" }] : []));
72
- this.triggerId = computed(() => makeTriggerId(this.tabsContext.getBaseId(), this.value()), ...(ngDevMode ? [{ debugName: "triggerId" }] : []));
73
- this.selected = computed(() => this.tabsContext.value() === this.value(), ...(ngDevMode ? [{ debugName: "selected" }] : []));
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: "20.3.3", ngImport: i0, type: RdxTabsContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
76
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.3", 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: "20.3.3", 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
- }] });
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: "20.3.3", ngImport: i0, type: RdxTabsListDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
99
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.3", 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: "20.3.3", 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
- this.value = input.required(...(ngDevMode ? [{ debugName: "value" }] : []));
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
- this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", transform: booleanAttribute }] : [{
126
- transform: booleanAttribute
127
- }]));
128
- this.contentId = computed(() => makeContentId(this.tabsContext.getBaseId(), this.value()), ...(ngDevMode ? [{ debugName: "contentId" }] : []));
129
- this.triggerId = computed(() => makeTriggerId(this.tabsContext.getBaseId(), this.value()), ...(ngDevMode ? [{ debugName: "triggerId" }] : []));
130
- this.isSelected = computed(() => this.tabsContext.value() === this.value(), ...(ngDevMode ? [{ debugName: "isSelected" }] : []));
131
- effect(() => this.rdxRovingFocusItemDirective.setActive(this.isSelected()));
391
+ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
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
+ });
132
402
  }
403
+ /** @ignore */
133
404
  onMouseDown(event) {
134
- // only call handler if it's the left button (mousedown gets triggered by all mouse buttons)
135
- // but not when the control key is pressed (avoiding MacOS right click)
405
+ // Only the primary button selects; ignore Ctrl-click (macOS right-click emulation).
136
406
  if (!this.disabled() && event.button === 0 && !event.ctrlKey) {
137
- this.tabsContext?.select(this.value());
407
+ this.rootContext.setValue(this.value());
138
408
  }
139
409
  else {
140
- // prevent focus to avoid accidental activation
410
+ // Prevent focus to avoid accidental activation.
141
411
  event.preventDefault();
142
412
  }
143
413
  }
414
+ /** @ignore */
144
415
  onKeyDown(event) {
145
- if ([' ', 'Enter'].includes(event.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: "20.3.3", ngImport: i0, type: RdxTabsTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
156
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.3", 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", "disabled": "disabled()", "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: "20.3.3", 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",
175
- '[disabled]': 'disabled()',
176
- '[attr.data-state]': "isSelected() ? 'active' : 'inactive'",
177
- '[attr.data-orientation]': 'tabsContext.orientation()',
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',
450
+ '[attr.disabled]': 'disabled() ? "" : undefined',
178
451
  '(mousedown)': 'onMouseDown($event)',
179
452
  '(keydown)': 'onKeyDown($event)',
180
453
  '(focus)': 'onFocus()'
181
454
  }
182
455
  }]
183
- }], ctorParameters: () => [] });
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
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxTabsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
188
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.3", ngImport: i0, type: RdxTabsModule, imports: [RdxTabsRootDirective, RdxTabsContentDirective, RdxTabsListDirective, RdxTabsTriggerDirective], exports: [RdxTabsRootDirective, RdxTabsContentDirective, RdxTabsListDirective, RdxTabsTriggerDirective] }); }
189
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxTabsModule }); }
460
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
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] }); }
462
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsModule }); }
190
463
  }
191
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxTabsModule, decorators: [{
464
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTabsModule, decorators: [{
192
465
  type: NgModule,
193
466
  args: [{
194
467
  imports: [...tabsImports],
@@ -200,5 +473,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", 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