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

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 (186) hide show
  1. package/fesm2022/radix-ng-primitives-accordion.mjs +105 -38
  2. package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
  3. package/fesm2022/radix-ng-primitives-alert-dialog.mjs +221 -129
  4. package/fesm2022/radix-ng-primitives-alert-dialog.mjs.map +1 -1
  5. package/fesm2022/radix-ng-primitives-arrow.mjs +20 -4
  6. package/fesm2022/radix-ng-primitives-arrow.mjs.map +1 -1
  7. package/fesm2022/radix-ng-primitives-aspect-ratio.mjs.map +1 -1
  8. package/fesm2022/radix-ng-primitives-avatar.mjs +54 -61
  9. package/fesm2022/radix-ng-primitives-avatar.mjs.map +1 -1
  10. package/fesm2022/radix-ng-primitives-button.mjs +123 -0
  11. package/fesm2022/radix-ng-primitives-button.mjs.map +1 -0
  12. package/fesm2022/radix-ng-primitives-calendar.mjs +95 -83
  13. package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
  14. package/fesm2022/radix-ng-primitives-checkbox.mjs +378 -54
  15. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  16. package/fesm2022/radix-ng-primitives-collapsible.mjs +182 -81
  17. package/fesm2022/radix-ng-primitives-collapsible.mjs.map +1 -1
  18. package/fesm2022/radix-ng-primitives-collection.mjs +40 -57
  19. package/fesm2022/radix-ng-primitives-collection.mjs.map +1 -1
  20. package/fesm2022/radix-ng-primitives-config.mjs.map +1 -1
  21. package/fesm2022/radix-ng-primitives-context-menu.mjs +140 -424
  22. package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
  23. package/fesm2022/radix-ng-primitives-core.mjs +845 -744
  24. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  25. package/fesm2022/radix-ng-primitives-cropper.mjs +288 -308
  26. package/fesm2022/radix-ng-primitives-cropper.mjs.map +1 -1
  27. package/fesm2022/radix-ng-primitives-date-field.mjs +104 -58
  28. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  29. package/fesm2022/radix-ng-primitives-dialog.mjs +655 -327
  30. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  31. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs +70 -46
  32. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs.map +1 -1
  33. package/fesm2022/radix-ng-primitives-drawer.mjs +960 -0
  34. package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -0
  35. package/fesm2022/radix-ng-primitives-editable.mjs +304 -23
  36. package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
  37. package/fesm2022/radix-ng-primitives-field.mjs +363 -0
  38. package/fesm2022/radix-ng-primitives-field.mjs.map +1 -0
  39. package/fesm2022/radix-ng-primitives-fieldset.mjs +79 -0
  40. package/fesm2022/radix-ng-primitives-fieldset.mjs.map +1 -0
  41. package/fesm2022/radix-ng-primitives-focus-scope.mjs +23 -8
  42. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  43. package/fesm2022/radix-ng-primitives-input.mjs +172 -0
  44. package/fesm2022/radix-ng-primitives-input.mjs.map +1 -0
  45. package/fesm2022/radix-ng-primitives-label.mjs +6 -6
  46. package/fesm2022/radix-ng-primitives-label.mjs.map +1 -1
  47. package/fesm2022/radix-ng-primitives-menu.mjs +1907 -363
  48. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  49. package/fesm2022/radix-ng-primitives-menubar.mjs +290 -162
  50. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  51. package/fesm2022/radix-ng-primitives-meter.mjs +271 -0
  52. package/fesm2022/radix-ng-primitives-meter.mjs.map +1 -0
  53. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +1052 -1553
  54. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  55. package/fesm2022/radix-ng-primitives-number-field.mjs +1102 -367
  56. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
  57. package/fesm2022/radix-ng-primitives-pagination.mjs.map +1 -1
  58. package/fesm2022/radix-ng-primitives-popover.mjs +978 -989
  59. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  60. package/fesm2022/radix-ng-primitives-popper.mjs +111 -44
  61. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  62. package/fesm2022/radix-ng-primitives-portal.mjs +34 -10
  63. package/fesm2022/radix-ng-primitives-portal.mjs.map +1 -1
  64. package/fesm2022/radix-ng-primitives-presence.mjs +134 -246
  65. package/fesm2022/radix-ng-primitives-presence.mjs.map +1 -1
  66. package/fesm2022/radix-ng-primitives-preview-card.mjs +997 -0
  67. package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -0
  68. package/fesm2022/radix-ng-primitives-progress.mjs +223 -84
  69. package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -1
  70. package/fesm2022/radix-ng-primitives-radio.mjs +191 -51
  71. package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
  72. package/fesm2022/radix-ng-primitives-roving-focus.mjs +96 -50
  73. package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
  74. package/fesm2022/radix-ng-primitives-scroll-area.mjs +923 -0
  75. package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -0
  76. package/fesm2022/radix-ng-primitives-select.mjs +791 -509
  77. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  78. package/fesm2022/radix-ng-primitives-separator.mjs +12 -35
  79. package/fesm2022/radix-ng-primitives-separator.mjs.map +1 -1
  80. package/fesm2022/radix-ng-primitives-slider.mjs +969 -717
  81. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  82. package/fesm2022/radix-ng-primitives-stepper.mjs +15 -19
  83. package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
  84. package/fesm2022/radix-ng-primitives-switch.mjs +125 -113
  85. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  86. package/fesm2022/radix-ng-primitives-tabs.mjs +390 -108
  87. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  88. package/fesm2022/radix-ng-primitives-time-field.mjs +55 -46
  89. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  90. package/fesm2022/radix-ng-primitives-toast.mjs +839 -0
  91. package/fesm2022/radix-ng-primitives-toast.mjs.map +1 -0
  92. package/fesm2022/radix-ng-primitives-toggle-group.mjs +121 -247
  93. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  94. package/fesm2022/radix-ng-primitives-toggle.mjs +98 -61
  95. package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
  96. package/fesm2022/radix-ng-primitives-toolbar.mjs +303 -92
  97. package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
  98. package/fesm2022/radix-ng-primitives-tooltip.mjs +699 -1072
  99. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  100. package/fesm2022/radix-ng-primitives-visually-hidden.mjs +25 -66
  101. package/fesm2022/radix-ng-primitives-visually-hidden.mjs.map +1 -1
  102. package/meter/README.md +3 -0
  103. package/navigation-menu/README.md +2 -1
  104. package/package.json +39 -18
  105. package/portal/README.md +2 -0
  106. package/preview-card/README.md +3 -0
  107. package/schematics/collection.json +1 -0
  108. package/schematics/ng-add/index.d.ts +3 -2
  109. package/schematics/ng-add/index.js +62 -31
  110. package/schematics/ng-add/index.js.map +1 -1
  111. package/schematics/ng-add/package-config.d.ts +4 -2
  112. package/schematics/ng-add/package-config.js +10 -2
  113. package/schematics/ng-add/package-config.js.map +1 -1
  114. package/schematics/ng-add/schema.d.ts +3 -0
  115. package/schematics/ng-add/schema.js +3 -0
  116. package/schematics/ng-add/schema.js.map +1 -0
  117. package/schematics/ng-add/schema.json +14 -0
  118. package/select/README.md +2 -0
  119. package/types/radix-ng-primitives-accordion.d.ts +51 -16
  120. package/types/radix-ng-primitives-alert-dialog.d.ts +95 -38
  121. package/types/radix-ng-primitives-arrow.d.ts +1 -1
  122. package/types/radix-ng-primitives-aspect-ratio.d.ts +1 -1
  123. package/types/radix-ng-primitives-avatar.d.ts +7 -11
  124. package/types/radix-ng-primitives-button.d.ts +73 -0
  125. package/types/radix-ng-primitives-calendar.d.ts +39 -20
  126. package/types/radix-ng-primitives-checkbox.d.ts +204 -35
  127. package/types/radix-ng-primitives-collapsible.d.ts +114 -40
  128. package/types/radix-ng-primitives-collection.d.ts +38 -34
  129. package/types/radix-ng-primitives-config.d.ts +1 -1
  130. package/types/radix-ng-primitives-context-menu.d.ts +61 -116
  131. package/types/radix-ng-primitives-core.d.ts +345 -235
  132. package/types/radix-ng-primitives-cropper.d.ts +89 -56
  133. package/types/radix-ng-primitives-date-field.d.ts +49 -28
  134. package/types/radix-ng-primitives-dialog.d.ts +283 -165
  135. package/types/radix-ng-primitives-dismissable-layer.d.ts +15 -7
  136. package/types/radix-ng-primitives-drawer.d.ts +426 -0
  137. package/types/radix-ng-primitives-editable.d.ts +91 -14
  138. package/types/radix-ng-primitives-field.d.ts +374 -0
  139. package/types/radix-ng-primitives-fieldset.d.ts +49 -0
  140. package/types/radix-ng-primitives-focus-scope.d.ts +15 -6
  141. package/types/radix-ng-primitives-input.d.ts +87 -0
  142. package/types/radix-ng-primitives-label.d.ts +0 -1
  143. package/types/radix-ng-primitives-menu.d.ts +584 -99
  144. package/types/radix-ng-primitives-menubar.d.ts +61 -50
  145. package/types/radix-ng-primitives-meter.d.ts +194 -0
  146. package/types/radix-ng-primitives-navigation-menu.d.ts +422 -340
  147. package/types/radix-ng-primitives-number-field.d.ts +405 -145
  148. package/types/radix-ng-primitives-pagination.d.ts +2 -2
  149. package/types/radix-ng-primitives-popover.d.ts +366 -351
  150. package/types/radix-ng-primitives-popper.d.ts +68 -11
  151. package/types/radix-ng-primitives-portal.d.ts +14 -6
  152. package/types/radix-ng-primitives-presence.d.ts +28 -76
  153. package/types/radix-ng-primitives-preview-card.d.ts +359 -0
  154. package/types/radix-ng-primitives-progress.d.ts +175 -48
  155. package/types/radix-ng-primitives-radio.d.ts +55 -25
  156. package/types/radix-ng-primitives-roving-focus.d.ts +33 -23
  157. package/types/radix-ng-primitives-scroll-area.d.ts +253 -0
  158. package/types/radix-ng-primitives-select.d.ts +475 -177
  159. package/types/radix-ng-primitives-separator.d.ts +7 -32
  160. package/types/radix-ng-primitives-slider.d.ts +315 -201
  161. package/types/radix-ng-primitives-stepper.d.ts +5 -7
  162. package/types/radix-ng-primitives-switch.d.ts +86 -71
  163. package/types/radix-ng-primitives-tabs.d.ts +213 -79
  164. package/types/radix-ng-primitives-time-field.d.ts +42 -27
  165. package/types/radix-ng-primitives-toast.d.ts +378 -0
  166. package/types/radix-ng-primitives-toggle-group.d.ts +86 -164
  167. package/types/radix-ng-primitives-toggle.d.ts +43 -53
  168. package/types/radix-ng-primitives-toolbar.d.ts +164 -38
  169. package/types/radix-ng-primitives-tooltip.d.ts +348 -384
  170. package/types/radix-ng-primitives-visually-hidden.d.ts +19 -19
  171. package/dropdown-menu/README.md +0 -1
  172. package/fesm2022/radix-ng-primitives-dropdown-menu.mjs +0 -581
  173. package/fesm2022/radix-ng-primitives-dropdown-menu.mjs.map +0 -1
  174. package/fesm2022/radix-ng-primitives-hover-card.mjs +0 -1238
  175. package/fesm2022/radix-ng-primitives-hover-card.mjs.map +0 -1
  176. package/fesm2022/radix-ng-primitives-select2.mjs +0 -897
  177. package/fesm2022/radix-ng-primitives-select2.mjs.map +0 -1
  178. package/fesm2022/radix-ng-primitives-tooltip2.mjs +0 -735
  179. package/fesm2022/radix-ng-primitives-tooltip2.mjs.map +0 -1
  180. package/hover-card/README.md +0 -3
  181. package/select2/README.md +0 -3
  182. package/tooltip2/README.md +0 -3
  183. package/types/radix-ng-primitives-dropdown-menu.d.ts +0 -171
  184. package/types/radix-ng-primitives-hover-card.d.ts +0 -471
  185. package/types/radix-ng-primitives-select2.d.ts +0 -511
  186. package/types/radix-ng-primitives-tooltip2.d.ts +0 -325
@@ -1,8 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
- import { forwardRef, input, booleanAttribute, output, linkedSignal, untracked, Directive, inject, ElementRef, NgZone, Input, DOCUMENT, DestroyRef, signal, afterNextRender, APP_ID, Injectable, InjectionToken, computed, effect } from '@angular/core';
3
- import { NG_VALUE_ACCESSOR, NgControl, FormControlDirective, FormControlName, NgModel } from '@angular/forms';
4
- import { Platform } from '@angular/cdk/platform';
2
+ import { forwardRef, input, booleanAttribute, output, linkedSignal, untracked, Directive, inject, InjectionToken, computed, APP_ID, Injectable, DOCUMENT, PLATFORM_ID, DestroyRef, signal, afterNextRender, effect, ElementRef, assertInInjectionContext, Injector } from '@angular/core';
3
+ import { NG_VALUE_ACCESSOR } from '@angular/forms';
5
4
  import { getLocalTimeZone, CalendarDateTime, ZonedDateTime, getDayOfWeek, DateFormatter, createCalendar, toCalendar, CalendarDate, Time, startOfMonth, endOfMonth, today } from '@internationalized/date';
5
+ import { isPlatformBrowser, DOCUMENT as DOCUMENT$1 } from '@angular/common';
6
6
 
7
7
  /**
8
8
  * Include in the providers section of a component which utilizes ControlValueAccessor to redundant code.
@@ -111,84 +111,6 @@ function injectControlValueAccessor() {
111
111
  return inject(RdxControlValueAccessor);
112
112
  }
113
113
 
114
- /*
115
- * <div [rdxAutoFocus]="true"></div>
116
- */
117
- class RdxAutoFocusDirective {
118
- constructor() {
119
- this.#elementRef = inject(ElementRef);
120
- this.#ngZone = inject(NgZone);
121
- this._autoSelect = false;
122
- }
123
- #elementRef;
124
- #ngZone;
125
- /**
126
- * @default false
127
- */
128
- set autoFocus(value) {
129
- if (value) {
130
- // Note: Running this outside Angular's zone because `element.focus()` does not trigger change detection.
131
- this.#ngZone.runOutsideAngular(() =>
132
- // Note: `element.focus()` causes re-layout which might lead to frame drops on slower devices.
133
- // https://gist.github.com/paulirish/5d52fb081b3570c81e3a#setting-focus
134
- // `setTimeout` is a macrotask executed within the current rendering frame.
135
- // Animation tasks are executed in the next rendering frame.
136
- reqAnimationFrame(() => {
137
- this.#elementRef.nativeElement.focus();
138
- if (this._autoSelect && this.#elementRef.nativeElement.select) {
139
- this.#elementRef.nativeElement.select();
140
- }
141
- }));
142
- }
143
- }
144
- // Setter for autoSelect attribute to enable text selection when autoFocus is true.
145
- set autoSelect(value) {
146
- this._autoSelect = value;
147
- }
148
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxAutoFocusDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
149
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.9", type: RdxAutoFocusDirective, isStandalone: true, selector: "[rdxAutoFocus]", inputs: { autoFocus: ["rdxAutoFocus", "autoFocus", booleanAttribute], autoSelect: ["autoSelect", "autoSelect", booleanAttribute] }, ngImport: i0 }); }
150
- }
151
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxAutoFocusDirective, decorators: [{
152
- type: Directive,
153
- args: [{
154
- selector: '[rdxAutoFocus]',
155
- standalone: true
156
- }]
157
- }], propDecorators: { autoFocus: [{
158
- type: Input,
159
- args: [{ alias: 'rdxAutoFocus', transform: booleanAttribute }]
160
- }], autoSelect: [{
161
- type: Input,
162
- args: [{ transform: booleanAttribute }]
163
- }] } });
164
- const availablePrefixes = ['moz', 'ms', 'webkit'];
165
- function requestAnimationFramePolyfill() {
166
- let lastTime = 0;
167
- return function (callback) {
168
- const currTime = new Date().getTime();
169
- const timeToCall = Math.max(0, 16 - (currTime - lastTime));
170
- const id = setTimeout(() => {
171
- callback(currTime + timeToCall);
172
- }, timeToCall);
173
- lastTime = currTime + timeToCall;
174
- return id;
175
- };
176
- }
177
- // Function to get the appropriate requestAnimationFrame method with fallback to polyfill.
178
- function getRequestAnimationFrame() {
179
- if (typeof window === 'undefined') {
180
- return () => 0;
181
- }
182
- if (window.requestAnimationFrame) {
183
- // https://github.com/vuejs/vue/issues/4465
184
- return window.requestAnimationFrame.bind(window);
185
- }
186
- const prefix = availablePrefixes.filter((key) => `${key}RequestAnimationFrame` in window)[0];
187
- return prefix ? window[`${prefix}RequestAnimationFrame`] : requestAnimationFramePolyfill();
188
- }
189
- // Get the requestAnimationFrame function or its polyfill.
190
- const reqAnimationFrame = getRequestAnimationFrame();
191
-
192
114
  /**
193
115
  * The `clamp` function restricts a number within a specified range by returning the value itself if it
194
116
  * falls within the range, or the closest boundary value if it exceeds the range.
@@ -259,444 +181,6 @@ function snapValueToStep(value, min, max, step) {
259
181
  return snappedValue;
260
182
  }
261
183
 
262
- function injectDocument() {
263
- return inject(DOCUMENT);
264
- }
265
-
266
- function elementSize({ elementRef, injector }) {
267
- const destroyRef = injector.get(DestroyRef);
268
- const result = signal({
269
- width: elementRef.nativeElement.offsetWidth,
270
- height: elementRef.nativeElement.offsetHeight
271
- }, ...(ngDevMode ? [{ debugName: "result" }] : /* istanbul ignore next */ []));
272
- afterNextRender(() => {
273
- const resizeObserver = new ResizeObserver((entries) => {
274
- const entry = entries[0];
275
- let width;
276
- let height;
277
- if ('borderBoxSize' in entry) {
278
- const borderSizeEntry = entry['borderBoxSize'];
279
- const borderSize = Array.isArray(borderSizeEntry) ? borderSizeEntry[0] : borderSizeEntry;
280
- width = borderSize['inlineSize'];
281
- height = borderSize['blockSize'];
282
- }
283
- else {
284
- width = elementRef.nativeElement.offsetWidth;
285
- height = elementRef.nativeElement.offsetHeight;
286
- }
287
- result.set({ width, height });
288
- });
289
- destroyRef.onDestroy(() => resizeObserver.disconnect());
290
- }, { injector: injector });
291
- return result.asReadonly();
292
- }
293
-
294
- class RdxFocusInitialDirective {
295
- constructor() {
296
- /** @ignore */
297
- this.nativeElement = inject(ElementRef).nativeElement;
298
- }
299
- /** @ignore */
300
- focus() {
301
- this.nativeElement.focus();
302
- }
303
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxFocusInitialDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
304
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxFocusInitialDirective, isStandalone: true, selector: "[rdxFocusInitial]", ngImport: i0 }); }
305
- }
306
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxFocusInitialDirective, decorators: [{
307
- type: Directive,
308
- args: [{
309
- selector: '[rdxFocusInitial]'
310
- }]
311
- }] });
312
-
313
- function getActiveElement() {
314
- let activeElement = document.activeElement;
315
- if (activeElement == null) {
316
- return null;
317
- }
318
- while (activeElement != null &&
319
- activeElement.shadowRoot != null &&
320
- activeElement.shadowRoot.activeElement != null) {
321
- activeElement = activeElement.shadowRoot.activeElement;
322
- }
323
- return activeElement;
324
- }
325
-
326
- /**
327
- * @license
328
- * Copyright Google LLC All Rights Reserved.
329
- *
330
- * Use of this source code is governed by an MIT-style license that can be
331
- * found in the LICENSE file at https://angular.dev/license
332
- */
333
- /**
334
- * Keeps track of the ID count per prefix. This helps us make the IDs a bit more deterministic
335
- * like they were before the service was introduced. Note that ideally we wouldn't have to do
336
- * this, but there are some internal tests that rely on the IDs.
337
- */
338
- const counters = {};
339
- /** Service that generates unique IDs for DOM nodes. */
340
- class _IdGenerator {
341
- constructor() {
342
- this._appId = inject(APP_ID);
343
- }
344
- /**
345
- * Generates a unique ID with a specific prefix.
346
- * @param prefix Prefix to add to the ID.
347
- */
348
- getId(prefix) {
349
- // Omit the app ID if it's the default `ng`. Since the vast majority of pages have one
350
- // Angular app on them, we can reduce the amount of breakages by not adding it.
351
- if (this._appId !== 'ng') {
352
- prefix += this._appId;
353
- }
354
- if (!Object.prototype.hasOwnProperty.call(counters, prefix)) {
355
- counters[prefix] = 0;
356
- }
357
- return `${prefix}${counters[prefix]++}`;
358
- }
359
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: _IdGenerator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
360
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: _IdGenerator, providedIn: 'root' }); }
361
- }
362
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: _IdGenerator, decorators: [{
363
- type: Injectable,
364
- args: [{ providedIn: 'root' }]
365
- }] });
366
-
367
- function injectNgControl(params) {
368
- const ngControl = inject(NgControl, { self: true, optional: true });
369
- if (!params?.optional && !ngControl)
370
- throw new Error('NgControl not found');
371
- if (ngControl instanceof FormControlDirective ||
372
- ngControl instanceof FormControlName ||
373
- ngControl instanceof NgModel) {
374
- return ngControl;
375
- }
376
- if (params?.optional) {
377
- return undefined;
378
- }
379
- throw new Error('NgControl is not an instance of FormControlDirective, FormControlName or NgModel');
380
- }
381
-
382
- function injectIsClient() {
383
- return inject(Platform).isBrowser;
384
- }
385
-
386
- // Originally based on https://github.com/puleos/object-hash v3.0.0 (MIT)
387
- /**
388
- * Serializes any input value into a string for hashing.
389
- *
390
- * This method uses best efforts to generate stable serialized values.
391
- * However, it is not designed for security purposes.
392
- * Keep in mind that there is always a chance of intentional collisions caused by user input.
393
- *
394
- * @param input any value to serialize
395
- * @return {string} serialized string value
396
- */
397
- function serialize(input) {
398
- if (typeof input === 'string') {
399
- return `'${input}'`;
400
- }
401
- return new Serializer().serialize(input);
402
- }
403
- const Serializer = /*@__PURE__*/ (function () {
404
- class Serializer {
405
- #context = new Map();
406
- compare(a, b) {
407
- const typeA = typeof a;
408
- const typeB = typeof b;
409
- if (typeA === 'string' && typeB === 'string') {
410
- return a.localeCompare(b);
411
- }
412
- if (typeA === 'number' && typeB === 'number') {
413
- return a - b;
414
- }
415
- return String.prototype.localeCompare.call(this.serialize(a, true), this.serialize(b, true));
416
- }
417
- serialize(value, noQuotes) {
418
- if (value === null) {
419
- return 'null';
420
- }
421
- switch (typeof value) {
422
- case 'string': {
423
- return noQuotes ? value : `'${value}'`;
424
- }
425
- case 'bigint': {
426
- return `${value}n`;
427
- }
428
- case 'object': {
429
- return this.$object(value);
430
- }
431
- case 'function': {
432
- return this.$function(value);
433
- }
434
- }
435
- return String(value);
436
- }
437
- serializeObject(object) {
438
- const objString = Object.prototype.toString.call(object);
439
- if (objString !== '[object Object]') {
440
- return this.serializeBuiltInType(objString.length < 10 /* '[object a]'.length === 10, the minimum */
441
- ? `unknown:${objString}`
442
- : objString.slice(8, -1) /* '[object '.length === 8 */, object);
443
- }
444
- const constructor = object.constructor;
445
- const objName = constructor === Object || constructor === undefined ? '' : constructor.name;
446
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
447
- // @ts-expect-error
448
- if (objName !== '' && globalThis[objName] === constructor) {
449
- return this.serializeBuiltInType(objName, object);
450
- }
451
- if ('toJSON' in object && typeof object.toJSON === 'function') {
452
- const json = object.toJSON();
453
- return (objName +
454
- (json !== null && typeof json === 'object' ? this.$object(json) : `(${this.serialize(json)})`));
455
- }
456
- const keys = Object.keys(object).sort((a, b) => a.localeCompare(b));
457
- let content = `${objName}{`;
458
- for (let i = 0; i < keys.length; i++) {
459
- const key = keys[i];
460
- content += `${key}:${this.serialize(object[key])}`;
461
- if (i < keys.length - 1) {
462
- content += ',';
463
- }
464
- }
465
- return content + '}';
466
- }
467
- serializeBuiltInType(type, object) {
468
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
469
- // @ts-expect-error
470
- const handler = this['$' + type];
471
- if (handler) {
472
- return handler.call(this, object);
473
- }
474
- if (typeof object.entries === 'function') {
475
- return this.serializeObjectEntries(type, object.entries());
476
- }
477
- throw new Error(`Cannot serialize ${type}`);
478
- }
479
- serializeObjectEntries(type, entries) {
480
- const sortedEntries = Array.from(entries).sort((a, b) => this.compare(a[0], b[0]));
481
- let content = `${type}{`;
482
- for (let i = 0; i < sortedEntries.length; i++) {
483
- const [key, value] = sortedEntries[i];
484
- content += `${this.serialize(key, true)}:${this.serialize(value)}`;
485
- if (i < sortedEntries.length - 1) {
486
- content += ',';
487
- }
488
- }
489
- return content + '}';
490
- }
491
- $object(object) {
492
- let content = this.#context.get(object);
493
- if (content === undefined) {
494
- this.#context.set(object, `#${this.#context.size}`);
495
- content = this.serializeObject(object);
496
- this.#context.set(object, content);
497
- }
498
- return content;
499
- }
500
- $function(fn) {
501
- const fnStr = Function.prototype.toString.call(fn);
502
- if (fnStr.slice(-15 /* "[native code] }".length */) === '[native code] }') {
503
- return `${fn.name || ''}()[native]`;
504
- }
505
- return `${fn.name}(${fn.length})${fnStr.replace(/\s*\n\s*/g, '')}`;
506
- }
507
- $Array(arr) {
508
- let content = '[';
509
- for (let i = 0; i < arr.length; i++) {
510
- content += this.serialize(arr[i]);
511
- if (i < arr.length - 1) {
512
- content += ',';
513
- }
514
- }
515
- return content + ']';
516
- }
517
- $Date(date) {
518
- try {
519
- return `Date(${date.toISOString()})`;
520
- }
521
- catch {
522
- return `Date(null)`;
523
- }
524
- }
525
- $ArrayBuffer(arr) {
526
- return `ArrayBuffer[${new Uint8Array(arr).join(',')}]`;
527
- }
528
- $Set(set) {
529
- return `Set${this.$Array(Array.from(set).sort((a, b) => this.compare(a, b)))}`;
530
- }
531
- $Map(map) {
532
- return this.serializeObjectEntries('Map', map.entries());
533
- }
534
- }
535
- for (const type of ['Error', 'RegExp', 'URL']) {
536
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
537
- // @ts-expect-error
538
- Serializer.prototype['$' + type] = function (val) {
539
- return `${type}(${val})`;
540
- };
541
- }
542
- for (const type of [
543
- 'Int8Array',
544
- 'Uint8Array',
545
- 'Uint8ClampedArray',
546
- 'Int16Array',
547
- 'Uint16Array',
548
- 'Int32Array',
549
- 'Uint32Array',
550
- 'Float32Array',
551
- 'Float64Array'
552
- ]) {
553
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
554
- // @ts-expect-error
555
- Serializer.prototype['$' + type] = function (arr) {
556
- return `${type}[${arr.join(',')}]`;
557
- };
558
- }
559
- for (const type of ['BigInt64Array', 'BigUint64Array']) {
560
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
561
- // @ts-expect-error
562
- Serializer.prototype['$' + type] = function (arr) {
563
- return `${type}[${arr.join('n,')}${arr.length > 0 ? 'n' : ''}]`;
564
- };
565
- }
566
- return Serializer;
567
- })();
568
-
569
- /**
570
- * Compare two objects using reference equality and stable deep hashing.
571
- * @param {any} object1 First object
572
- * @param {any} object2 Second object
573
- * @return {boolean} true if equal and false if not
574
- */
575
- function isEqual(object1, object2) {
576
- if (object1 === object2) {
577
- return true;
578
- }
579
- if (serialize(object1) === serialize(object2)) {
580
- return true;
581
- }
582
- return false;
583
- }
584
-
585
- function isInsideForm(el) {
586
- if (!el || !el.nativeElement) {
587
- return true;
588
- }
589
- return Boolean(el.nativeElement.closest('form'));
590
- }
591
-
592
- function isNullish(value) {
593
- return value === null || value === undefined;
594
- }
595
-
596
- const isNumber = (v) => typeof v === 'number';
597
-
598
- /**
599
- * The function `isValueEqualOrExist` checks if a value is equal to or exists in another value or
600
- * array.
601
- * @param {T | T[] | undefined} base - It represents the base value that you want to compare with the `current` value.
602
- * @param {T | T[] | undefined} current - The `current` parameter represents the current value that you want to compare with the `base` value or values.
603
- * @returns The `isValueEqualOrExist` function returns a boolean value. It checks if the `base` value
604
- * is equal to the `current` value or if the `current` value exists within the `base` value. The
605
- * function handles cases where `base` can be a single value, an array of values, or undefined.
606
- */
607
- function isValueEqualOrExist(base, current) {
608
- if (isNullish(base))
609
- return false;
610
- if (Array.isArray(base)) {
611
- return base.some((val) => isEqual(val, current));
612
- }
613
- else {
614
- return isEqual(base, current);
615
- }
616
- }
617
-
618
- const ALT = 'Alt';
619
- const ARROW_DOWN = 'ArrowDown';
620
- const ARROW_LEFT = 'ArrowLeft';
621
- const ARROW_RIGHT = 'ArrowRight';
622
- const ARROW_UP = 'ArrowUp';
623
- const BACKSPACE = 'Backspace';
624
- const CAPS_LOCK = 'CapsLock';
625
- const CONTROL = 'Control';
626
- const DELETE = 'Delete';
627
- const END = 'End';
628
- const ENTER = 'Enter';
629
- const ESCAPE = 'Escape';
630
- const F1 = 'F1';
631
- const F10 = 'F10';
632
- const F11 = 'F11';
633
- const F12 = 'F12';
634
- const F2 = 'F2';
635
- const F3 = 'F3';
636
- const F4 = 'F4';
637
- const F5 = 'F5';
638
- const F6 = 'F6';
639
- const F7 = 'F7';
640
- const F8 = 'F8';
641
- const F9 = 'F9';
642
- const HOME = 'Home';
643
- const META = 'Meta';
644
- const PAGE_DOWN = 'PageDown';
645
- const PAGE_UP = 'PageUp';
646
- const SHIFT = 'Shift';
647
- const SPACE = ' ';
648
- const TAB = 'Tab';
649
- const CTRL = 'Control';
650
- const ASTERISK = '*';
651
- const a = 'a';
652
- const P = 'P';
653
- const A = 'A';
654
- const p = 'p';
655
- const n = 'n';
656
- const j = 'j';
657
- const k = 'k';
658
- const SPACE_CODE = 'Space';
659
-
660
- /**
661
- * Creates an Angular provider that binds the given token to the existing instance
662
- * of the specified class. This is especially useful when you want multiple
663
- * tokens (or interfaces) to resolve to the same directive/component instance.
664
- *
665
- * @template T - The type associated with the injection token.
666
- * @param token - The InjectionToken or abstract type you want to provide.
667
- * @param type - The class type whose existing instance will be used for this token.
668
- * @returns A Provider configuration object for Angular's DI system.
669
- *
670
- * @example
671
- *
672
- * @Directive({
673
- * providers: [
674
- * provideToken(RdxToggleGroupToken, RdxToggleGroupDirective),
675
- * provideValueAccessor(RdxToggleGroupDirective)
676
- * ]
677
- * })
678
- * export class RdxToggleGroupDirective {}
679
- */
680
- function provideToken(token, type) {
681
- return {
682
- provide: token,
683
- useExisting: forwardRef(() => type)
684
- };
685
- }
686
-
687
- const WINDOW = new InjectionToken('An abstraction over global window object', {
688
- factory: () => {
689
- const { defaultView } = injectDocument();
690
- if (!defaultView) {
691
- throw new Error('Window is not available');
692
- }
693
- return defaultView;
694
- }
695
- });
696
- function injectWindow() {
697
- return inject(WINDOW);
698
- }
699
-
700
184
  // Thanks for idea.
701
185
  // https://github.com/unovue/reka-ui/blob/v2/packages/core/src/shared/createContext.ts
702
186
  /**
@@ -716,9 +200,13 @@ function createContext(description) {
716
200
  * @throws Error when context is not provided and not optional
717
201
  */
718
202
  const injectContext = (optional = false) => {
719
- const value = optional ? inject(CONTEXT_TOKEN, { optional: true }) : inject(CONTEXT_TOKEN);
203
+ // Always inject optionally so a missing context produces our own descriptive
204
+ // error instead of Angular's generic NullInjectorError. This also catches a
205
+ // provided factory that returns null/undefined for the non-optional case.
206
+ const value = inject(CONTEXT_TOKEN, { optional: true });
720
207
  if (value == null && !optional) {
721
- throw new Error(`No context provided for token ${CONTEXT_TOKEN.toString()}`);
208
+ throw new Error(`No \`${description}Context\` found. A part of the \`${description}\` primitive ` +
209
+ `must be used inside its root (the directive that provides \`${description}Context\`).`);
722
210
  }
723
211
  return value;
724
212
  };
@@ -1486,23 +974,65 @@ function createContent(props) {
1486
974
  };
1487
975
  }
1488
976
 
1489
- function isSegmentNavigationKey(key) {
1490
- if (key === ARROW_RIGHT || key === ARROW_LEFT)
1491
- return true;
1492
- return false;
1493
- }
1494
- function isNumberString(value) {
1495
- if (Number.isNaN(Number.parseInt(value)))
1496
- return false;
1497
- return true;
1498
- }
1499
- function isAcceptableSegmentKey(key) {
1500
- const acceptableSegmentKeys = [
1501
- ENTER,
1502
- ARROW_UP,
1503
- ARROW_DOWN,
1504
- ARROW_LEFT,
1505
- ARROW_RIGHT,
977
+ const ALT = 'Alt';
978
+ const ARROW_DOWN = 'ArrowDown';
979
+ const ARROW_LEFT = 'ArrowLeft';
980
+ const ARROW_RIGHT = 'ArrowRight';
981
+ const ARROW_UP = 'ArrowUp';
982
+ const BACKSPACE = 'Backspace';
983
+ const CAPS_LOCK = 'CapsLock';
984
+ const CONTROL = 'Control';
985
+ const DELETE = 'Delete';
986
+ const END = 'End';
987
+ const ENTER = 'Enter';
988
+ const ESCAPE = 'Escape';
989
+ const F1 = 'F1';
990
+ const F10 = 'F10';
991
+ const F11 = 'F11';
992
+ const F12 = 'F12';
993
+ const F2 = 'F2';
994
+ const F3 = 'F3';
995
+ const F4 = 'F4';
996
+ const F5 = 'F5';
997
+ const F6 = 'F6';
998
+ const F7 = 'F7';
999
+ const F8 = 'F8';
1000
+ const F9 = 'F9';
1001
+ const HOME = 'Home';
1002
+ const META = 'Meta';
1003
+ const PAGE_DOWN = 'PageDown';
1004
+ const PAGE_UP = 'PageUp';
1005
+ const SHIFT = 'Shift';
1006
+ const SPACE = ' ';
1007
+ const TAB = 'Tab';
1008
+ const CTRL = 'Control';
1009
+ const ASTERISK = '*';
1010
+ const a = 'a';
1011
+ const P = 'P';
1012
+ const A = 'A';
1013
+ const p = 'p';
1014
+ const n = 'n';
1015
+ const j = 'j';
1016
+ const k = 'k';
1017
+ const SPACE_CODE = 'Space';
1018
+
1019
+ function isSegmentNavigationKey(key) {
1020
+ if (key === ARROW_RIGHT || key === ARROW_LEFT)
1021
+ return true;
1022
+ return false;
1023
+ }
1024
+ function isNumberString(value) {
1025
+ if (Number.isNaN(Number.parseInt(value)))
1026
+ return false;
1027
+ return true;
1028
+ }
1029
+ function isAcceptableSegmentKey(key) {
1030
+ const acceptableSegmentKeys = [
1031
+ ENTER,
1032
+ ARROW_UP,
1033
+ ARROW_DOWN,
1034
+ ARROW_LEFT,
1035
+ ARROW_RIGHT,
1506
1036
  BACKSPACE,
1507
1037
  SPACE,
1508
1038
  'a',
@@ -2297,219 +1827,353 @@ function handleAndDispatchCustomEvent(name, handler, detail) {
2297
1827
  target.dispatchEvent(event);
2298
1828
  }
2299
1829
 
2300
- var RdxPositionSide;
2301
- (function (RdxPositionSide) {
2302
- RdxPositionSide["Top"] = "top";
2303
- RdxPositionSide["Right"] = "right";
2304
- RdxPositionSide["Bottom"] = "bottom";
2305
- RdxPositionSide["Left"] = "left";
2306
- })(RdxPositionSide || (RdxPositionSide = {}));
2307
- var RdxPositionAlign;
2308
- (function (RdxPositionAlign) {
2309
- RdxPositionAlign["Start"] = "start";
2310
- RdxPositionAlign["Center"] = "center";
2311
- RdxPositionAlign["End"] = "end";
2312
- })(RdxPositionAlign || (RdxPositionAlign = {}));
1830
+ /**
1831
+ * Per-prefix counters, kept module-global so generated IDs stay deterministic within a run.
1832
+ * Determinism keeps server and client renders in sync, which matters for hydration.
1833
+ */
1834
+ const counters = new Map();
1835
+ /**
1836
+ * Generates unique, SSR-stable IDs for DOM nodes.
1837
+ *
1838
+ * IDs are deterministic per prefix (a monotonic counter) so the server and the client produce the
1839
+ * same sequence and hydration does not mismatch. The application's `APP_ID` is folded into the
1840
+ * prefix so multiple Angular apps on one page don't collide; the default `ng` app id is omitted to
1841
+ * keep IDs short for the common single-app case.
1842
+ *
1843
+ * Prefer the {@link injectId} hook at call sites; inject this service directly only when you need to
1844
+ * generate IDs lazily outside an injection context.
1845
+ */
1846
+ class RdxIdGenerator {
1847
+ constructor() {
1848
+ this.appId = inject(APP_ID);
1849
+ }
1850
+ /** Generates a unique ID with the given prefix. */
1851
+ getId(prefix) {
1852
+ const key = this.appId === 'ng' ? prefix : prefix + this.appId;
1853
+ const next = counters.get(key) ?? 0;
1854
+ counters.set(key, next + 1);
1855
+ return `${key}${next}`;
1856
+ }
1857
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxIdGenerator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1858
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxIdGenerator, providedIn: 'root' }); }
1859
+ }
1860
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxIdGenerator, decorators: [{
1861
+ type: Injectable,
1862
+ args: [{ providedIn: 'root' }]
1863
+ }] });
1864
+ /**
1865
+ * Returns a unique, SSR-stable ID for the given prefix — the Angular counterpart of React's
1866
+ * `useId`. Must be called in an injection context (e.g. a field initializer or constructor).
1867
+ *
1868
+ * @example
1869
+ * readonly contentId = injectId('rdx-dialog-content-');
1870
+ */
1871
+ function injectId(prefix) {
1872
+ return inject(RdxIdGenerator).getId(prefix);
1873
+ }
2313
1874
 
2314
- const RDX_POSITIONS = {
2315
- [RdxPositionSide.Top]: {
2316
- [RdxPositionAlign.Center]: {
2317
- originX: 'center',
2318
- originY: 'top',
2319
- overlayX: 'center',
2320
- overlayY: 'bottom'
2321
- },
2322
- [RdxPositionAlign.Start]: {
2323
- originX: 'start',
2324
- originY: 'top',
2325
- overlayX: 'start',
2326
- overlayY: 'bottom'
2327
- },
2328
- [RdxPositionAlign.End]: {
2329
- originX: 'end',
2330
- originY: 'top',
2331
- overlayX: 'end',
2332
- overlayY: 'bottom'
1875
+ /**
1876
+ * Announces messages to screen readers through an `aria-live` region, without moving focus.
1877
+ *
1878
+ * Own replacement for CDK's `LiveAnnouncer` — lazily appends a visually hidden live region to
1879
+ * the document body and writes messages into it. No-op on the server.
1880
+ */
1881
+ class RdxLiveAnnouncer {
1882
+ constructor() {
1883
+ this.document = inject(DOCUMENT);
1884
+ this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
1885
+ this.liveElement = null;
1886
+ inject(DestroyRef).onDestroy(() => {
1887
+ clearTimeout(this.previousTimeout);
1888
+ this.liveElement?.remove();
1889
+ this.liveElement = null;
1890
+ });
1891
+ }
1892
+ /**
1893
+ * Announces a message to screen readers.
1894
+ *
1895
+ * @param message The message to announce.
1896
+ * @param politeness The politeness of the announcer element (defaults to `'polite'`).
1897
+ * @param duration If provided, the message is cleared after this many milliseconds.
1898
+ */
1899
+ announce(message, politeness = 'polite', duration) {
1900
+ if (!this.isBrowser) {
1901
+ return;
2333
1902
  }
2334
- },
2335
- [RdxPositionSide.Right]: {
2336
- [RdxPositionAlign.Center]: {
2337
- originX: 'end',
2338
- originY: 'center',
2339
- overlayX: 'start',
2340
- overlayY: 'center'
2341
- },
2342
- [RdxPositionAlign.Start]: {
2343
- originX: 'end',
2344
- originY: 'top',
2345
- overlayX: 'start',
2346
- overlayY: 'top'
2347
- },
2348
- [RdxPositionAlign.End]: {
2349
- originX: 'end',
2350
- originY: 'bottom',
2351
- overlayX: 'start',
2352
- overlayY: 'bottom'
1903
+ const liveElement = this.getLiveElement();
1904
+ clearTimeout(this.previousTimeout);
1905
+ liveElement.setAttribute('aria-live', politeness);
1906
+ // Clear the live element first, then set the message after a tick so that screen
1907
+ // readers reliably pick up the change even when the text is identical.
1908
+ liveElement.textContent = '';
1909
+ this.previousTimeout = setTimeout(() => {
1910
+ liveElement.textContent = message;
1911
+ if (typeof duration === 'number') {
1912
+ this.previousTimeout = setTimeout(() => (liveElement.textContent = ''), duration);
1913
+ }
1914
+ });
1915
+ }
1916
+ /** Clears the current announcement. */
1917
+ clear() {
1918
+ if (this.liveElement) {
1919
+ this.liveElement.textContent = '';
1920
+ }
1921
+ }
1922
+ getLiveElement() {
1923
+ if (this.liveElement) {
1924
+ return this.liveElement;
1925
+ }
1926
+ const element = this.document.createElement('div');
1927
+ element.classList.add('rdx-live-announcer');
1928
+ element.setAttribute('aria-atomic', 'true');
1929
+ element.setAttribute('aria-live', 'polite');
1930
+ // Visually hide the region while keeping it available to assistive technology.
1931
+ element.style.position = 'absolute';
1932
+ element.style.width = '1px';
1933
+ element.style.height = '1px';
1934
+ element.style.margin = '-1px';
1935
+ element.style.padding = '0';
1936
+ element.style.border = '0';
1937
+ element.style.overflow = 'hidden';
1938
+ element.style.clip = 'rect(0 0 0 0)';
1939
+ element.style.clipPath = 'inset(100%)';
1940
+ element.style.whiteSpace = 'nowrap';
1941
+ this.document.body.appendChild(element);
1942
+ this.liveElement = element;
1943
+ return element;
1944
+ }
1945
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxLiveAnnouncer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1946
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxLiveAnnouncer, providedIn: 'root' }); }
1947
+ }
1948
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxLiveAnnouncer, decorators: [{
1949
+ type: Injectable,
1950
+ args: [{ providedIn: 'root' }]
1951
+ }], ctorParameters: () => [] });
1952
+
1953
+ /** Narrows to `null | undefined`. */
1954
+ function isNullish(value) {
1955
+ return value === null || value === undefined;
1956
+ }
1957
+ /**
1958
+ * Structural equality for the value shapes a primitive can hold: primitives (incl. `NaN`), arrays,
1959
+ * plain objects, and the common built-ins `Date`, `RegExp`, `Map`, and `Set`. Reference cycles are
1960
+ * handled. Other opaque objects (e.g. class instances with no own enumerable properties) fall back
1961
+ * to per-key comparison and so only match when they expose equal enumerable state.
1962
+ */
1963
+ function isEqual(a, b) {
1964
+ return equals(a, b, new WeakMap());
1965
+ }
1966
+ function equals(a, b, seen) {
1967
+ if (a === b) {
1968
+ return true;
1969
+ }
1970
+ // NaN is the one primitive that is not reference-equal to itself.
1971
+ if (typeof a === 'number' && typeof b === 'number') {
1972
+ return Number.isNaN(a) && Number.isNaN(b);
1973
+ }
1974
+ if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') {
1975
+ return false;
1976
+ }
1977
+ // Different prototypes (Date vs plain object, class A vs class B, …) are never structurally equal.
1978
+ if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) {
1979
+ return false;
1980
+ }
1981
+ // Break reference cycles: if this exact pair is already being compared on the current path,
1982
+ // the structure has matched so far — treat it as equal. Cleared on ascent so sibling branches
1983
+ // start fresh.
1984
+ if (seen.get(a) === b) {
1985
+ return true;
1986
+ }
1987
+ seen.set(a, b);
1988
+ try {
1989
+ if (a instanceof Date) {
1990
+ return a.getTime() === b.getTime();
2353
1991
  }
2354
- },
2355
- [RdxPositionSide.Bottom]: {
2356
- [RdxPositionAlign.Center]: {
2357
- originX: 'center',
2358
- originY: 'bottom',
2359
- overlayX: 'center',
2360
- overlayY: 'top'
2361
- },
2362
- [RdxPositionAlign.Start]: {
2363
- originX: 'start',
2364
- originY: 'bottom',
2365
- overlayX: 'start',
2366
- overlayY: 'top'
2367
- },
2368
- [RdxPositionAlign.End]: {
2369
- originX: 'end',
2370
- originY: 'bottom',
2371
- overlayX: 'end',
2372
- overlayY: 'top'
1992
+ if (a instanceof RegExp) {
1993
+ return a.source === b.source && a.flags === b.flags;
2373
1994
  }
2374
- },
2375
- [RdxPositionSide.Left]: {
2376
- [RdxPositionAlign.Center]: {
2377
- originX: 'start',
2378
- originY: 'center',
2379
- overlayX: 'end',
2380
- overlayY: 'center'
2381
- },
2382
- [RdxPositionAlign.Start]: {
2383
- originX: 'start',
2384
- originY: 'top',
2385
- overlayX: 'end',
2386
- overlayY: 'top'
2387
- },
2388
- [RdxPositionAlign.End]: {
2389
- originX: 'start',
2390
- originY: 'bottom',
2391
- overlayX: 'end',
2392
- overlayY: 'bottom'
1995
+ if (Array.isArray(a)) {
1996
+ return a.length === b.length && a.every((item, index) => equals(item, b[index], seen));
2393
1997
  }
2394
- }
2395
- };
2396
- const RDX_POSITIONING_DEFAULTS = {
2397
- offsets: {
2398
- side: 4,
2399
- align: 0
2400
- },
2401
- arrow: {
2402
- width: 8,
2403
- height: 6
2404
- }
2405
- };
2406
-
2407
- function getContentPosition(sideAndAlignWithOffsets) {
2408
- const { side, align, sideOffset, alignOffset } = sideAndAlignWithOffsets;
2409
- const position = {
2410
- ...(RDX_POSITIONS[side]?.[align] ?? RDX_POSITIONS[RdxPositionSide.Top][RdxPositionAlign.Center])
2411
- };
2412
- if (sideOffset || alignOffset) {
2413
- if ([RdxPositionSide.Top, RdxPositionSide.Bottom].includes(side)) {
2414
- if (sideOffset) {
2415
- position.offsetY = side === RdxPositionSide.Top ? -sideOffset : sideOffset;
1998
+ if (a instanceof Map) {
1999
+ if (a.size !== b.size) {
2000
+ return false;
2416
2001
  }
2417
- if (alignOffset) {
2418
- position.offsetX = alignOffset;
2002
+ for (const [key, value] of a) {
2003
+ if (!b.has(key) || !equals(value, b.get(key), seen)) {
2004
+ return false;
2005
+ }
2419
2006
  }
2007
+ return true;
2420
2008
  }
2421
- else {
2422
- if (sideOffset) {
2423
- position.offsetX = side === RdxPositionSide.Left ? -sideOffset : sideOffset;
2009
+ if (a instanceof Set) {
2010
+ if (a.size !== b.size) {
2011
+ return false;
2424
2012
  }
2425
- if (alignOffset) {
2426
- position.offsetY = alignOffset;
2013
+ for (const value of a) {
2014
+ if (!b.has(value)) {
2015
+ return false;
2016
+ }
2427
2017
  }
2018
+ return true;
2019
+ }
2020
+ const keys = Object.keys(a);
2021
+ if (keys.length !== Object.keys(b).length) {
2022
+ return false;
2428
2023
  }
2024
+ return keys.every((key) => Object.prototype.hasOwnProperty.call(b, key) && equals(a[key], b[key], seen));
2429
2025
  }
2430
- return position;
2431
- }
2432
- let allPossibleConnectedPositions;
2433
- function getAllPossibleConnectedPositions() {
2434
- if (!allPossibleConnectedPositions) {
2435
- allPossibleConnectedPositions = new Map();
2026
+ finally {
2027
+ seen.delete(a);
2436
2028
  }
2437
- if (allPossibleConnectedPositions.size < 1) {
2438
- for (const [side, aligns] of Object.entries(RDX_POSITIONS)) {
2439
- for (const [align, position] of Object.entries(aligns)) {
2440
- allPossibleConnectedPositions.set(`${side}|${align}`, position);
2029
+ }
2030
+
2031
+ /**
2032
+ * Creates an Angular provider that binds the given token to the existing instance
2033
+ * of the specified class. This is especially useful when you want multiple
2034
+ * tokens (or interfaces) to resolve to the same directive/component instance.
2035
+ *
2036
+ * @template T - The type associated with the injection token.
2037
+ * @param token - The InjectionToken or abstract type you want to provide.
2038
+ * @param type - The class type whose existing instance will be used for this token.
2039
+ * @returns A Provider configuration object for Angular's DI system.
2040
+ *
2041
+ * @example
2042
+ *
2043
+ * @Directive({
2044
+ * providers: [
2045
+ * provideToken(RdxFooToken, RdxFooDirective),
2046
+ * provideValueAccessor(RdxFooDirective)
2047
+ * ]
2048
+ * })
2049
+ * export class RdxFooDirective {}
2050
+ */
2051
+ function provideToken(token, type) {
2052
+ return {
2053
+ provide: token,
2054
+ useExisting: forwardRef(() => type)
2055
+ };
2056
+ }
2057
+
2058
+ function injectDocument() {
2059
+ return inject(DOCUMENT);
2060
+ }
2061
+
2062
+ function elementSize({ elementRef, injector }) {
2063
+ const destroyRef = injector.get(DestroyRef);
2064
+ const result = signal({
2065
+ width: elementRef.nativeElement.offsetWidth,
2066
+ height: elementRef.nativeElement.offsetHeight
2067
+ }, ...(ngDevMode ? [{ debugName: "result" }] : /* istanbul ignore next */ []));
2068
+ afterNextRender(() => {
2069
+ const resizeObserver = new ResizeObserver((entries) => {
2070
+ const entry = entries[0];
2071
+ let width;
2072
+ let height;
2073
+ if ('borderBoxSize' in entry) {
2074
+ const borderSizeEntry = entry['borderBoxSize'];
2075
+ const borderSize = Array.isArray(borderSizeEntry) ? borderSizeEntry[0] : borderSizeEntry;
2076
+ width = borderSize['inlineSize'];
2077
+ height = borderSize['blockSize'];
2441
2078
  }
2442
- }
2079
+ else {
2080
+ width = elementRef.nativeElement.offsetWidth;
2081
+ height = elementRef.nativeElement.offsetHeight;
2082
+ }
2083
+ result.set({ width, height });
2084
+ });
2085
+ destroyRef.onDestroy(() => resizeObserver.disconnect());
2086
+ }, { injector: injector });
2087
+ return result.asReadonly();
2088
+ }
2089
+
2090
+ function getActiveElement() {
2091
+ let activeElement = document.activeElement;
2092
+ if (activeElement == null) {
2093
+ return null;
2443
2094
  }
2444
- return allPossibleConnectedPositions;
2445
- }
2446
- function getSideAndAlignFromAllPossibleConnectedPositions(position) {
2447
- const allPossibleConnectedPositions = getAllPossibleConnectedPositions();
2448
- let sideAndAlign;
2449
- allPossibleConnectedPositions.forEach((value, key) => {
2450
- if (position.originX === value.originX &&
2451
- position.originY === value.originY &&
2452
- position.overlayX === value.overlayX &&
2453
- position.overlayY === value.overlayY) {
2454
- const sideAndAlignArray = key.split('|');
2455
- sideAndAlign = {
2456
- side: sideAndAlignArray[0],
2457
- align: sideAndAlignArray[1]
2458
- };
2459
- }
2460
- });
2461
- if (!sideAndAlign) {
2462
- throw Error(`[Rdx positioning] cannot infer both side and align from the given position (${JSON.stringify(position)})`);
2095
+ while (activeElement != null &&
2096
+ activeElement.shadowRoot != null &&
2097
+ activeElement.shadowRoot.activeElement != null) {
2098
+ activeElement = activeElement.shadowRoot.activeElement;
2463
2099
  }
2464
- return sideAndAlign;
2100
+ return activeElement;
2465
2101
  }
2466
- function getArrowPositionParams(sideAndAlign, arrowWidthAndHeight, triggerWidthAndHeight) {
2467
- const posParams = {
2468
- top: '',
2469
- left: '',
2470
- transform: '',
2471
- transformOrigin: 'center center 0px'
2472
- };
2473
- if ([RdxPositionSide.Top, RdxPositionSide.Bottom].includes(sideAndAlign.side)) {
2474
- if (sideAndAlign.side === RdxPositionSide.Top) {
2475
- posParams.top = '100%';
2476
- }
2477
- else {
2478
- posParams.top = `-${arrowWidthAndHeight.height}px`;
2479
- posParams.transform = `rotate(180deg)`;
2102
+
2103
+ /**
2104
+ * Creates a resize observer effect for element
2105
+ *
2106
+ * @param options Configuration options
2107
+ * @param options.injector Angular injector
2108
+ * @param options.element Signal returning the element to observe
2109
+ * @param options.onResize Callback when element is resized
2110
+ * @returns EffectRef that can be destroyed when needed
2111
+ */
2112
+ function resizeEffect(options) {
2113
+ return effect((onCleanup) => {
2114
+ const elementOrRef = options.element();
2115
+ if (!elementOrRef)
2116
+ return;
2117
+ // Extract native element from ElementRef or use directly if it's HTMLElement
2118
+ const element = elementOrRef instanceof ElementRef ? elementOrRef.nativeElement : elementOrRef;
2119
+ const resizeObserver = new ResizeObserver(options.onResize);
2120
+ resizeObserver.observe(element);
2121
+ onCleanup(() => resizeObserver.disconnect());
2122
+ }, { injector: options.injector });
2123
+ }
2124
+
2125
+ /**
2126
+ * Process-wide ownership of `document.body`'s overflow while one or more overlays lock scrolling.
2127
+ *
2128
+ * A single shared counter across every primitive that locks scroll is essential: with separate
2129
+ * per-primitive counters, a popover and a dialog open at the same time would each capture the
2130
+ * other's already-locked `overflow: hidden` as the "original" value and restore it on close,
2131
+ * leaving the page permanently unscrollable.
2132
+ */
2133
+ let originalBodyOverflow = null;
2134
+ let scrollLockCount = 0;
2135
+ /**
2136
+ * Locks `document.body` scrolling while `active()` is `true`, and restores the original overflow
2137
+ * when it becomes `false` or the calling context is destroyed.
2138
+ *
2139
+ * Lock ownership is shared across all callers via a single module-level counter, so nested or
2140
+ * concurrent overlays compose correctly. Must be called in an injection context.
2141
+ */
2142
+ function useScrollLock(active) {
2143
+ const document = inject(DOCUMENT$1);
2144
+ let isLocked = false;
2145
+ const lock = () => {
2146
+ if (isLocked) {
2147
+ return;
2480
2148
  }
2481
- if (sideAndAlign.align === RdxPositionAlign.Start) {
2482
- posParams.left = `${(triggerWidthAndHeight.width - arrowWidthAndHeight.width) / 2}px`;
2149
+ const body = document.body;
2150
+ if (scrollLockCount === 0) {
2151
+ originalBodyOverflow = body.style.overflow;
2152
+ body.style.overflow = 'hidden';
2483
2153
  }
2484
- else if (sideAndAlign.align === RdxPositionAlign.Center) {
2485
- posParams.left = `calc(50% - ${arrowWidthAndHeight.width / 2}px)`;
2154
+ scrollLockCount++;
2155
+ isLocked = true;
2156
+ };
2157
+ const unlock = () => {
2158
+ if (!isLocked) {
2159
+ return;
2486
2160
  }
2487
- else if (sideAndAlign.align === RdxPositionAlign.End) {
2488
- posParams.left = `calc(100% - ${(triggerWidthAndHeight.width + arrowWidthAndHeight.width) / 2}px)`;
2161
+ scrollLockCount--;
2162
+ isLocked = false;
2163
+ if (scrollLockCount === 0 && originalBodyOverflow !== null) {
2164
+ document.body.style.overflow = originalBodyOverflow;
2165
+ originalBodyOverflow = null;
2489
2166
  }
2490
- }
2491
- else if ([RdxPositionSide.Left, RdxPositionSide.Right].includes(sideAndAlign.side)) {
2492
- if (sideAndAlign.side === RdxPositionSide.Left) {
2493
- posParams.left = `calc(100% - ${arrowWidthAndHeight.width}px)`;
2494
- posParams.transform = `rotate(-90deg)`;
2495
- posParams.transformOrigin = 'top right 0px';
2167
+ };
2168
+ effect(() => {
2169
+ if (active()) {
2170
+ lock();
2496
2171
  }
2497
2172
  else {
2498
- posParams.left = `0`;
2499
- posParams.transform = `rotate(90deg)`;
2500
- posParams.transformOrigin = 'top left 0px';
2173
+ unlock();
2501
2174
  }
2502
- if (sideAndAlign.align === RdxPositionAlign.Start) {
2503
- posParams.top = `${(triggerWidthAndHeight.height - arrowWidthAndHeight.width) / 2}px`;
2504
- }
2505
- else if (sideAndAlign.align === RdxPositionAlign.Center) {
2506
- posParams.top = `calc(50% - ${arrowWidthAndHeight.width / 2}px)`;
2507
- }
2508
- else if (sideAndAlign.align === RdxPositionAlign.End) {
2509
- posParams.top = `calc(100% - ${(triggerWidthAndHeight.height + arrowWidthAndHeight.width) / 2}px)`;
2510
- }
2511
- }
2512
- return posParams;
2175
+ });
2176
+ inject(DestroyRef).onDestroy(unlock);
2513
2177
  }
2514
2178
 
2515
2179
  // made by https://reka-ui.com/
@@ -2596,26 +2260,449 @@ function findNextFocusableElement(elements, currentElement, options, iterations
2596
2260
  return candidate;
2597
2261
  }
2598
2262
 
2263
+ const graceAreaContainers = new WeakMap();
2264
+ function createSignalEvent() {
2265
+ const handlers = new Set();
2266
+ return {
2267
+ on(callback) {
2268
+ handlers.add(callback);
2269
+ return () => handlers.delete(callback);
2270
+ },
2271
+ emitVoid() {
2272
+ handlers.forEach((handler) => handler(undefined));
2273
+ }
2274
+ };
2275
+ }
2599
2276
  /**
2600
- * Creates a resize observer effect for element
2277
+ * Keeps hover content open while the pointer crosses the gap between a trigger and a popup.
2278
+ */
2279
+ function useGraceArea(triggerEl, containerEl, resetMs = 300) {
2280
+ const isPointerInTransit = signal(false, ...(ngDevMode ? [{ debugName: "isPointerInTransit" }] : /* istanbul ignore next */ []));
2281
+ const pointerExit = createSignalEvent();
2282
+ let pointerGraceArea = null;
2283
+ let resetTimer = null;
2284
+ function armInTransitAutoReset() {
2285
+ if (resetTimer !== null)
2286
+ window.clearTimeout(resetTimer);
2287
+ resetTimer = window.setTimeout(() => {
2288
+ isPointerInTransit.set(false);
2289
+ resetTimer = null;
2290
+ }, resetMs);
2291
+ }
2292
+ function clearGraceArea() {
2293
+ pointerGraceArea = null;
2294
+ isPointerInTransit.set(false);
2295
+ if (resetTimer !== null) {
2296
+ window.clearTimeout(resetTimer);
2297
+ resetTimer = null;
2298
+ }
2299
+ }
2300
+ function createGraceArea(event, hoverTarget) {
2301
+ const currentTarget = event.currentTarget;
2302
+ const exitPoint = { x: event.clientX, y: event.clientY };
2303
+ const exitSide = getExitSideFromRect(exitPoint, currentTarget.getBoundingClientRect());
2304
+ const paddedExitPoints = getPaddedExitPoints(exitPoint, exitSide);
2305
+ const hoverTargetPoints = getPointsFromRect(hoverTarget.getBoundingClientRect());
2306
+ pointerGraceArea = getHull([...paddedExitPoints, ...hoverTargetPoints]);
2307
+ isPointerInTransit.set(true);
2308
+ armInTransitAutoReset();
2309
+ }
2310
+ function trackPointerGrace(event) {
2311
+ if (!pointerGraceArea || !(event.target instanceof HTMLElement))
2312
+ return;
2313
+ const trigger = triggerEl();
2314
+ const container = containerEl();
2315
+ if (!trigger || !container)
2316
+ return;
2317
+ const target = event.target;
2318
+ const pointerPosition = { x: event.clientX, y: event.clientY };
2319
+ const enteredContainer = target.closest('[data-grace-area-container]');
2320
+ const nestedTrigger = enteredContainer ? graceAreaContainers.get(enteredContainer) : undefined;
2321
+ const hasEnteredTarget = trigger.contains(target) ||
2322
+ container.contains(target) ||
2323
+ (nestedTrigger ? container.contains(nestedTrigger) : false);
2324
+ const isOutsideGrace = !isPointInPolygon(pointerPosition, pointerGraceArea);
2325
+ const isAnotherGraceAreaTrigger = !!target.closest('[data-grace-area-trigger]');
2326
+ if (hasEnteredTarget) {
2327
+ clearGraceArea();
2328
+ }
2329
+ else if (isOutsideGrace || isAnotherGraceAreaTrigger) {
2330
+ clearGraceArea();
2331
+ pointerExit.emitVoid();
2332
+ }
2333
+ }
2334
+ effect((onCleanup) => {
2335
+ const trigger = triggerEl();
2336
+ const container = containerEl();
2337
+ const onTriggerLeave = (event) => {
2338
+ if (container)
2339
+ createGraceArea(event, container);
2340
+ };
2341
+ const onContainerLeave = (event) => {
2342
+ if (trigger)
2343
+ createGraceArea(event, trigger);
2344
+ };
2345
+ onCleanup(() => {
2346
+ const doc = trigger?.ownerDocument;
2347
+ trigger?.removeEventListener('pointerleave', onTriggerLeave);
2348
+ container?.removeEventListener('pointerleave', onContainerLeave);
2349
+ doc?.removeEventListener('pointermove', trackPointerGrace);
2350
+ trigger?.removeAttribute('data-grace-area-trigger');
2351
+ container?.removeAttribute('data-grace-area-container');
2352
+ if (container && graceAreaContainers.get(container) === trigger) {
2353
+ graceAreaContainers.delete(container);
2354
+ }
2355
+ clearGraceArea();
2356
+ });
2357
+ if (!trigger || !container)
2358
+ return;
2359
+ trigger.setAttribute('data-grace-area-trigger', '');
2360
+ container.setAttribute('data-grace-area-container', '');
2361
+ graceAreaContainers.set(container, trigger);
2362
+ trigger.addEventListener('pointerleave', onTriggerLeave, { passive: true });
2363
+ container.addEventListener('pointerleave', onContainerLeave, { passive: true });
2364
+ trigger.ownerDocument.addEventListener('pointermove', trackPointerGrace, { passive: true });
2365
+ });
2366
+ return {
2367
+ isPointerInTransit: isPointerInTransit.asReadonly(),
2368
+ onPointerExit: pointerExit.on
2369
+ };
2370
+ }
2371
+ function getExitSideFromRect(point, rect) {
2372
+ const top = Math.abs(rect.top - point.y);
2373
+ const bottom = Math.abs(rect.bottom - point.y);
2374
+ const right = Math.abs(rect.right - point.x);
2375
+ const left = Math.abs(rect.left - point.x);
2376
+ const min = Math.min(top, bottom, right, left);
2377
+ if (!Number.isFinite(min)) {
2378
+ return 'bottom';
2379
+ }
2380
+ switch (min) {
2381
+ case left:
2382
+ return 'left';
2383
+ case right:
2384
+ return 'right';
2385
+ case top:
2386
+ return 'top';
2387
+ case bottom:
2388
+ return 'bottom';
2389
+ default:
2390
+ throw new Error('unreachable');
2391
+ }
2392
+ }
2393
+ function getPaddedExitPoints(exitPoint, exitSide, padding = 5) {
2394
+ const points = [];
2395
+ switch (exitSide) {
2396
+ case 'top':
2397
+ points.push({ x: exitPoint.x - padding, y: exitPoint.y + padding }, { x: exitPoint.x + padding, y: exitPoint.y + padding });
2398
+ break;
2399
+ case 'bottom':
2400
+ points.push({ x: exitPoint.x - padding, y: exitPoint.y - padding }, { x: exitPoint.x + padding, y: exitPoint.y - padding });
2401
+ break;
2402
+ case 'left':
2403
+ points.push({ x: exitPoint.x + padding, y: exitPoint.y - padding }, { x: exitPoint.x + padding, y: exitPoint.y + padding });
2404
+ break;
2405
+ case 'right':
2406
+ points.push({ x: exitPoint.x - padding, y: exitPoint.y - padding }, { x: exitPoint.x - padding, y: exitPoint.y + padding });
2407
+ break;
2408
+ }
2409
+ return points;
2410
+ }
2411
+ function getPointsFromRect(rect) {
2412
+ const { top, right, bottom, left } = rect;
2413
+ return [
2414
+ { x: left, y: top },
2415
+ { x: right, y: top },
2416
+ { x: right, y: bottom },
2417
+ { x: left, y: bottom }
2418
+ ];
2419
+ }
2420
+ function isPointInPolygon(point, polygon) {
2421
+ const { x, y } = point;
2422
+ let inside = false;
2423
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
2424
+ const xi = polygon[i].x;
2425
+ const yi = polygon[i].y;
2426
+ const xj = polygon[j].x;
2427
+ const yj = polygon[j].y;
2428
+ const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
2429
+ if (intersect)
2430
+ inside = !inside;
2431
+ }
2432
+ return inside;
2433
+ }
2434
+ function getHull(points) {
2435
+ const sortedPoints = points.slice();
2436
+ sortedPoints.sort((a, b) => a.x - b.x || a.y - b.y);
2437
+ return getHullPresorted(sortedPoints);
2438
+ }
2439
+ function getHullPresorted(points) {
2440
+ if (points.length <= 1)
2441
+ return points.slice();
2442
+ const upper = [];
2443
+ for (const point of points) {
2444
+ while (upper.length >= 2) {
2445
+ const q = upper[upper.length - 1];
2446
+ const r = upper[upper.length - 2];
2447
+ if ((q.x - r.x) * (point.y - r.y) >= (q.y - r.y) * (point.x - r.x))
2448
+ upper.pop();
2449
+ else
2450
+ break;
2451
+ }
2452
+ upper.push(point);
2453
+ }
2454
+ upper.pop();
2455
+ const lower = [];
2456
+ for (let index = points.length - 1; index >= 0; index--) {
2457
+ const point = points[index];
2458
+ while (lower.length >= 2) {
2459
+ const q = lower[lower.length - 1];
2460
+ const r = lower[lower.length - 2];
2461
+ if ((q.x - r.x) * (point.y - r.y) >= (q.y - r.y) * (point.x - r.x))
2462
+ lower.pop();
2463
+ else
2464
+ break;
2465
+ }
2466
+ lower.push(point);
2467
+ }
2468
+ lower.pop();
2469
+ if (upper.length === 1 && lower.length === 1 && upper[0].x === lower[0].x && upper[0].y === lower[0].y) {
2470
+ return upper;
2471
+ }
2472
+ return upper.concat(lower);
2473
+ }
2474
+
2475
+ /** Pointer travel (px) before a press becomes a drag — below this a press stays a click/tap. */
2476
+ const DRAG_THRESHOLD = 4;
2477
+ /**
2478
+ * Shared pointer-drag lifecycle for gesture primitives (drawer swipe, toast swipe, etc.).
2601
2479
  *
2602
- * @param options Configuration options
2603
- * @param options.injector Angular injector
2604
- * @param options.element Signal returning the element to observe
2605
- * @param options.onResize Callback when element is resized
2606
- * @returns EffectRef that can be destroyed when needed
2480
+ * A press only becomes a drag once the pointer moves past {@link DRAG_THRESHOLD}; until then it is a
2481
+ * plain tap, so clicks on buttons inside the element keep working (the gesture never captures the
2482
+ * pointer for a tap). Once dragging, the pointer is captured so a drag that leaves the element still
2483
+ * completes, and `lostpointercapture` / `pointercancel` count as a non-committed end — a swallowed
2484
+ * `pointerup` (native context menu, OS gesture, tab switch) can never wedge the gesture. Only the
2485
+ * primary pointer is tracked, so a second finger can't start a parallel gesture. No-op outside the
2486
+ * browser, keeping SSR safe.
2487
+ *
2488
+ * `onEnd` is NOT called if the host is destroyed mid-drag — callers that pair `onStart`/`onEnd`
2489
+ * (e.g. to pause/resume timers) should balance that case in their own `DestroyRef` cleanup.
2490
+ *
2491
+ * Must be called from an injection context (a directive/component constructor).
2607
2492
  */
2608
- function resizeEffect(options) {
2609
- return effect((onCleanup) => {
2610
- const elementOrRef = options.element();
2611
- if (!elementOrRef)
2493
+ function usePointerDrag(handlers) {
2494
+ assertInInjectionContext(usePointerDrag);
2495
+ if (!isPlatformBrowser(inject(PLATFORM_ID))) {
2496
+ return;
2497
+ }
2498
+ const host = inject(ElementRef).nativeElement;
2499
+ let pointerId = null;
2500
+ let downEvent = null;
2501
+ let dragging = false;
2502
+ const removeWindowListeners = () => {
2503
+ window.removeEventListener('pointermove', onPointerMove);
2504
+ window.removeEventListener('pointerup', onPointerUp);
2505
+ window.removeEventListener('pointercancel', onPointerUp);
2506
+ };
2507
+ const reset = (event, committed) => {
2508
+ if (pointerId === null) {
2612
2509
  return;
2613
- // Extract native element from ElementRef or use directly if it's HTMLElement
2614
- const element = elementOrRef instanceof ElementRef ? elementOrRef.nativeElement : elementOrRef;
2615
- const resizeObserver = new ResizeObserver(options.onResize);
2616
- resizeObserver.observe(element);
2617
- onCleanup(() => resizeObserver.disconnect());
2618
- }, { injector: options.injector });
2510
+ }
2511
+ const wasDragging = dragging;
2512
+ try {
2513
+ host.releasePointerCapture?.(pointerId);
2514
+ }
2515
+ catch {
2516
+ // Capture may already be gone (e.g. on lostpointercapture); ignore.
2517
+ }
2518
+ pointerId = null;
2519
+ downEvent = null;
2520
+ dragging = false;
2521
+ removeWindowListeners();
2522
+ // A press that never crossed the threshold was a tap — leave the click untouched.
2523
+ if (wasDragging) {
2524
+ handlers.onEnd(event, committed);
2525
+ }
2526
+ };
2527
+ function onPointerMove(event) {
2528
+ if (event.pointerId !== pointerId || !downEvent) {
2529
+ return;
2530
+ }
2531
+ if (!dragging) {
2532
+ const dx = event.clientX - downEvent.clientX;
2533
+ const dy = event.clientY - downEvent.clientY;
2534
+ if (Math.hypot(dx, dy) < DRAG_THRESHOLD) {
2535
+ return;
2536
+ }
2537
+ dragging = true;
2538
+ try {
2539
+ host.setPointerCapture?.(pointerId);
2540
+ }
2541
+ catch {
2542
+ // Not all environments support pointer capture; the window listeners still drive the gesture.
2543
+ }
2544
+ handlers.onStart(downEvent);
2545
+ }
2546
+ if (handlers.onMove(event) === false) {
2547
+ reset(event, false);
2548
+ }
2549
+ }
2550
+ function onPointerUp(event) {
2551
+ if (event.pointerId !== pointerId) {
2552
+ return;
2553
+ }
2554
+ reset(event, event.type === 'pointerup');
2555
+ }
2556
+ const onLostCapture = (event) => {
2557
+ if (event.pointerId === pointerId) {
2558
+ reset(event, false);
2559
+ }
2560
+ };
2561
+ const onPointerDown = (event) => {
2562
+ if (pointerId !== null || !event.isPrimary || event.button !== 0 || !handlers.canStart(event)) {
2563
+ return;
2564
+ }
2565
+ pointerId = event.pointerId;
2566
+ downEvent = event;
2567
+ dragging = false;
2568
+ window.addEventListener('pointermove', onPointerMove);
2569
+ window.addEventListener('pointerup', onPointerUp);
2570
+ window.addEventListener('pointercancel', onPointerUp);
2571
+ };
2572
+ host.addEventListener('pointerdown', onPointerDown);
2573
+ host.addEventListener('lostpointercapture', onLostCapture);
2574
+ inject(DestroyRef).onDestroy(() => {
2575
+ host.removeEventListener('pointerdown', onPointerDown);
2576
+ host.removeEventListener('lostpointercapture', onLostCapture);
2577
+ removeWindowListeners();
2578
+ });
2579
+ }
2580
+
2581
+ /**
2582
+ * Grace period (ms) added to an element's declared transition duration before the
2583
+ * safety-net timer force-completes a transition. Only matters when the real
2584
+ * `animationend`/`transitionend` never arrives (interrupted, replaced without a
2585
+ * cancel event, reduced motion, …).
2586
+ */
2587
+ const TRANSITION_FALLBACK_BUFFER = 50;
2588
+ /**
2589
+ * Shared open/close transition state machine used by overlay primitives (dialog, popover, …).
2590
+ *
2591
+ * On `start(open)` it flips `status` to `'starting'`/`'ending'`, then — after the next render and
2592
+ * (for opening) one animation frame — clears it and waits for the registered element's running CSS
2593
+ * animations/transitions to finish (via the Web Animations API) before invoking `onComplete(open)`.
2594
+ * Completing on the real `animationend` rather than a duration timer keeps it from firing a frame
2595
+ * late. A duration-based timer remains as a safety net, and if no element is registered or it has no
2596
+ * animation (also SSR / jsdom, where computed durations are `0`) completion is synchronous.
2597
+ *
2598
+ * Must be called in an injection context (uses {@link Injector} and {@link DestroyRef}).
2599
+ */
2600
+ function useTransitionStatus(onComplete) {
2601
+ const injector = inject(Injector);
2602
+ const destroyRef = inject(DestroyRef);
2603
+ const status = signal(undefined, ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
2604
+ let element;
2605
+ let timer;
2606
+ let frame;
2607
+ let version = 0;
2608
+ const clearTimers = () => {
2609
+ if (frame !== undefined) {
2610
+ cancelAnimationFrame(frame);
2611
+ frame = undefined;
2612
+ }
2613
+ if (timer !== undefined) {
2614
+ clearTimeout(timer);
2615
+ timer = undefined;
2616
+ }
2617
+ };
2618
+ const complete = (open, currentVersion) => {
2619
+ if (currentVersion !== version) {
2620
+ return;
2621
+ }
2622
+ clearTimers();
2623
+ status.set(undefined);
2624
+ if (!destroyRef.destroyed) {
2625
+ onComplete(open);
2626
+ }
2627
+ };
2628
+ const waitForTransition = (open, currentVersion) => {
2629
+ const node = element;
2630
+ const duration = node ? getMaxTransitionDuration(node) : 0;
2631
+ // Nothing animating (also the SSR / jsdom path, where computed durations are
2632
+ // 0): settle synchronously, exactly as before.
2633
+ if (!node || duration === 0) {
2634
+ complete(open, currentVersion);
2635
+ return;
2636
+ }
2637
+ // Prefer the Web Animations API so completion lands on the real
2638
+ // `animationend` / `transitionend` instead of a timer that can fire a frame
2639
+ // late — that lateness is what let a closing collapsible flash back to its
2640
+ // natural size before `hidden` was applied.
2641
+ const animations = typeof node.getAnimations === 'function' ? node.getAnimations() : [];
2642
+ // Safety net: if an animation never settles (interrupted, replaced without a
2643
+ // cancel event, reduced motion, or simply not exposed by the engine yet)
2644
+ // still complete shortly after the declared duration.
2645
+ timer = setTimeout(() => complete(open, currentVersion), duration + TRANSITION_FALLBACK_BUFFER);
2646
+ if (animations.length === 0) {
2647
+ return;
2648
+ }
2649
+ // A cancelled animation rejects `finished`; swallow it so reopening (which
2650
+ // cancels the in-flight animation) still resolves and settles.
2651
+ void Promise.all(animations.map((animation) => animation.finished.catch(() => undefined))).then(() => complete(open, currentVersion));
2652
+ };
2653
+ destroyRef.onDestroy(clearTimers);
2654
+ return {
2655
+ status: status.asReadonly(),
2656
+ registerElement: (registered) => {
2657
+ element = registered;
2658
+ return () => {
2659
+ if (element === registered) {
2660
+ element = undefined;
2661
+ }
2662
+ };
2663
+ },
2664
+ start: (open) => {
2665
+ const currentVersion = ++version;
2666
+ clearTimers();
2667
+ status.set(open ? 'starting' : 'ending');
2668
+ afterNextRender(() => {
2669
+ if (destroyRef.destroyed || currentVersion !== version) {
2670
+ return;
2671
+ }
2672
+ if (open) {
2673
+ frame = requestAnimationFrame(() => {
2674
+ frame = undefined;
2675
+ if (destroyRef.destroyed || currentVersion !== version) {
2676
+ return;
2677
+ }
2678
+ status.set(undefined);
2679
+ waitForTransition(open, currentVersion);
2680
+ });
2681
+ }
2682
+ else {
2683
+ waitForTransition(open, currentVersion);
2684
+ }
2685
+ }, { injector });
2686
+ }
2687
+ };
2688
+ }
2689
+ /** Longest of an element's CSS transition / animation durations (including delays), in milliseconds. */
2690
+ function getMaxTransitionDuration(element) {
2691
+ const styles = getComputedStyle(element);
2692
+ return Math.max(getMaxCssDuration(styles.transitionDuration, styles.transitionDelay), getMaxCssDuration(styles.animationDuration, styles.animationDelay));
2693
+ }
2694
+ function getMaxCssDuration(durations, delays) {
2695
+ const parsedDurations = durations.split(',').map(parseCssTime);
2696
+ const parsedDelays = delays.split(',').map(parseCssTime);
2697
+ return parsedDurations.reduce((max, duration, index) => Math.max(max, duration + parsedDelays[index % parsedDelays.length]), 0);
2698
+ }
2699
+ function parseCssTime(value) {
2700
+ const trimmed = value.trim();
2701
+ const parsed = Number.parseFloat(trimmed);
2702
+ if (!Number.isFinite(parsed)) {
2703
+ return 0;
2704
+ }
2705
+ return trimmed.endsWith('ms') ? parsed : parsed * 1000;
2619
2706
  }
2620
2707
 
2621
2708
  // https://ngxtension.netlify.app/utilities/signals/explicit-effect/
@@ -2655,9 +2742,23 @@ function watch(deps, fn, options) {
2655
2742
  }, options);
2656
2743
  }
2657
2744
 
2745
+ var RdxPositionSide;
2746
+ (function (RdxPositionSide) {
2747
+ RdxPositionSide["Top"] = "top";
2748
+ RdxPositionSide["Right"] = "right";
2749
+ RdxPositionSide["Bottom"] = "bottom";
2750
+ RdxPositionSide["Left"] = "left";
2751
+ })(RdxPositionSide || (RdxPositionSide = {}));
2752
+ var RdxPositionAlign;
2753
+ (function (RdxPositionAlign) {
2754
+ RdxPositionAlign["Start"] = "start";
2755
+ RdxPositionAlign["Center"] = "center";
2756
+ RdxPositionAlign["End"] = "end";
2757
+ })(RdxPositionAlign || (RdxPositionAlign = {}));
2758
+
2658
2759
  /**
2659
2760
  * Generated bundle index. Do not edit.
2660
2761
  */
2661
2762
 
2662
- export { A, ALT, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, ARROW_UP, ASTERISK, BACKSPACE, CAPS_LOCK, CONTROL, CTRL, DELETE, END, ENTER, ESCAPE, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, HOME, META, P, PAGE_DOWN, PAGE_UP, RDX_POSITIONING_DEFAULTS, RDX_POSITIONS, RdxAutoFocusDirective, RdxControlValueAccessor, RdxFocusInitialDirective, RdxPositionAlign, RdxPositionSide, SHIFT, SPACE, SPACE_CODE, TAB, WINDOW, _IdGenerator, a, areAllDaysBetweenValid, clamp, createContent, createContext, createFormatter, createMonth, createMonths, elementSize, getActiveElement, getAllPossibleConnectedPositions, getArrowPositionParams, getContentPosition, getDaysBetween, getDaysInMonth, getDefaultDate, getDefaultTime, getLastFirstDayOfWeek, getNextLastDayOfWeek, getOptsByGranularity, getPlaceholder, getSegmentElements, getSideAndAlignFromAllPossibleConnectedPositions, getWeekNumber, handleAndDispatchCustomEvent, handleCalendarInitialFocus, hasTime, initializeSegmentValues, injectControlValueAccessor, injectDocument, injectIsClient, injectNgControl, injectWindow, isAcceptableSegmentKey, isAfter, isAfterOrSame, isBefore, isBeforeOrSame, isBetween, isBetweenInclusive, isCalendarDateTime, isEqual, isInsideForm, isNullish, isNumber, isNumberString, isSegmentNavigationKey, isValueEqualOrExist, isZonedDateTime, j, k, n, normalizeDateStep, normalizeHour12, normalizeHourCycle, p, provideToken, provideValueAccessor, resizeEffect, roundToStepPrecision, segmentBuilders, snapValueToStep, syncSegmentValues, syncTimeSegmentValues, toDate, useArrowNavigation, useDateField, watch };
2763
+ export { A, ALT, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, ARROW_UP, ASTERISK, BACKSPACE, CAPS_LOCK, CONTROL, CTRL, DELETE, END, ENTER, ESCAPE, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, HOME, META, P, PAGE_DOWN, PAGE_UP, RdxControlValueAccessor, RdxIdGenerator, RdxLiveAnnouncer, RdxPositionAlign, RdxPositionSide, SHIFT, SPACE, SPACE_CODE, TAB, a, areAllDaysBetweenValid, clamp, createContent, createContext, createFormatter, createMonth, createMonths, elementSize, getActiveElement, getDaysBetween, getDaysInMonth, getDefaultDate, getDefaultTime, getLastFirstDayOfWeek, getMaxTransitionDuration, getNextLastDayOfWeek, getOptsByGranularity, getPlaceholder, getSegmentElements, getWeekNumber, handleAndDispatchCustomEvent, handleCalendarInitialFocus, hasTime, initializeSegmentValues, injectControlValueAccessor, injectDocument, injectId, isAcceptableSegmentKey, isAfter, isAfterOrSame, isBefore, isBeforeOrSame, isBetween, isBetweenInclusive, isCalendarDateTime, isEqual, isNullish, isNumberString, isSegmentNavigationKey, isZonedDateTime, j, k, n, normalizeDateStep, normalizeHour12, normalizeHourCycle, p, provideToken, provideValueAccessor, resizeEffect, roundToStepPrecision, segmentBuilders, snapValueToStep, syncSegmentValues, syncTimeSegmentValues, toDate, useArrowNavigation, useDateField, useGraceArea, usePointerDrag, useScrollLock, useTransitionStatus, watch };
2663
2764
  //# sourceMappingURL=radix-ng-primitives-core.mjs.map