@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,423 +1,751 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, computed, inject, Directive, DestroyRef, Injector, RendererFactory2, runInInjectionContext, effect, Renderer2, Injectable, makeEnvironmentProviders, importProvidersFrom, input, Input, NgModule } from '@angular/core';
3
- import { map, filter, isObservable, of, take, merge, switchMap, takeUntil } from 'rxjs';
4
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
- import { Dialog, DialogModule, DIALOG_DATA } from '@angular/cdk/dialog';
2
+ import { InjectionToken, booleanAttribute, inject, DestroyRef, model, input, output, signal, computed, effect, untracked, Directive, ElementRef, NgModule } from '@angular/core';
3
+ import { createContext, useTransitionStatus, injectId, useScrollLock } from '@radix-ng/primitives/core';
4
+ import { outputFromObservable, outputToObservable } from '@angular/core/rxjs-interop';
5
+ import * as i1 from '@radix-ng/primitives/dismissable-layer';
6
+ import { RdxDismissableLayer, provideRdxDismissableLayerConfig } from '@radix-ng/primitives/dismissable-layer';
7
+ import * as i2 from '@radix-ng/primitives/focus-scope';
8
+ import { RdxFocusScope, provideRdxFocusScopeConfig } from '@radix-ng/primitives/focus-scope';
9
+ import * as i1$1 from '@radix-ng/primitives/portal';
10
+ import { RdxPortal } from '@radix-ng/primitives/portal';
11
+ import * as i1$2 from '@radix-ng/primitives/presence';
12
+ import { provideRdxPresenceContext, RdxPresenceDirective } from '@radix-ng/primitives/presence';
6
13
 
7
- const DISMISSED_VALUE = {};
8
- function isDismissed(v) {
9
- return v === DISMISSED_VALUE;
14
+ const DEFAULT_VARIANT = {
15
+ role: 'dialog',
16
+ forceModal: false,
17
+ forcePointerDismissalDisabled: false
18
+ };
19
+ const RDX_DIALOG_VARIANT = new InjectionToken('RdxDialogVariant', {
20
+ factory: () => DEFAULT_VARIANT
21
+ });
22
+ function provideRdxDialogVariant(variant) {
23
+ return { provide: RDX_DIALOG_VARIANT, useValue: { ...DEFAULT_VARIANT, ...variant } };
10
24
  }
25
+
26
+ const transformModal = (value) => value === 'trap-focus' ? value : booleanAttribute(value);
27
+ const context = () => contextFor(inject(RdxDialogRoot));
28
+ const [injectRdxDialogRootContext, provideRdxDialogRootContext] = createContext('RdxDialogRootContext');
11
29
  /**
12
- * Represents a reference to an open dialog.
13
- * Provides methods and observables to interact with and monitor the dialog's state.
14
- * @template C - The type of the dialog's content component
30
+ * Groups all parts of the dialog.
15
31
  */
16
- class RdxDialogRef {
17
- /**
18
- * @param cdkRef - Reference to the underlying CDK dialog
19
- * @param config - Configuration options for the dialog
20
- */
21
- constructor(cdkRef, config) {
22
- this.cdkRef = cdkRef;
23
- this.config = config;
24
- // state tracking
25
- this._openSignal = signal(true, ...(ngDevMode ? [{ debugName: "_openSignal" }] : []));
26
- this.state = computed(() => (this._openSignal() ? 'open' : 'closed'), ...(ngDevMode ? [{ debugName: "state" }] : []));
27
- this.closed$ = this.cdkRef.closed.pipe(map((res) => (isDismissed(res) ? undefined : res)));
28
- this.dismissed$ = this.cdkRef.closed.pipe(filter((res) => res === DISMISSED_VALUE), map(() => undefined));
29
- this.result$ = this.cdkRef.closed.pipe(filter((res) => !isDismissed(res)));
32
+ class RdxDialogRoot {
33
+ constructor() {
34
+ this.destroyRef = inject(DestroyRef);
35
+ this.parentRoot = inject(RdxDialogRoot, { optional: true, skipSelf: true });
36
+ this.variant = inject(RDX_DIALOG_VARIANT);
37
+ this.hasAppliedDefaultOpen = false;
38
+ this.hasAppliedDefaultTriggerId = false;
39
+ this.registeredTriggers = new Map();
40
+ this.transition = useTransitionStatus((open) => this.emitOpenChangeComplete(open));
41
+ this.transitionStatus = this.transition.status;
42
+ this.registerTransitionElement = this.transition.registerElement;
43
+ /**
44
+ * Whether the dialog is currently open.
45
+ */
46
+ this.open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
47
+ /**
48
+ * Whether the dialog is initially open.
49
+ */
50
+ this.defaultOpen = input(false, { ...(ngDevMode ? { debugName: "defaultOpen" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
51
+ /**
52
+ * ID of the trigger associated with a controlled dialog.
53
+ */
54
+ this.triggerId = model(null, ...(ngDevMode ? [{ debugName: "triggerId" }] : /* istanbul ignore next */ []));
55
+ /**
56
+ * ID of the trigger associated with an initially open uncontrolled dialog.
57
+ */
58
+ this.defaultTriggerId = input(null, ...(ngDevMode ? [{ debugName: "defaultTriggerId" }] : /* istanbul ignore next */ []));
59
+ /**
60
+ * Determines if the dialog enters a modal state when open.
61
+ * - `true`: focus is trapped, page scroll is locked, outside pointer events are disabled.
62
+ * - `false`: interaction with the rest of the document is allowed.
63
+ * - `'trap-focus'`: focus is trapped, but scroll is not locked and outside pointer events remain enabled.
64
+ */
65
+ this.modal = input(true, { ...(ngDevMode ? { debugName: "modal" } : /* istanbul ignore next */ {}), transform: transformModal });
66
+ /**
67
+ * Determines whether the dialog should close on outside clicks.
68
+ */
69
+ this.disablePointerDismissal = input(false, { ...(ngDevMode ? { debugName: "disablePointerDismissal" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
70
+ /**
71
+ * Associates this root with detached trigger elements rendered outside of it.
72
+ */
73
+ this.handle = input(...(ngDevMode ? [undefined, { debugName: "handle" }] : /* istanbul ignore next */ []));
74
+ /**
75
+ * Event handler called when the dialog is opened or closed.
76
+ */
77
+ this.onOpenChange = output();
78
+ /**
79
+ * Event handler called after any animations complete when the dialog is opened or closed.
80
+ */
81
+ this.onOpenChangeComplete = output();
82
+ this.contentId = injectId('rdx-dialog-content-');
83
+ this.titleId = signal(undefined, ...(ngDevMode ? [{ debugName: "titleId" }] : /* istanbul ignore next */ []));
84
+ this.descriptionId = signal(undefined, ...(ngDevMode ? [{ debugName: "descriptionId" }] : /* istanbul ignore next */ []));
85
+ this.trigger = signal(undefined, ...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
86
+ this.triggers = signal([], ...(ngDevMode ? [{ debugName: "triggers" }] : /* istanbul ignore next */ []));
87
+ this.payload = signal(undefined, ...(ngDevMode ? [{ debugName: "payload" }] : /* istanbul ignore next */ []));
88
+ this.nestedOpenCount = signal(0, ...(ngDevMode ? [{ debugName: "nestedOpenCount" }] : /* istanbul ignore next */ []));
89
+ /** Whether this dialog is rendered inside another dialog. Fixed at construction. */
90
+ this.nested = !!this.parentRoot;
91
+ this.nestedDialogOpen = computed(() => this.nestedOpenCount() > 0, ...(ngDevMode ? [{ debugName: "nestedDialogOpen" }] : /* istanbul ignore next */ []));
92
+ /** ARIA role, fixed at construction by the dialog variant (`alertdialog` for alert dialogs). */
93
+ this.role = this.variant.role;
94
+ /** Effective modality: the variant can pin it to `true` regardless of the `modal` input. */
95
+ this.effectiveModal = computed(() => (this.variant.forceModal ? true : this.modal()), ...(ngDevMode ? [{ debugName: "effectiveModal" }] : /* istanbul ignore next */ []));
96
+ /** Effective dismissal flag: disabled when the input asks, or when the variant forces it (alerts). */
97
+ this.effectiveDisablePointerDismissal = computed(() => this.disablePointerDismissal() || this.variant.forcePointerDismissalDisabled, ...(ngDevMode ? [{ debugName: "effectiveDisablePointerDismissal" }] : /* istanbul ignore next */ []));
98
+ let previousOpen = this.open();
99
+ effect(() => {
100
+ const defaultOpen = this.defaultOpen();
101
+ if (!this.hasAppliedDefaultOpen && defaultOpen) {
102
+ this.hasAppliedDefaultOpen = true;
103
+ this.open.set(defaultOpen);
104
+ }
105
+ });
106
+ effect(() => {
107
+ const defaultTriggerId = this.defaultTriggerId();
108
+ if (!this.hasAppliedDefaultTriggerId && defaultTriggerId !== null) {
109
+ this.hasAppliedDefaultTriggerId = true;
110
+ this.triggerId.set(defaultTriggerId);
111
+ }
112
+ });
113
+ effect(() => {
114
+ const triggerId = this.triggerId();
115
+ untracked(() => this.syncTriggerId(triggerId));
116
+ });
117
+ effect(() => {
118
+ const open = this.open();
119
+ if (open !== previousOpen) {
120
+ previousOpen = open;
121
+ untracked(() => this.transition.start(open));
122
+ }
123
+ });
124
+ // Report nested open state to the parent dialog so it can apply data-nested-dialog-open.
125
+ effect((onCleanup) => {
126
+ const open = this.open();
127
+ if (open && this.parentRoot) {
128
+ onCleanup(untracked(() => this.parentRoot.openNestedChild()));
129
+ }
130
+ });
131
+ effect((onCleanup) => {
132
+ const handle = this.handle();
133
+ if (handle) {
134
+ onCleanup(untracked(() => handle.registerRoot(contextFor(this))));
135
+ }
136
+ });
137
+ }
138
+ show(trigger = this.trigger(), payload, triggerId, reason = 'none', event = new Event('dialog.open-change')) {
139
+ if (trigger) {
140
+ this.trigger.set(trigger);
141
+ }
142
+ if (triggerId !== undefined) {
143
+ this.triggerId.set(triggerId);
144
+ }
145
+ // Only adopt the payload when a trigger context is actually provided, so a bare
146
+ // imperative re-show on an already-open dialog doesn't clobber the live payload.
147
+ if (trigger !== undefined || payload !== undefined) {
148
+ this.payload.set(payload);
149
+ }
150
+ if (this.open()) {
151
+ return;
152
+ }
153
+ this.open.set(true);
154
+ this.emitOpenChange(true, reason, event);
30
155
  }
31
- get instance() {
32
- return this.cdkRef.componentInstance;
156
+ close(reason = 'none', event = new Event('dialog.open-change')) {
157
+ if (!this.open()) {
158
+ return;
159
+ }
160
+ this.open.set(false);
161
+ this.emitOpenChange(false, reason, event);
33
162
  }
34
- /**
35
- * Attempts to dismiss the dialog
36
- * Checks the canClose condition before dismissing
37
- */
38
- dismiss() {
39
- if (!this.instance || this.config.isAlert) {
163
+ toggle(triggerId, trigger, payload, event = new Event('dialog.open-change')) {
164
+ if (this.open() && this.trigger() === trigger) {
165
+ this.close('trigger-press', event);
40
166
  return;
41
167
  }
42
- const canClose = this.config.canClose?.(this.instance) ?? true;
43
- const canClose$ = isObservable(canClose) ? canClose : of(canClose);
44
- canClose$.pipe(take(1)).subscribe((close) => {
45
- if (close) {
46
- this.cdkRef.close(DISMISSED_VALUE);
168
+ this.show(trigger, payload, triggerId, 'trigger-press', event);
169
+ }
170
+ registerTrigger(id, trigger, payload) {
171
+ this.registeredTriggers.set(id, { element: trigger, payload });
172
+ this.triggers.update((triggers) => (triggers.includes(trigger) ? triggers : [...triggers, trigger]));
173
+ if (this.triggerId() === id || (!this.trigger() && this.triggerId() === null)) {
174
+ this.trigger.set(trigger);
175
+ this.payload.set(payload());
176
+ }
177
+ return () => {
178
+ if (this.registeredTriggers.get(id)?.element === trigger) {
179
+ this.registeredTriggers.delete(id);
47
180
  }
48
- });
181
+ this.triggers.update((triggers) => triggers.filter((candidate) => candidate !== trigger));
182
+ if (!this.destroyRef.destroyed && this.trigger() === trigger) {
183
+ const next = this.registeredTriggers.entries().next().value;
184
+ if (this.triggerId() !== null) {
185
+ this.triggerId.set(next?.[0] ?? null);
186
+ }
187
+ this.trigger.set(next?.[1].element);
188
+ this.payload.set(next?.[1].payload());
189
+ // Intentionally do NOT close when the last trigger unregisters (unlike popover):
190
+ // a controlled / imperatively-opened dialog must survive its trigger unmounting.
191
+ }
192
+ };
193
+ }
194
+ /** Increments the nested-open counter and returns a release callback that decrements it. */
195
+ openNestedChild() {
196
+ this.nestedOpenCount.update((count) => count + 1);
197
+ return () => this.nestedOpenCount.update((count) => count - 1);
49
198
  }
50
- close(result) {
51
- // check if dialog is already in closing state to prevent double-closing
52
- if (this.state() === 'closed') {
199
+ syncTriggerId(triggerId) {
200
+ if (triggerId === null) {
201
+ // Controlled triggerId cleared: drop the active trigger so stale state doesn't linger.
202
+ this.trigger.set(undefined);
203
+ this.payload.set(undefined);
53
204
  return;
54
205
  }
55
- this._openSignal.set(false);
56
- if (this._previousTimeout) {
57
- clearTimeout(this._previousTimeout);
206
+ const trigger = this.registeredTriggers.get(triggerId);
207
+ if (trigger && trigger.element !== this.trigger()) {
208
+ this.trigger.set(trigger.element);
209
+ this.payload.set(trigger.payload());
210
+ }
211
+ }
212
+ emitOpenChange(open, reason, event) {
213
+ this.onOpenChange.emit({
214
+ open,
215
+ triggerId: this.triggerId(),
216
+ trigger: this.trigger(),
217
+ reason,
218
+ event
219
+ });
220
+ }
221
+ emitOpenChangeComplete(open) {
222
+ if (!this.destroyRef.destroyed) {
223
+ this.onOpenChangeComplete.emit(open);
58
224
  }
59
- const closeDelay = this.config.closeDelay ?? 100; // Default to 100ms if not specified
60
- // Actual closing happens after delay
61
- this._previousTimeout = setTimeout(() => {
62
- this.cdkRef.close(result ?? DISMISSED_VALUE);
63
- }, closeDelay);
64
225
  }
226
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
227
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxDialogRoot, isStandalone: true, selector: "[rdxDialogRoot]", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, triggerId: { classPropertyName: "triggerId", publicName: "triggerId", isSignal: true, isRequired: false, transformFunction: null }, defaultTriggerId: { classPropertyName: "defaultTriggerId", publicName: "defaultTriggerId", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, disablePointerDismissal: { classPropertyName: "disablePointerDismissal", publicName: "disablePointerDismissal", isSignal: true, isRequired: false, transformFunction: null }, handle: { classPropertyName: "handle", publicName: "handle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", triggerId: "triggerIdChange", onOpenChange: "onOpenChange", onOpenChangeComplete: "onOpenChangeComplete" }, providers: [provideRdxDialogRootContext(context)], exportAs: ["rdxDialogRoot"], ngImport: i0 }); }
228
+ }
229
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogRoot, decorators: [{
230
+ type: Directive,
231
+ args: [{
232
+ selector: '[rdxDialogRoot]',
233
+ exportAs: 'rdxDialogRoot',
234
+ providers: [provideRdxDialogRootContext(context)]
235
+ }]
236
+ }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], defaultOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultOpen", required: false }] }], triggerId: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerId", required: false }] }, { type: i0.Output, args: ["triggerIdChange"] }], defaultTriggerId: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultTriggerId", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], disablePointerDismissal: [{ type: i0.Input, args: [{ isSignal: true, alias: "disablePointerDismissal", required: false }] }], handle: [{ type: i0.Input, args: [{ isSignal: true, alias: "handle", required: false }] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
237
+ function contextFor(root) {
238
+ return {
239
+ contentId: root.contentId,
240
+ titleId: root.titleId.asReadonly(),
241
+ descriptionId: root.descriptionId.asReadonly(),
242
+ isOpen: root.open,
243
+ modal: root.effectiveModal,
244
+ disablePointerDismissal: root.effectiveDisablePointerDismissal,
245
+ role: root.role,
246
+ transitionStatus: root.transitionStatus,
247
+ trigger: root.trigger.asReadonly(),
248
+ triggers: root.triggers.asReadonly(),
249
+ payload: root.payload.asReadonly(),
250
+ nested: root.nested,
251
+ nestedDialogOpen: root.nestedDialogOpen,
252
+ setTitleId: (id) => root.titleId.set(id),
253
+ setDescriptionId: (id) => root.descriptionId.set(id),
254
+ registerTransitionElement: (element) => root.registerTransitionElement(element),
255
+ registerTrigger: (id, trigger, payload) => root.registerTrigger(id, trigger, payload),
256
+ open: (trigger, payload, triggerId, reason, event) => root.show(trigger, payload, triggerId, reason, event),
257
+ close: (reason, event) => root.close(reason, event),
258
+ toggle: (triggerId, trigger, payload, event) => root.toggle(triggerId, trigger, payload, event)
259
+ };
65
260
  }
66
261
 
67
- class RdxDialogCloseDirective {
262
+ /**
263
+ * An overlay displayed beneath the dialog popup.
264
+ */
265
+ class RdxDialogBackdrop {
68
266
  constructor() {
69
- this.ref = inject(RdxDialogRef);
267
+ this.rootContext = injectRdxDialogRootContext();
70
268
  }
71
- onClick() {
72
- this.ref.close();
73
- }
74
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogCloseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
75
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.3", type: RdxDialogCloseDirective, isStandalone: true, selector: "[rdxDialogClose]", host: { listeners: { "click": "onClick()" } }, ngImport: i0 }); }
269
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogBackdrop, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
270
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDialogBackdrop, isStandalone: true, selector: "[rdxDialogBackdrop]", host: { properties: { "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "attr.data-nested": "rootContext.nested ? \"\" : undefined", "attr.data-nested-dialog-open": "rootContext.nestedDialogOpen() ? \"\" : undefined" } }, exportAs: ["rdxDialogBackdrop"], ngImport: i0 }); }
76
271
  }
77
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogCloseDirective, decorators: [{
272
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogBackdrop, decorators: [{
78
273
  type: Directive,
79
274
  args: [{
80
- selector: '[rdxDialogClose]',
81
- standalone: true,
275
+ selector: '[rdxDialogBackdrop]',
276
+ exportAs: 'rdxDialogBackdrop',
82
277
  host: {
83
- '(click)': 'onClick()'
278
+ '[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
279
+ '[attr.data-ending-style]': 'rootContext.transitionStatus() === "ending" ? "" : undefined',
280
+ '[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
281
+ '[attr.data-starting-style]': 'rootContext.transitionStatus() === "starting" ? "" : undefined',
282
+ '[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"',
283
+ '[attr.data-nested]': 'rootContext.nested ? "" : undefined',
284
+ '[attr.data-nested-dialog-open]': 'rootContext.nestedDialogOpen() ? "" : undefined'
84
285
  }
85
286
  }]
86
287
  }] });
87
288
 
88
- const ɵdialogData = Symbol.for('rdxDialogData');
89
- const ɵdialogResult = Symbol.for('rdxDialogResult');
90
- function getState(open) {
91
- return open ? 'open' : 'closed';
92
- }
93
-
94
- class RdxDialogContentDirective {
289
+ /**
290
+ * A button that closes the dialog.
291
+ */
292
+ class RdxDialogClose {
95
293
  constructor() {
96
- this.dialogRef = inject(RdxDialogRef);
97
- this.destroyRef = inject(DestroyRef);
98
- this.isOpen = signal(true, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
99
- this.state = computed(() => getState(this.isOpen()), ...(ngDevMode ? [{ debugName: "state" }] : []));
100
- this.dialogRef.closed$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
101
- this.isOpen.set(false);
102
- });
103
- }
104
- /**
105
- * Closes the dialog with a specified result.
106
- *
107
- * @param result The result to be passed back when closing the dialog
108
- */
109
- close(result) {
110
- this.dialogRef.close(result);
111
- }
112
- /**
113
- * Dismisses the dialog without a result.
114
- */
115
- dismiss() {
116
- this.dialogRef.dismiss();
294
+ this.rootContext = injectRdxDialogRootContext();
117
295
  }
118
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
119
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.3", type: RdxDialogContentDirective, isStandalone: true, selector: "[rdxDialogContent]", host: { attributes: { "role": "dialog" }, properties: { "attr.aria-describedby": "\"true\"", "attr.aria-labelledby": "\"true\"", "attr.data-state": "state()" } }, ngImport: i0 }); }
296
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogClose, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
297
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDialogClose, isStandalone: true, selector: "button[rdxDialogClose]", host: { attributes: { "type": "button" }, listeners: { "click": "rootContext.close(\"close-press\", $event)" } }, exportAs: ["rdxDialogClose"], ngImport: i0 }); }
120
298
  }
121
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogContentDirective, decorators: [{
299
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogClose, decorators: [{
122
300
  type: Directive,
123
301
  args: [{
124
- selector: '[rdxDialogContent]',
125
- standalone: true,
302
+ selector: 'button[rdxDialogClose]',
303
+ exportAs: 'rdxDialogClose',
126
304
  host: {
127
- role: 'dialog',
128
- '[attr.aria-describedby]': '"true"',
129
- '[attr.aria-labelledby]': '"true"',
130
- '[attr.data-state]': 'state()'
305
+ type: 'button',
306
+ '(click)': 'rootContext.close("close-press", $event)'
131
307
  }
132
308
  }]
133
- }], ctorParameters: () => [] });
309
+ }] });
134
310
 
135
- class RdxDialogDescriptionDirective {
136
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogDescriptionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
137
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.3", type: RdxDialogDescriptionDirective, isStandalone: true, selector: "[rdxDialogDescription]", ngImport: i0 }); }
311
+ /**
312
+ * An accessible description for the dialog.
313
+ */
314
+ class RdxDialogDescription {
315
+ constructor() {
316
+ this.rootContext = injectRdxDialogRootContext();
317
+ this.id = injectId('rdx-dialog-description-');
318
+ this.rootContext.setDescriptionId(this.id);
319
+ inject(DestroyRef).onDestroy(() => this.rootContext.setDescriptionId(undefined));
320
+ }
321
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogDescription, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
322
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDialogDescription, isStandalone: true, selector: "[rdxDialogDescription]", host: { properties: { "id": "id" } }, exportAs: ["rdxDialogDescription"], ngImport: i0 }); }
138
323
  }
139
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogDescriptionDirective, decorators: [{
324
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogDescription, decorators: [{
140
325
  type: Directive,
141
326
  args: [{
142
327
  selector: '[rdxDialogDescription]',
143
- standalone: true
328
+ exportAs: 'rdxDialogDescription',
329
+ host: {
330
+ '[id]': 'id'
331
+ }
144
332
  }]
145
- }] });
333
+ }], ctorParameters: () => [] });
146
334
 
147
- class RdxDialogDismissDirective {
335
+ /**
336
+ * A container for the dialog contents.
337
+ */
338
+ class RdxDialogPopup {
148
339
  constructor() {
149
- this.ref = inject(RdxDialogRef);
340
+ this.rootContext = injectRdxDialogRootContext();
341
+ this.dismissableLayer = inject(RdxDismissableLayer);
342
+ this.focusScope = inject(RdxFocusScope);
343
+ this.dismissDetails = {
344
+ reason: 'none',
345
+ event: new Event('dialog.dismiss')
346
+ };
347
+ /**
348
+ * Event handler called when the escape key is down. Can be prevented.
349
+ */
350
+ this.escapeKeyDown = outputFromObservable(outputToObservable(this.dismissableLayer.escapeKeyDown));
351
+ /**
352
+ * Event handler called when a pointerdown event happens outside of the popup. Can be prevented.
353
+ */
354
+ this.pointerDownOutside = outputFromObservable(outputToObservable(this.dismissableLayer.pointerDownOutside));
355
+ /**
356
+ * Event handler called when focus moves outside of the popup. Can be prevented.
357
+ */
358
+ this.focusOutside = outputFromObservable(outputToObservable(this.dismissableLayer.focusOutside));
359
+ /**
360
+ * Event handler called when an interaction happens outside of the popup. Can be prevented.
361
+ */
362
+ this.interactOutside = outputFromObservable(outputToObservable(this.dismissableLayer.interactOutside));
363
+ /**
364
+ * Event handler called before focus moves into the popup. Can be prevented.
365
+ */
366
+ this.openAutoFocus = outputFromObservable(outputToObservable(this.focusScope.mountAutoFocus));
367
+ /**
368
+ * Event handler called before focus returns after the popup is removed. Can be prevented.
369
+ */
370
+ this.closeAutoFocus = outputFromObservable(outputToObservable(this.focusScope.unmountAutoFocus));
371
+ useScrollLock(computed(() => this.rootContext.modal() === true && this.rootContext.isOpen()));
372
+ const unregisterTransitionElement = this.rootContext.registerTransitionElement(inject(ElementRef).nativeElement);
373
+ inject(DestroyRef).onDestroy(unregisterTransitionElement);
374
+ this.dismissableLayer.pointerDownOutside.subscribe((event) => {
375
+ this.dismissDetails = { reason: 'outside-press', event };
376
+ // A pointerdown on the trigger is an "outside" press relative to the portaled popup.
377
+ // Let the trigger's own click toggle the dialog instead of dismissing here (which would
378
+ // close and then immediately reopen).
379
+ if (this.isEventOnTrigger(event)) {
380
+ event.preventDefault();
381
+ }
382
+ });
383
+ this.dismissableLayer.focusOutside.subscribe((event) => {
384
+ this.dismissDetails = { reason: 'focus-out', event };
385
+ if (this.isEventOnTrigger(event)) {
386
+ event.preventDefault();
387
+ }
388
+ });
389
+ this.dismissableLayer.escapeKeyDown.subscribe((event) => {
390
+ this.dismissDetails = { reason: 'escape-key', event };
391
+ });
392
+ this.dismissableLayer.dismiss.subscribe(() => {
393
+ const { reason, event } = this.dismissDetails;
394
+ this.dismissDetails = { reason: 'none', event: new Event('dialog.dismiss') };
395
+ // When pointer dismissal is disabled, keep the dialog open on outside interactions.
396
+ // Escape always closes (standard a11y behavior).
397
+ if ((reason === 'outside-press' || reason === 'focus-out') && this.rootContext.disablePointerDismissal()) {
398
+ return;
399
+ }
400
+ this.rootContext.close(reason, event);
401
+ });
150
402
  }
151
- onClick() {
152
- this.ref.dismiss();
403
+ isEventOnTrigger(event) {
404
+ const target = event.target;
405
+ return !!target && this.rootContext.triggers().some((trigger) => trigger.contains(target));
153
406
  }
154
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogDismissDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
155
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.3", type: RdxDialogDismissDirective, isStandalone: true, selector: "button[rdxDialogDismiss]", host: { attributes: { "type": "button" }, listeners: { "click": "onClick()" } }, ngImport: i0 }); }
407
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPopup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
408
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDialogPopup, isStandalone: true, selector: "[rdxDialogPopup]", outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside", focusOutside: "focusOutside", interactOutside: "interactOutside", openAutoFocus: "openAutoFocus", closeAutoFocus: "closeAutoFocus" }, host: { properties: { "attr.role": "rootContext.role", "attr.aria-modal": "rootContext.modal() === true ? \"true\" : undefined", "attr.aria-describedby": "rootContext.descriptionId()", "attr.aria-labelledby": "rootContext.titleId()", "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "attr.data-nested": "rootContext.nested ? \"\" : undefined", "attr.data-nested-dialog-open": "rootContext.nestedDialogOpen() ? \"\" : undefined", "id": "rootContext.contentId" } }, providers: [
409
+ provideRdxDismissableLayerConfig(() => {
410
+ const rootContext = injectRdxDialogRootContext();
411
+ return {
412
+ disableOutsidePointerEvents: computed(() => rootContext.modal() === true)
413
+ };
414
+ }),
415
+ provideRdxFocusScopeConfig(() => {
416
+ const rootContext = injectRdxDialogRootContext();
417
+ return {
418
+ trapped: computed(() => rootContext.modal() === 'trap-focus' || rootContext.modal() === true)
419
+ };
420
+ })
421
+ ], exportAs: ["rdxDialogPopup"], hostDirectives: [{ directive: i1.RdxDismissableLayer }, { directive: i2.RdxFocusScope }], ngImport: i0 }); }
156
422
  }
157
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogDismissDirective, decorators: [{
423
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPopup, decorators: [{
158
424
  type: Directive,
159
425
  args: [{
160
- selector: 'button[rdxDialogDismiss]',
161
- standalone: true,
426
+ selector: '[rdxDialogPopup]',
427
+ exportAs: 'rdxDialogPopup',
428
+ hostDirectives: [RdxDismissableLayer, RdxFocusScope],
429
+ providers: [
430
+ provideRdxDismissableLayerConfig(() => {
431
+ const rootContext = injectRdxDialogRootContext();
432
+ return {
433
+ disableOutsidePointerEvents: computed(() => rootContext.modal() === true)
434
+ };
435
+ }),
436
+ provideRdxFocusScopeConfig(() => {
437
+ const rootContext = injectRdxDialogRootContext();
438
+ return {
439
+ trapped: computed(() => rootContext.modal() === 'trap-focus' || rootContext.modal() === true)
440
+ };
441
+ })
442
+ ],
162
443
  host: {
163
- type: 'button',
164
- '(click)': 'onClick()'
444
+ '[attr.role]': 'rootContext.role',
445
+ '[attr.aria-modal]': 'rootContext.modal() === true ? "true" : undefined',
446
+ '[attr.aria-describedby]': 'rootContext.descriptionId()',
447
+ '[attr.aria-labelledby]': 'rootContext.titleId()',
448
+ '[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
449
+ '[attr.data-ending-style]': 'rootContext.transitionStatus() === "ending" ? "" : undefined',
450
+ '[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
451
+ '[attr.data-starting-style]': 'rootContext.transitionStatus() === "starting" ? "" : undefined',
452
+ '[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"',
453
+ '[attr.data-nested]': 'rootContext.nested ? "" : undefined',
454
+ '[attr.data-nested-dialog-open]': 'rootContext.nestedDialogOpen() ? "" : undefined',
455
+ '[id]': 'rootContext.contentId'
165
456
  }
166
457
  }]
167
- }] });
458
+ }], 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"] }], openAutoFocus: [{ type: i0.Output, args: ["openAutoFocus"] }], closeAutoFocus: [{ type: i0.Output, args: ["closeAutoFocus"] }] } });
168
459
 
169
- class RdxDialogTitleDirective {
170
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogTitleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
171
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.3", type: RdxDialogTitleDirective, isStandalone: true, selector: "[rdxDialogTitle]", ngImport: i0 }); }
460
+ /**
461
+ * Moves the dialog to a different part of the DOM.
462
+ */
463
+ class RdxDialogPortal {
464
+ constructor() {
465
+ this.rootContext = injectRdxDialogRootContext();
466
+ /**
467
+ * Optional container to portal the content into. Defaults to `document.body`.
468
+ */
469
+ this.container = input(...(ngDevMode ? [undefined, { debugName: "container" }] : /* istanbul ignore next */ []));
470
+ }
471
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPortal, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
472
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxDialogPortal, isStandalone: true, selector: "[rdxDialogPortal]", inputs: { container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"" } }, exportAs: ["rdxDialogPortal"], hostDirectives: [{ directive: i1$1.RdxPortal, inputs: ["container", "container"] }], ngImport: i0 }); }
172
473
  }
173
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogTitleDirective, decorators: [{
474
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPortal, decorators: [{
174
475
  type: Directive,
175
476
  args: [{
176
- selector: '[rdxDialogTitle]',
177
- standalone: true
477
+ selector: '[rdxDialogPortal]',
478
+ exportAs: 'rdxDialogPortal',
479
+ hostDirectives: [
480
+ {
481
+ directive: RdxPortal,
482
+ inputs: ['container']
483
+ }
484
+ ],
485
+ host: {
486
+ '[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
487
+ '[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
488
+ '[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"'
489
+ }
178
490
  }]
179
- }] });
491
+ }], propDecorators: { container: [{ type: i0.Input, args: [{ isSignal: true, alias: "container", required: false }] }] } });
180
492
 
181
493
  /**
182
- * Modality control: When `isModal` is set to `true`, the dialog will:
183
- *
184
- * - Have a backdrop that blocks interaction with the rest of the page
185
- * - Disable closing by clicking outside or pressing Escape
186
- * - Set `aria-modal="true"` for screen readers
187
- * - Automatically focus the first tabbable element in the dialog
188
- * - Restore focus to the element that opened the dialog when it's closed
189
- *
190
- *
191
- * When `isModal` is `false`, the dialog will:
192
- *
193
- * - Not have a backdrop, allowing interaction with the rest of the page
194
- * - Allow closing by clicking outside or pressing Escape
195
- * - Not set `aria-modal` attribute
196
- * - Not automatically manage focus
494
+ * Mounts the portal while the dialog is open and waits for CSS exit keyframes before unmounting.
197
495
  */
198
- class RdxDialogService {
199
- #cdkDialog = inject(Dialog);
200
- #injector = inject(Injector);
201
- #rendererFactory = inject(RendererFactory2);
202
- #renderer = this.#rendererFactory.createRenderer(null, null);
203
- open(config) {
204
- let dialogRef;
205
- let modeClasses = [];
206
- switch (config.mode) {
207
- case 'sheet':
208
- modeClasses = ['mod-sheet', 'mod-right'];
209
- break;
210
- case 'sheet-right':
211
- modeClasses = ['mod-sheet', 'mod-right'];
212
- break;
213
- case 'sheet-bottom':
214
- modeClasses = ['mod-sheet', 'mod-bottom'];
215
- break;
216
- case 'sheet-left':
217
- modeClasses = ['mod-sheet', 'mod-left'];
218
- break;
219
- case 'sheet-top':
220
- modeClasses = ['mod-sheet', 'mod-top'];
221
- break;
222
- }
223
- // Create a new configuration with default closeDelay if not provided
224
- const extendedConfig = {
225
- ...config,
226
- closeDelay: config.closeDelay ?? 0
227
- };
228
- const cdkRef = this.#cdkDialog.open(config.content, {
229
- ariaModal: config.modal ?? true,
230
- hasBackdrop: config.modal ?? true,
231
- data: 'data' in config ? config.data : null,
232
- restoreFocus: true,
233
- role: config.isAlert ? 'alertdialog' : 'dialog',
234
- disableClose: true,
235
- closeOnDestroy: true,
236
- injector: this.#injector,
237
- backdropClass: config.backdropClass ? config.backdropClass : 'cdk-overlay-dark-backdrop',
238
- panelClass: ['dialog', ...modeClasses, ...(config.panelClasses || [])],
239
- autoFocus: config.autoFocus === 'first-input' ? 'dialog' : (config.autoFocus ?? 'first-tabbable'),
240
- ariaLabel: config.ariaLabel,
241
- templateContext: () => ({ dialogRef: dialogRef }),
242
- providers: (ref) => {
243
- // Create dialog ref with state tracking
244
- dialogRef = new RdxDialogRef(ref, extendedConfig);
245
- // Get overlay and backdrop references
246
- const overlay = ref.overlayRef.overlayElement;
247
- const backdrop = ref.overlayRef.backdropElement;
248
- // Set up effect to track and update state attributes
249
- runInInjectionContext(this.#injector, () => {
250
- effect(() => {
251
- const currentState = dialogRef.state();
252
- if (overlay) {
253
- this.#renderer.setAttribute(overlay, 'data-state', currentState);
254
- }
255
- if (backdrop) {
256
- this.#renderer.setAttribute(backdrop, 'data-state', currentState);
257
- }
258
- // For sheet dialogs, add data-side attribute
259
- if (config.mode?.startsWith('sheet-')) {
260
- const side = config.mode.substring(6);
261
- if (overlay) {
262
- this.#renderer.setAttribute(overlay, 'data-side', side);
263
- }
264
- if (backdrop) {
265
- this.#renderer.setAttribute(backdrop, 'data-side', side);
266
- }
267
- }
268
- });
269
- });
270
- return [
271
- {
272
- provide: RdxDialogRef,
273
- useValue: dialogRef
274
- }
275
- ];
276
- },
277
- // @FIXME
278
- ...(config.cdkConfigOverride || {})
279
- });
280
- if (cdkRef.componentRef) {
281
- cdkRef.componentRef.injector
282
- .get(Renderer2)
283
- .setStyle(cdkRef.componentRef.location.nativeElement, 'display', 'contents');
284
- }
285
- if (!config.isAlert) {
286
- merge(cdkRef.backdropClick, cdkRef.keydownEvents.pipe(filter((e) => e.key === 'Escape' && !e.defaultPrevented)))
287
- .pipe(filter(() => config.canCloseWithBackdrop ?? true), switchMap(() => {
288
- const canClose = (cdkRef.componentInstance && config.canClose?.(cdkRef.componentInstance)) ?? true;
289
- const canClose$ = isObservable(canClose) ? canClose : of(canClose);
290
- return canClose$.pipe(take(1));
291
- }), takeUntil(dialogRef.closed$))
292
- .subscribe((canClose) => {
293
- if (canClose) {
294
- // rather than `cdkRef.close()`, closing the `dialogRef` directly
295
- // ensures that the `state` is represented correctly
296
- dialogRef.close(undefined);
297
- }
298
- });
299
- }
300
- return dialogRef;
301
- }
302
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
303
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogService }); }
496
+ class RdxDialogPortalPresence {
497
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPortalPresence, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
498
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDialogPortalPresence, isStandalone: true, selector: "ng-template[rdxDialogPortalPresence]", providers: [
499
+ provideRdxPresenceContext(() => {
500
+ const context = injectRdxDialogRootContext();
501
+ return { present: context.isOpen };
502
+ })
503
+ ], hostDirectives: [{ directive: i1$2.RdxPresenceDirective }], ngImport: i0 }); }
304
504
  }
305
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogService, decorators: [{
306
- type: Injectable
505
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPortalPresence, decorators: [{
506
+ type: Directive,
507
+ args: [{
508
+ selector: 'ng-template[rdxDialogPortalPresence]',
509
+ hostDirectives: [RdxPresenceDirective],
510
+ providers: [
511
+ provideRdxPresenceContext(() => {
512
+ const context = injectRdxDialogRootContext();
513
+ return { present: context.isOpen };
514
+ })
515
+ ]
516
+ }]
307
517
  }] });
308
518
 
309
519
  /**
310
- * Configures the RdxDialog module by providing necessary dependencies.
311
- *
312
- * This function sets up the environment providers required for the RdxDialog to function,
313
- * specifically importing the Angular CDK's DialogModule.
314
- *
315
- * @returns {EnvironmentProviders} An EnvironmentProviders instance containing the DialogModule.
316
- */
317
- function provideRdxDialogConfig() {
318
- return makeEnvironmentProviders([importProvidersFrom(DialogModule)]);
319
- }
320
- /**
321
- * Provides the RdxDialogService for dependency injection.
322
- *
323
- * This function is used to make the RdxDialogService available for injection
324
- * in components, directives, or other services that require dialog functionality.
325
- *
326
- * @returns {Provider} A provider for the RdxDialogService.
520
+ * An accessible title for the dialog.
327
521
  */
328
- function provideRdxDialog() {
329
- return RdxDialogService;
522
+ class RdxDialogTitle {
523
+ constructor() {
524
+ this.rootContext = injectRdxDialogRootContext();
525
+ this.id = injectId('rdx-dialog-title-');
526
+ this.rootContext.setTitleId(this.id);
527
+ inject(DestroyRef).onDestroy(() => this.rootContext.setTitleId(undefined));
528
+ }
529
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogTitle, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
530
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDialogTitle, isStandalone: true, selector: "[rdxDialogTitle]", host: { properties: { "id": "id" } }, exportAs: ["rdxDialogTitle"], ngImport: i0 }); }
330
531
  }
532
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogTitle, decorators: [{
533
+ type: Directive,
534
+ args: [{
535
+ selector: '[rdxDialogTitle]',
536
+ exportAs: 'rdxDialogTitle',
537
+ host: {
538
+ '[id]': 'id'
539
+ }
540
+ }]
541
+ }], ctorParameters: () => [] });
331
542
 
332
- let nextId = 0;
333
543
  /**
334
- * @group Components
544
+ * A button that opens the dialog.
335
545
  */
336
- class RdxDialogTriggerDirective {
546
+ class RdxDialogTrigger {
337
547
  constructor() {
338
- this.dialogService = inject(RdxDialogService);
548
+ this.parentRootContext = injectRdxDialogRootContext(true);
549
+ this.elementRef = inject(ElementRef);
339
550
  /**
340
- * @group Props
551
+ * Associates this trigger with a detached dialog root.
341
552
  */
342
- this.id = input(`rdx-dialog-trigger-${nextId++}`, ...(ngDevMode ? [{ debugName: "id" }] : []));
343
- this.dialogId = computed(() => `rdx-dialog-${this.id()}`, ...(ngDevMode ? [{ debugName: "dialogId" }] : []));
344
- this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
345
- this.state = computed(() => getState(this.isOpen()), ...(ngDevMode ? [{ debugName: "state" }] : []));
346
- this.currentDialogRef = null;
347
- }
348
- onClick() {
349
- this.currentDialogRef = this.dialogService.open({
350
- ...this.dialogConfig,
351
- content: this.dialog
352
- });
353
- this.isOpen.set(true);
354
- this.currentDialogRef.closed$.subscribe(() => {
355
- this.isOpen.set(false);
356
- this.currentDialogRef = null;
553
+ this.handle = input(...(ngDevMode ? [undefined, { debugName: "handle" }] : /* istanbul ignore next */ []));
554
+ /**
555
+ * Data associated with this trigger while it is active.
556
+ */
557
+ this.payload = input(...(ngDevMode ? [undefined, { debugName: "payload" }] : /* istanbul ignore next */ []));
558
+ /**
559
+ * ID used to identify this trigger when opening a detached or controlled dialog.
560
+ */
561
+ this.id = input(...(ngDevMode ? [undefined, { debugName: "id" }] : /* istanbul ignore next */ []));
562
+ /**
563
+ * Whether the trigger should ignore user interaction.
564
+ */
565
+ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
566
+ this.generatedId = injectId('rdx-dialog-trigger-');
567
+ this.triggerId = computed(() => this.id() ?? this.generatedId, ...(ngDevMode ? [{ debugName: "triggerId" }] : /* istanbul ignore next */ []));
568
+ this.rootContext = computed(() => this.handle()?.context() ?? this.parentRootContext, ...(ngDevMode ? [{ debugName: "rootContext" }] : /* istanbul ignore next */ []));
569
+ this.isOpen = computed(() => this.rootContext()?.isOpen() === true && this.rootContext()?.trigger() === this.elementRef.nativeElement, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
570
+ effect((onCleanup) => {
571
+ const handle = this.handle();
572
+ if (handle) {
573
+ onCleanup(untracked(() => handle.registerTrigger(this.triggerId(), this.elementRef.nativeElement, () => this.payload())));
574
+ }
575
+ else if (this.parentRootContext) {
576
+ onCleanup(untracked(() => this.parentRootContext.registerTrigger(this.triggerId(), this.elementRef.nativeElement, () => this.payload())));
577
+ }
357
578
  });
358
579
  }
359
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
360
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.3", type: RdxDialogTriggerDirective, isStandalone: true, selector: "[rdxDialogTrigger]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, dialog: { classPropertyName: "dialog", publicName: "rdxDialogTrigger", isSignal: false, isRequired: true, transformFunction: null }, dialogConfig: { classPropertyName: "dialogConfig", publicName: "rdxDialogConfig", isSignal: false, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button" }, listeners: { "click": "onClick()" }, properties: { "attr.id": "id()", "attr.aria-haspopup": "\"dialog\"", "attr.aria-expanded": "isOpen()", "attr.aria-controls": "dialogId()", "attr.data-state": "state()" } }, providers: [provideRdxDialog()], ngImport: i0 }); }
580
+ handleClick(event) {
581
+ if (this.disabled()) {
582
+ return;
583
+ }
584
+ if (this.handle()) {
585
+ this.handle().toggle(this.triggerId(), event);
586
+ }
587
+ else {
588
+ this.parentRootContext?.toggle(this.triggerId(), this.elementRef.nativeElement, this.payload(), event);
589
+ }
590
+ }
591
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
592
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxDialogTrigger, isStandalone: true, selector: "button[rdxDialogTrigger]", inputs: { handle: { classPropertyName: "handle", publicName: "handle", isSignal: true, isRequired: false, transformFunction: null }, payload: { classPropertyName: "payload", publicName: "payload", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button" }, listeners: { "click": "handleClick($event)" }, properties: { "attr.aria-haspopup": "\"dialog\"", "attr.aria-controls": "rootContext()?.contentId", "attr.aria-expanded": "isOpen()", "attr.data-state": "isOpen() ? \"open\" : \"closed\"", "attr.data-popup-open": "isOpen() ? \"\" : undefined", "attr.disabled": "disabled() ? \"\" : undefined", "id": "triggerId()" } }, exportAs: ["rdxDialogTrigger"], ngImport: i0 }); }
361
593
  }
362
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogTriggerDirective, decorators: [{
594
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogTrigger, decorators: [{
363
595
  type: Directive,
364
596
  args: [{
365
- selector: '[rdxDialogTrigger]',
366
- standalone: true,
367
- providers: [provideRdxDialog()],
597
+ selector: 'button[rdxDialogTrigger]',
598
+ exportAs: 'rdxDialogTrigger',
368
599
  host: {
369
600
  type: 'button',
370
- '[attr.id]': 'id()',
371
601
  '[attr.aria-haspopup]': '"dialog"',
602
+ '[attr.aria-controls]': 'rootContext()?.contentId',
372
603
  '[attr.aria-expanded]': 'isOpen()',
373
- '[attr.aria-controls]': 'dialogId()',
374
- '[attr.data-state]': 'state()',
375
- '(click)': 'onClick()'
604
+ '[attr.data-state]': 'isOpen() ? "open" : "closed"',
605
+ '[attr.data-popup-open]': 'isOpen() ? "" : undefined',
606
+ '[attr.disabled]': 'disabled() ? "" : undefined',
607
+ '[id]': 'triggerId()',
608
+ '(click)': 'handleClick($event)'
609
+ }
610
+ }]
611
+ }], ctorParameters: () => [], propDecorators: { handle: [{ type: i0.Input, args: [{ isSignal: true, alias: "handle", required: false }] }], payload: [{ type: i0.Input, args: [{ isSignal: true, alias: "payload", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
612
+
613
+ /**
614
+ * A positioning container for the dialog popup that can be made scrollable.
615
+ *
616
+ * Place it inside the portal, around the popup, to scroll the popup when it is taller than the
617
+ * viewport (outside scroll). Pointer events pass through while the dialog is closed.
618
+ */
619
+ class RdxDialogViewport {
620
+ constructor() {
621
+ this.rootContext = injectRdxDialogRootContext();
622
+ }
623
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogViewport, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
624
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDialogViewport, isStandalone: true, selector: "[rdxDialogViewport]", host: { attributes: { "role": "presentation" }, properties: { "style.pointer-events": "rootContext.isOpen() ? null : \"none\"", "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "attr.data-nested": "rootContext.nested ? \"\" : undefined", "attr.data-nested-dialog-open": "rootContext.nestedDialogOpen() ? \"\" : undefined" } }, exportAs: ["rdxDialogViewport"], ngImport: i0 }); }
625
+ }
626
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogViewport, decorators: [{
627
+ type: Directive,
628
+ args: [{
629
+ selector: '[rdxDialogViewport]',
630
+ exportAs: 'rdxDialogViewport',
631
+ host: {
632
+ role: 'presentation',
633
+ '[style.pointer-events]': 'rootContext.isOpen() ? null : "none"',
634
+ '[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
635
+ '[attr.data-ending-style]': 'rootContext.transitionStatus() === "ending" ? "" : undefined',
636
+ '[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
637
+ '[attr.data-starting-style]': 'rootContext.transitionStatus() === "starting" ? "" : undefined',
638
+ '[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"',
639
+ '[attr.data-nested]': 'rootContext.nested ? "" : undefined',
640
+ '[attr.data-nested-dialog-open]': 'rootContext.nestedDialogOpen() ? "" : undefined'
376
641
  }
377
642
  }]
378
- }], propDecorators: { dialog: [{
379
- type: Input,
380
- args: [{ required: true, alias: 'rdxDialogTrigger' }]
381
- }], dialogConfig: [{
382
- type: Input,
383
- args: [{ alias: 'rdxDialogConfig' }]
384
- }] } });
643
+ }] });
385
644
 
386
- function injectDialogData() {
387
- return inject(DIALOG_DATA);
645
+ /**
646
+ * Connects a dialog root with trigger elements rendered elsewhere in the DOM, and exposes
647
+ * imperative `open`/`close`/`toggle` methods.
648
+ */
649
+ class RdxDialogHandle {
650
+ constructor() {
651
+ this.rootContext = signal(undefined, ...(ngDevMode ? [{ debugName: "rootContext" }] : /* istanbul ignore next */ []));
652
+ this.triggers = new Map();
653
+ this.rootTriggerCleanups = new Map();
654
+ this.isOpen = computed(() => this.rootContext()?.isOpen() ?? false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
655
+ }
656
+ open(triggerId) {
657
+ const trigger = this.triggers.get(triggerId);
658
+ if (!trigger) {
659
+ throw new Error(`No dialog trigger registered with id "${triggerId}".`);
660
+ }
661
+ this.rootContext()?.open(trigger.element, trigger.payload(), triggerId, 'imperative-action', new Event('dialog.open'));
662
+ }
663
+ close() {
664
+ this.rootContext()?.close('imperative-action', new Event('dialog.close'));
665
+ }
666
+ toggle(triggerId, event = new Event('dialog.toggle')) {
667
+ const trigger = this.triggers.get(triggerId);
668
+ if (!trigger) {
669
+ throw new Error(`No dialog trigger registered with id "${triggerId}".`);
670
+ }
671
+ this.rootContext()?.toggle(triggerId, trigger.element, trigger.payload(), event);
672
+ }
673
+ registerRoot(rootContext) {
674
+ this.rootContext.set(rootContext);
675
+ this.triggers.forEach((trigger, id) => {
676
+ this.rootTriggerCleanups.set(id, rootContext.registerTrigger(id, trigger.element, trigger.payload));
677
+ });
678
+ return () => {
679
+ if (this.rootContext() === rootContext) {
680
+ this.rootTriggerCleanups.forEach((cleanup) => cleanup());
681
+ this.rootTriggerCleanups.clear();
682
+ this.rootContext.set(undefined);
683
+ }
684
+ };
685
+ }
686
+ registerTrigger(id, trigger, payload) {
687
+ this.rootTriggerCleanups.get(id)?.();
688
+ this.triggers.set(id, { element: trigger, payload });
689
+ const unregisterFromRoot = this.rootContext()?.registerTrigger(id, trigger, payload);
690
+ if (unregisterFromRoot) {
691
+ this.rootTriggerCleanups.set(id, unregisterFromRoot);
692
+ }
693
+ return () => {
694
+ this.rootTriggerCleanups.get(id)?.();
695
+ this.rootTriggerCleanups.delete(id);
696
+ if (this.triggers.get(id)?.element === trigger) {
697
+ this.triggers.delete(id);
698
+ }
699
+ };
700
+ }
701
+ context() {
702
+ return this.rootContext();
703
+ }
388
704
  }
389
- function injectDialogRef() {
390
- return inject(RdxDialogRef);
705
+ function createRdxDialogHandle() {
706
+ return new RdxDialogHandle();
391
707
  }
392
708
 
393
- const _imports = [
394
- RdxDialogTriggerDirective,
395
- RdxDialogContentDirective,
396
- RdxDialogTitleDirective,
397
- RdxDialogCloseDirective,
398
- RdxDialogDescriptionDirective,
399
- RdxDialogDismissDirective
709
+ const dialogImports = [
710
+ RdxDialogRoot,
711
+ RdxDialogTrigger,
712
+ RdxDialogPortalPresence,
713
+ RdxDialogPortal,
714
+ RdxDialogBackdrop,
715
+ RdxDialogViewport,
716
+ RdxDialogPopup,
717
+ RdxDialogTitle,
718
+ RdxDialogDescription,
719
+ RdxDialogClose
400
720
  ];
401
721
  class RdxDialogModule {
402
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
403
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogModule, imports: [RdxDialogTriggerDirective,
404
- RdxDialogContentDirective,
405
- RdxDialogTitleDirective,
406
- RdxDialogCloseDirective,
407
- RdxDialogDescriptionDirective,
408
- RdxDialogDismissDirective], exports: [RdxDialogTriggerDirective,
409
- RdxDialogContentDirective,
410
- RdxDialogTitleDirective,
411
- RdxDialogCloseDirective,
412
- RdxDialogDescriptionDirective,
413
- RdxDialogDismissDirective] }); }
414
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogModule }); }
722
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
723
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogModule, imports: [RdxDialogRoot,
724
+ RdxDialogTrigger,
725
+ RdxDialogPortalPresence,
726
+ RdxDialogPortal,
727
+ RdxDialogBackdrop,
728
+ RdxDialogViewport,
729
+ RdxDialogPopup,
730
+ RdxDialogTitle,
731
+ RdxDialogDescription,
732
+ RdxDialogClose], exports: [RdxDialogRoot,
733
+ RdxDialogTrigger,
734
+ RdxDialogPortalPresence,
735
+ RdxDialogPortal,
736
+ RdxDialogBackdrop,
737
+ RdxDialogViewport,
738
+ RdxDialogPopup,
739
+ RdxDialogTitle,
740
+ RdxDialogDescription,
741
+ RdxDialogClose] }); }
742
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogModule }); }
415
743
  }
416
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: RdxDialogModule, decorators: [{
744
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogModule, decorators: [{
417
745
  type: NgModule,
418
746
  args: [{
419
- imports: [..._imports],
420
- exports: [..._imports]
747
+ imports: [...dialogImports],
748
+ exports: [...dialogImports]
421
749
  }]
422
750
  }] });
423
751
 
@@ -425,5 +753,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImpor
425
753
  * Generated bundle index. Do not edit.
426
754
  */
427
755
 
428
- export { DISMISSED_VALUE, RdxDialogCloseDirective, RdxDialogContentDirective, RdxDialogDescriptionDirective, RdxDialogDismissDirective, RdxDialogModule, RdxDialogRef, RdxDialogService, RdxDialogTitleDirective, RdxDialogTriggerDirective, getState, injectDialogData, injectDialogRef, provideRdxDialog, provideRdxDialogConfig };
756
+ export { RDX_DIALOG_VARIANT, RdxDialogBackdrop, RdxDialogClose, RdxDialogDescription, RdxDialogHandle, RdxDialogModule, RdxDialogPopup, RdxDialogPortal, RdxDialogPortalPresence, RdxDialogRoot, RdxDialogTitle, RdxDialogTrigger, RdxDialogViewport, createRdxDialogHandle, dialogImports, injectRdxDialogRootContext, provideRdxDialogRootContext, provideRdxDialogVariant };
429
757
  //# sourceMappingURL=radix-ng-primitives-dialog.mjs.map