@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
@@ -3,10 +3,10 @@ import { InjectionToken, signal, computed, input, booleanAttribute, linkedSignal
3
3
 
4
4
  const RdxDismissableLayersContextToken = new InjectionToken('RdxDismissableLayersContextToken', {
5
5
  factory() {
6
- const layersRoot = signal([], ...(ngDevMode ? [{ debugName: "layersRoot" }] : []));
6
+ const layersRoot = signal([], ...(ngDevMode ? [{ debugName: "layersRoot" }] : /* istanbul ignore next */ []));
7
7
  return {
8
8
  layersRoot,
9
- layersWithOutsidePointerEventsDisabled: computed(() => layersRoot().filter((i) => i.disableOutsidePointerEvents())),
9
+ layersWithOutsidePointerEventsDisabled: computed(() => layersRoot().filter((i) => i.isOutsidePointerEventsDisabled())),
10
10
  branches: signal([])
11
11
  };
12
12
  }
@@ -50,13 +50,13 @@ class RdxFocusOutside {
50
50
  return this.#enabled();
51
51
  }
52
52
  constructor() {
53
- this.enabledInput = input(true, ...(ngDevMode ? [{ debugName: "enabledInput", transform: booleanAttribute, alias: 'enabled' }] : [{ transform: booleanAttribute, alias: 'enabled' }]));
54
- this.#enabled = linkedSignal(() => this.enabledInput(), ...(ngDevMode ? [{ debugName: "#enabled" }] : []));
53
+ this.enabledInput = input(true, { ...(ngDevMode ? { debugName: "enabledInput" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'enabled' });
54
+ this.#enabled = linkedSignal(() => this.enabledInput(), ...(ngDevMode ? [{ debugName: "#enabled" }] : /* istanbul ignore next */ []));
55
55
  this.focusOutside = output();
56
56
  /*
57
57
  * Flag to indicate if the focus is currently within the DOM subtree
58
58
  */
59
- this.isFocusInsideDOMTree = signal(false, ...(ngDevMode ? [{ debugName: "isFocusInsideDOMTree" }] : []));
59
+ this.isFocusInsideDOMTree = signal(false, ...(ngDevMode ? [{ debugName: "isFocusInsideDOMTree" }] : /* istanbul ignore next */ []));
60
60
  /*
61
61
  * Handles capturing the focus event to mark focus as inside the DOM subtree
62
62
  */
@@ -83,6 +83,9 @@ class RdxFocusOutside {
83
83
  if (!elementRef?.nativeElement) {
84
84
  return;
85
85
  }
86
+ // Defer past the focus settling: the first microtask lets the matching capture
87
+ // `focus`/`blur` handler update `isFocusInsideDOMTree`, the second lets the browser
88
+ // finish moving focus, so the check below reflects the final focus target.
86
89
  await Promise.resolve();
87
90
  await Promise.resolve();
88
91
  const target = event.target;
@@ -111,16 +114,16 @@ class RdxFocusOutside {
111
114
  });
112
115
  });
113
116
  }
114
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxFocusOutside, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
115
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.3", type: RdxFocusOutside, isStandalone: true, selector: "[rdxFocusOutside]", inputs: { enabledInput: { classPropertyName: "enabledInput", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { focusOutside: "focusOutside" }, exportAs: ["rdxFocusOutside"], ngImport: i0 }); }
117
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxFocusOutside, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
118
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxFocusOutside, isStandalone: true, selector: "[rdxFocusOutside]", inputs: { enabledInput: { classPropertyName: "enabledInput", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { focusOutside: "focusOutside" }, exportAs: ["rdxFocusOutside"], ngImport: i0 }); }
116
119
  }
117
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxFocusOutside, decorators: [{
120
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxFocusOutside, decorators: [{
118
121
  type: Directive,
119
122
  args: [{
120
123
  selector: '[rdxFocusOutside]',
121
124
  exportAs: 'rdxFocusOutside'
122
125
  }]
123
- }], ctorParameters: () => [] });
126
+ }], ctorParameters: () => [], propDecorators: { enabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "enabled", required: false }] }], focusOutside: [{ type: i0.Output, args: ["focusOutside"] }] } });
124
127
  /**
125
128
  * Listens for `pointerdown` outside a DOM subtree. We use `pointerdown` rather than `pointerup`
126
129
  * to mimic layer dismissing behavior present in OS.
@@ -138,16 +141,25 @@ class RdxPointerDownOutside {
138
141
  }
139
142
  constructor() {
140
143
  this.elementRef = inject(ElementRef);
141
- this.enabledInput = input(true, ...(ngDevMode ? [{ debugName: "enabledInput", transform: booleanAttribute, alias: 'enabled' }] : [{ transform: booleanAttribute, alias: 'enabled' }]));
142
- this.#enabled = linkedSignal(() => this.enabledInput(), ...(ngDevMode ? [{ debugName: "#enabled" }] : []));
144
+ this.enabledInput = input(true, { ...(ngDevMode ? { debugName: "enabledInput" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'enabled' });
145
+ this.#enabled = linkedSignal(() => this.enabledInput(), ...(ngDevMode ? [{ debugName: "#enabled" }] : /* istanbul ignore next */ []));
143
146
  this.pointerDownOutside = output();
144
- this.isPointerInsideDOMTree = signal(false, ...(ngDevMode ? [{ debugName: "isPointerInsideDOMTree" }] : []));
147
+ this.isPointerInsideDOMTree = signal(false, ...(ngDevMode ? [{ debugName: "isPointerInsideDOMTree" }] : /* istanbul ignore next */ []));
145
148
  this.handleAndDispatchPointerDownOutsideEvent = (e) => () => this.pointerDownOutside.emit(e);
146
149
  effect((onCleanup) => {
147
150
  if (!this.#enabled()) {
148
151
  return;
149
152
  }
150
153
  const ownerDocument = this.elementRef.nativeElement.ownerDocument ?? globalThis.document;
154
+ // Avoid the global `window` so this stays safe under SSR; `globalThis` provides
155
+ // `setTimeout`/`clearTimeout` in both the browser and Node.
156
+ const ownerWindow = ownerDocument.defaultView ?? globalThis;
157
+ const removeClickListener = () => {
158
+ if (this.handleClick) {
159
+ ownerDocument.removeEventListener('click', this.handleClick);
160
+ this.handleClick = undefined;
161
+ }
162
+ };
151
163
  const handlePointerDown = async (event) => {
152
164
  if (event.target && !this.isPointerInsideDOMTree()) {
153
165
  /**
@@ -163,7 +175,7 @@ class RdxPointerDownOutside {
163
175
  * certain that it was raised, and therefore cleaned-up.
164
176
  */
165
177
  if (event.pointerType === 'touch') {
166
- ownerDocument.removeEventListener('click', this.handleClick);
178
+ removeClickListener();
167
179
  this.handleClick = this.handleAndDispatchPointerDownOutsideEvent(event);
168
180
  ownerDocument.addEventListener('click', this.handleClick, {
169
181
  once: true
@@ -176,7 +188,7 @@ class RdxPointerDownOutside {
176
188
  else {
177
189
  // We need to remove the event listener in case the outside click has been canceled.
178
190
  // See: https://github.com/radix-ui/primitives/issues/2171
179
- ownerDocument.removeEventListener('click', this.handleClick);
191
+ removeClickListener();
180
192
  }
181
193
  this.isPointerInsideDOMTree.set(false);
182
194
  };
@@ -193,7 +205,7 @@ class RdxPointerDownOutside {
193
205
  * })
194
206
  * });
195
207
  */
196
- const timerId = window.setTimeout(() => {
208
+ const timerId = ownerWindow.setTimeout(() => {
197
209
  ownerDocument.addEventListener('pointerdown', handlePointerDown);
198
210
  }, 0);
199
211
  const onPointerDownCapture = () => {
@@ -204,31 +216,31 @@ class RdxPointerDownOutside {
204
216
  };
205
217
  this.elementRef.nativeElement.addEventListener('pointerdown', onPointerDownCapture, { capture: true });
206
218
  onCleanup(() => {
207
- window.clearTimeout(timerId);
219
+ ownerWindow.clearTimeout(timerId);
208
220
  ownerDocument.removeEventListener('pointerdown', handlePointerDown);
209
- ownerDocument.removeEventListener('click', this.handleClick);
221
+ removeClickListener();
210
222
  this.elementRef.nativeElement.removeEventListener('pointerdown', onPointerDownCapture, {
211
223
  capture: true
212
224
  });
213
225
  });
214
226
  });
215
227
  }
216
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxPointerDownOutside, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
217
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.3", type: RdxPointerDownOutside, isStandalone: true, selector: "[rdxPointerDownOutside]", inputs: { enabledInput: { classPropertyName: "enabledInput", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pointerDownOutside: "pointerDownOutside" }, exportAs: ["rdxPointerDownOutside"], ngImport: i0 }); }
228
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPointerDownOutside, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
229
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPointerDownOutside, isStandalone: true, selector: "[rdxPointerDownOutside]", inputs: { enabledInput: { classPropertyName: "enabledInput", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pointerDownOutside: "pointerDownOutside" }, exportAs: ["rdxPointerDownOutside"], ngImport: i0 }); }
218
230
  }
219
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxPointerDownOutside, decorators: [{
231
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPointerDownOutside, decorators: [{
220
232
  type: Directive,
221
233
  args: [{
222
234
  selector: '[rdxPointerDownOutside]',
223
235
  exportAs: 'rdxPointerDownOutside'
224
236
  }]
225
- }], ctorParameters: () => [] });
237
+ }], ctorParameters: () => [], propDecorators: { enabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "enabled", required: false }] }], pointerDownOutside: [{ type: i0.Output, args: ["pointerDownOutside"] }] } });
226
238
  class RdxEscapeKeyDown {
227
239
  constructor() {
228
240
  this.elementRef = inject(ElementRef);
229
241
  this.destroyRef = inject(DestroyRef);
230
242
  this.escapeKeyDown = output();
231
- this.afterNextRender = afterNextRender(() => {
243
+ afterNextRender(() => {
232
244
  const ownerDocument = this.elementRef.nativeElement.ownerDocument ?? globalThis.document;
233
245
  const handleKeyDown = (event) => {
234
246
  if (event.key === 'Escape') {
@@ -243,18 +255,24 @@ class RdxEscapeKeyDown {
243
255
  }));
244
256
  });
245
257
  }
246
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxEscapeKeyDown, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
247
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.3", type: RdxEscapeKeyDown, isStandalone: true, selector: "[rdxEscapeKeyDown]", outputs: { escapeKeyDown: "escapeKeyDown" }, exportAs: ["rdxEscapeKeyDown"], ngImport: i0 }); }
258
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxEscapeKeyDown, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
259
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxEscapeKeyDown, isStandalone: true, selector: "[rdxEscapeKeyDown]", outputs: { escapeKeyDown: "escapeKeyDown" }, exportAs: ["rdxEscapeKeyDown"], ngImport: i0 }); }
248
260
  }
249
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxEscapeKeyDown, decorators: [{
261
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxEscapeKeyDown, decorators: [{
250
262
  type: Directive,
251
263
  args: [{
252
264
  selector: '[rdxEscapeKeyDown]',
253
265
  exportAs: 'rdxEscapeKeyDown'
254
266
  }]
255
- }] });
267
+ }], ctorParameters: () => [], propDecorators: { escapeKeyDown: [{ type: i0.Output, args: ["escapeKeyDown"] }] } });
256
268
 
257
- let originalBodyPointerEvents;
269
+ /**
270
+ * Shared across all layers. Holds the body's original `pointer-events` value while at least one
271
+ * layer disables outside pointer events. `null` means the body is not currently overridden — it
272
+ * doubles as the "ownership" flag so stacked layers don't overwrite the saved original with
273
+ * `none`.
274
+ */
275
+ let originalBodyPointerEvents = null;
258
276
  class RdxDismissableLayer {
259
277
  constructor() {
260
278
  this.elementRef = inject(ElementRef);
@@ -295,48 +313,26 @@ class RdxDismissableLayer {
295
313
  * the `DismissableLayer`. Users will need to click twice on outside elements to
296
314
  * interact with them: once to close the `DismissableLayer`, and again to trigger the element.
297
315
  */
298
- this.disableOutsidePointerEvents = input(this.config.disableOutsidePointerEvents(), ...(ngDevMode ? [{ debugName: "disableOutsidePointerEvents", transform: booleanAttribute }] : [{
299
- transform: booleanAttribute
300
- }]));
301
- this.layers = computed(() => this.context.layersRoot, ...(ngDevMode ? [{ debugName: "layers" }] : []));
302
- this.isBodyPointerEventsDisabled = computed(() => this.context.layersWithOutsidePointerEventsDisabled().length > 0, ...(ngDevMode ? [{ debugName: "isBodyPointerEventsDisabled" }] : []));
316
+ this.disableOutsidePointerEvents = input(undefined, { ...(ngDevMode ? { debugName: "disableOutsidePointerEvents" } : /* istanbul ignore next */ {}), transform: (value) => (value === undefined ? undefined : booleanAttribute(value)) });
317
+ this.isOutsidePointerEventsDisabled = computed(() => this.disableOutsidePointerEvents() ?? this.config.disableOutsidePointerEvents(), ...(ngDevMode ? [{ debugName: "isOutsidePointerEventsDisabled" }] : /* istanbul ignore next */ []));
318
+ this.isBodyPointerEventsDisabled = computed(() => this.context.layersWithOutsidePointerEventsDisabled().length > 0, ...(ngDevMode ? [{ debugName: "isBodyPointerEventsDisabled" }] : /* istanbul ignore next */ []));
303
319
  this.isPointerEventsEnabled = computed(() => {
304
- const localLayers = this.layers();
305
- const [highestLayerWithOutsidePointerEventsDisabled] = [
306
- ...this.context.layersWithOutsidePointerEventsDisabled()
307
- ].slice(-1);
308
- const highestLayerWithOutsidePointerEventsDisabledIndex = localLayers().indexOf(highestLayerWithOutsidePointerEventsDisabled);
309
- return this.index() >= highestLayerWithOutsidePointerEventsDisabledIndex;
310
- }, ...(ngDevMode ? [{ debugName: "isPointerEventsEnabled" }] : []));
311
- this.index = computed(() => this.context.layersRoot().indexOf(this), ...(ngDevMode ? [{ debugName: "index" }] : []));
312
- this.afterNextRender = afterNextRender(() => {
313
- const ownerDocument = this.elementRef.nativeElement.ownerDocument ?? globalThis.document;
314
- let lastDisabledCount = 0;
315
- untracked(() => {
316
- this.context.layersRoot.update((v) => (v.includes(this) ? v : [...v, this]));
317
- });
318
- this.destroyRef.onDestroy(() => {
319
- untracked(() => {
320
- this.context.layersRoot.update((v) => v.filter((x) => x !== this));
321
- });
322
- });
323
- effect((onCleanup) => {
324
- const disabledCount = this.context.layersWithOutsidePointerEventsDisabled().length;
325
- if (lastDisabledCount === 0 && disabledCount > 0) {
326
- originalBodyPointerEvents = ownerDocument.body.style.pointerEvents;
327
- ownerDocument.body.style.pointerEvents = 'none';
328
- }
329
- onCleanup(() => {
330
- const next = untracked(() => this.context.layersWithOutsidePointerEventsDisabled().length);
331
- if (lastDisabledCount > 0 && next === 0) {
332
- ownerDocument.body.style.pointerEvents = originalBodyPointerEvents;
333
- }
334
- lastDisabledCount = next;
335
- });
336
- lastDisabledCount = disabledCount;
337
- }, { injector: this.injector });
338
- });
320
+ const layers = this.context.layersRoot();
321
+ const disabledLayers = this.context.layersWithOutsidePointerEventsDisabled();
322
+ const highestDisabledLayer = disabledLayers[disabledLayers.length - 1];
323
+ return this.index() >= layers.indexOf(highestDisabledLayer);
324
+ }, ...(ngDevMode ? [{ debugName: "isPointerEventsEnabled" }] : /* istanbul ignore next */ []));
325
+ this.index = computed(() => this.context.layersRoot().indexOf(this), ...(ngDevMode ? [{ debugName: "index" }] : /* istanbul ignore next */ []));
326
+ /** The topmost layer in the stack the only one that should react to the Escape key. */
327
+ this.isHighestLayer = computed(() => {
328
+ const layers = this.context.layersRoot();
329
+ return layers.indexOf(this) === layers.length - 1;
330
+ }, ...(ngDevMode ? [{ debugName: "isHighestLayer" }] : /* istanbul ignore next */ []));
339
331
  this.context.layersRoot.update((v) => [...v, this]);
332
+ this.destroyRef.onDestroy(() => {
333
+ this.context.layersRoot.update((v) => v.filter((i) => i !== this));
334
+ });
335
+ this.setupBodyPointerEvents();
340
336
  this.rdxPointerDownOutside.pointerDownOutside.subscribe((event) => {
341
337
  const isPointerDownOnBranch = this.context
342
338
  .branches()
@@ -364,20 +360,46 @@ class RdxDismissableLayer {
364
360
  }
365
361
  });
366
362
  this.rdxEscapeKeyDown.escapeKeyDown.subscribe((event) => {
363
+ // Only the topmost layer is dismissed by Escape; stacked layers close one at a time.
364
+ if (!this.isHighestLayer()) {
365
+ return;
366
+ }
367
367
  this.escapeKeyDown.emit(event);
368
368
  if (!event.defaultPrevented) {
369
369
  event.preventDefault();
370
370
  this.dismiss.emit();
371
371
  }
372
372
  });
373
- this.destroyRef.onDestroy(() => {
374
- this.context.layersRoot.update((v) => v.filter((i) => i !== this));
373
+ }
374
+ /**
375
+ * Toggles `pointer-events: none` on the document body while any layer has
376
+ * `disableOutsidePointerEvents`. Ownership is shared across all layers via
377
+ * {@link originalBodyPointerEvents}: the original value is saved only on the global
378
+ * `0 -> >0` transition and restored only when the count returns to `0`.
379
+ */
380
+ setupBodyPointerEvents() {
381
+ afterNextRender(() => {
382
+ const ownerDocument = this.elementRef.nativeElement.ownerDocument ?? globalThis.document;
383
+ effect((onCleanup) => {
384
+ const disabledCount = this.context.layersWithOutsidePointerEventsDisabled().length;
385
+ if (disabledCount > 0 && originalBodyPointerEvents === null) {
386
+ originalBodyPointerEvents = ownerDocument.body.style.pointerEvents;
387
+ ownerDocument.body.style.pointerEvents = 'none';
388
+ }
389
+ onCleanup(() => {
390
+ const remaining = untracked(() => this.context.layersWithOutsidePointerEventsDisabled().length);
391
+ if (remaining === 0 && originalBodyPointerEvents !== null) {
392
+ ownerDocument.body.style.pointerEvents = originalBodyPointerEvents;
393
+ originalBodyPointerEvents = null;
394
+ }
395
+ });
396
+ }, { injector: this.injector });
375
397
  });
376
398
  }
377
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDismissableLayer, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
378
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.3", type: RdxDismissableLayer, isStandalone: true, selector: "[rdxDismissableLayer]", inputs: { disableOutsidePointerEvents: { classPropertyName: "disableOutsidePointerEvents", publicName: "disableOutsidePointerEvents", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside", focusOutside: "focusOutside", interactOutside: "interactOutside", dismiss: "dismiss" }, host: { attributes: { "data-dismissable-layer": "" }, properties: { "style": "{\n pointerEvents: isBodyPointerEventsDisabled() ? (isPointerEventsEnabled() ? 'auto' : 'none') : undefined\n }" } }, exportAs: ["rdxDismissableLayer"], hostDirectives: [{ directive: RdxPointerDownOutside }, { directive: RdxFocusOutside }, { directive: RdxEscapeKeyDown }], ngImport: i0 }); }
399
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDismissableLayer, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
400
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxDismissableLayer, isStandalone: true, selector: "[rdxDismissableLayer]", inputs: { disableOutsidePointerEvents: { classPropertyName: "disableOutsidePointerEvents", publicName: "disableOutsidePointerEvents", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside", focusOutside: "focusOutside", interactOutside: "interactOutside", dismiss: "dismiss" }, host: { attributes: { "data-dismissable-layer": "" }, properties: { "style": "{\n pointerEvents: isBodyPointerEventsDisabled() ? (isPointerEventsEnabled() ? 'auto' : 'none') : undefined\n }" } }, exportAs: ["rdxDismissableLayer"], hostDirectives: [{ directive: RdxPointerDownOutside }, { directive: RdxFocusOutside }, { directive: RdxEscapeKeyDown }], ngImport: i0 }); }
379
401
  }
380
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDismissableLayer, decorators: [{
402
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDismissableLayer, decorators: [{
381
403
  type: Directive,
382
404
  args: [{
383
405
  selector: '[rdxDismissableLayer]',
@@ -390,7 +412,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImpor
390
412
  }`
391
413
  }
392
414
  }]
393
- }], ctorParameters: () => [] });
415
+ }], ctorParameters: () => [], propDecorators: { escapeKeyDown: [{ type: i0.Output, args: ["escapeKeyDown"] }], pointerDownOutside: [{ type: i0.Output, args: ["pointerDownOutside"] }], focusOutside: [{ type: i0.Output, args: ["focusOutside"] }], interactOutside: [{ type: i0.Output, args: ["interactOutside"] }], dismiss: [{ type: i0.Output, args: ["dismiss"] }], disableOutsidePointerEvents: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableOutsidePointerEvents", required: false }] }] } });
394
416
 
395
417
  class RdxDismissableLayerBranch {
396
418
  constructor() {
@@ -400,10 +422,10 @@ class RdxDismissableLayerBranch {
400
422
  this.dismissableLayersContext.branches.update((elements) => [...elements, this.elementRef.nativeElement]);
401
423
  this.destroyRef.onDestroy(() => this.dismissableLayersContext.branches.update((elements) => elements.filter((el) => el !== this.elementRef.nativeElement)));
402
424
  }
403
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDismissableLayerBranch, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
404
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.3", type: RdxDismissableLayerBranch, isStandalone: true, selector: "[rdxDismissableLayerBranch]", ngImport: i0 }); }
425
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDismissableLayerBranch, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
426
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDismissableLayerBranch, isStandalone: true, selector: "[rdxDismissableLayerBranch]", ngImport: i0 }); }
405
427
  }
406
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDismissableLayerBranch, decorators: [{
428
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDismissableLayerBranch, decorators: [{
407
429
  type: Directive,
408
430
  args: [{
409
431
  selector: '[rdxDismissableLayerBranch]'