@cdevhub/ngx-tw 0.4.0 → 0.6.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 (209) hide show
  1. package/README.md +78 -15
  2. package/fesm2022/cdevhub-ngx-tw-accordion.mjs +16 -5
  3. package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
  4. package/fesm2022/cdevhub-ngx-tw-avatar.mjs +26 -15
  5. package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
  6. package/fesm2022/cdevhub-ngx-tw-badge.mjs +17 -5
  7. package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
  8. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +27 -6
  9. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
  10. package/fesm2022/cdevhub-ngx-tw-button.mjs +23 -11
  11. package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
  12. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +5 -5
  13. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
  14. package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +3 -3
  15. package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -1
  16. package/fesm2022/cdevhub-ngx-tw-calendar.mjs +427 -122
  17. package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
  18. package/fesm2022/cdevhub-ngx-tw-card.mjs +21 -11
  19. package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
  20. package/fesm2022/cdevhub-ngx-tw-carousel.mjs +215 -96
  21. package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
  22. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +108 -64
  23. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
  24. package/fesm2022/cdevhub-ngx-tw-code-block.mjs +18 -6
  25. package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
  26. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +55 -30
  27. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
  28. package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs +218 -0
  29. package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs.map +1 -0
  30. package/fesm2022/cdevhub-ngx-tw-combobox.mjs +236 -211
  31. package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
  32. package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs +200 -0
  33. package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs.map +1 -0
  34. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +34 -7
  35. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
  36. package/fesm2022/cdevhub-ngx-tw-core.mjs +135 -15
  37. package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
  38. package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs +203 -0
  39. package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs.map +1 -0
  40. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +160 -102
  41. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
  42. package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs +209 -0
  43. package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs.map +1 -0
  44. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +182 -107
  45. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
  46. package/fesm2022/cdevhub-ngx-tw-dialog-dialog-renderer-DoIhoV3d.mjs +198 -0
  47. package/fesm2022/cdevhub-ngx-tw-dialog-dialog-renderer-DoIhoV3d.mjs.map +1 -0
  48. package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs +122 -0
  49. package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs.map +1 -0
  50. package/fesm2022/cdevhub-ngx-tw-dialog.mjs +199 -220
  51. package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
  52. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +1 -1
  53. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
  54. package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs +149 -0
  55. package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs.map +1 -0
  56. package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +57 -67
  57. package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -1
  58. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +42 -24
  59. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
  60. package/fesm2022/cdevhub-ngx-tw-form-field.mjs +114 -21
  61. package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
  62. package/fesm2022/cdevhub-ngx-tw-icon.mjs +16 -6
  63. package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
  64. package/fesm2022/cdevhub-ngx-tw-input.mjs +52 -61
  65. package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
  66. package/fesm2022/cdevhub-ngx-tw-item.mjs +18 -3
  67. package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
  68. package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs +168 -0
  69. package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs.map +1 -0
  70. package/fesm2022/cdevhub-ngx-tw-menu.mjs +58 -21
  71. package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
  72. package/fesm2022/cdevhub-ngx-tw-number-input.mjs +34 -1
  73. package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -1
  74. package/fesm2022/cdevhub-ngx-tw-paginator.mjs +95 -45
  75. package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
  76. package/fesm2022/cdevhub-ngx-tw-popover.mjs +81 -32
  77. package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
  78. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +1 -1
  79. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
  80. package/fesm2022/cdevhub-ngx-tw-radio.mjs +131 -98
  81. package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
  82. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +207 -42
  83. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
  84. package/fesm2022/cdevhub-ngx-tw-select-testing.mjs +165 -0
  85. package/fesm2022/cdevhub-ngx-tw-select-testing.mjs.map +1 -0
  86. package/fesm2022/cdevhub-ngx-tw-select.mjs +386 -210
  87. package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
  88. package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs +256 -0
  89. package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs.map +1 -0
  90. package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs +129 -0
  91. package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs.map +1 -0
  92. package/fesm2022/cdevhub-ngx-tw-sheet.mjs +197 -278
  93. package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
  94. package/fesm2022/cdevhub-ngx-tw-slider.mjs +89 -54
  95. package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
  96. package/fesm2022/cdevhub-ngx-tw-sort.mjs +122 -17
  97. package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
  98. package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -19
  99. package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
  100. package/fesm2022/cdevhub-ngx-tw-stat.mjs +63 -25
  101. package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
  102. package/fesm2022/cdevhub-ngx-tw-stepper.mjs +35 -8
  103. package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
  104. package/fesm2022/cdevhub-ngx-tw-switch.mjs +54 -48
  105. package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
  106. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +12 -15
  107. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
  108. package/fesm2022/cdevhub-ngx-tw-table.mjs +74 -13
  109. package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
  110. package/fesm2022/cdevhub-ngx-tw-tabs.mjs +84 -30
  111. package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
  112. package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs +172 -0
  113. package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs.map +1 -0
  114. package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +107 -71
  115. package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -1
  116. package/fesm2022/cdevhub-ngx-tw-textarea.mjs +41 -9
  117. package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
  118. package/fesm2022/cdevhub-ngx-tw-theme.mjs +257 -45
  119. package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
  120. package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs +201 -0
  121. package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs.map +1 -0
  122. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +184 -77
  123. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
  124. package/fesm2022/cdevhub-ngx-tw-timeline.mjs +110 -27
  125. package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
  126. package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs +616 -0
  127. package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs.map +1 -0
  128. package/fesm2022/cdevhub-ngx-tw-toast.mjs +556 -945
  129. package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
  130. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +102 -15
  131. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
  132. package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs +219 -0
  133. package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs.map +1 -0
  134. package/fesm2022/cdevhub-ngx-tw-transfer.mjs +88 -69
  135. package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -1
  136. package/fesm2022/cdevhub-ngx-tw-tree.mjs +68 -19
  137. package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -1
  138. package/index.json +1 -1
  139. package/package.json +63 -2
  140. package/theme/_base.css +13 -0
  141. package/theme/_dark.css +110 -36
  142. package/theme/_high-contrast-dark.css +367 -0
  143. package/theme/_high-contrast.css +13 -2
  144. package/theme/_light.css +276 -0
  145. package/theme/_semantic.css +47 -12
  146. package/theme/_typography.css +17 -0
  147. package/theme/index.css +86 -7
  148. package/types/cdevhub-ngx-tw-accordion.d.ts +12 -4
  149. package/types/cdevhub-ngx-tw-avatar.d.ts +10 -3
  150. package/types/cdevhub-ngx-tw-button.d.ts +1 -0
  151. package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +2 -2
  152. package/types/cdevhub-ngx-tw-calendar-testing.d.ts +1 -1
  153. package/types/cdevhub-ngx-tw-calendar.d.ts +179 -73
  154. package/types/cdevhub-ngx-tw-card.d.ts +11 -3
  155. package/types/cdevhub-ngx-tw-carousel.d.ts +89 -20
  156. package/types/cdevhub-ngx-tw-checkbox.d.ts +40 -12
  157. package/types/cdevhub-ngx-tw-code-block.d.ts +11 -2
  158. package/types/cdevhub-ngx-tw-collapsible.d.ts +32 -5
  159. package/types/cdevhub-ngx-tw-combobox-testing.d.ts +157 -0
  160. package/types/cdevhub-ngx-tw-combobox.d.ts +94 -53
  161. package/types/cdevhub-ngx-tw-command-palette-testing.d.ts +136 -0
  162. package/types/cdevhub-ngx-tw-command-palette.d.ts +33 -5
  163. package/types/cdevhub-ngx-tw-core.d.ts +152 -21
  164. package/types/cdevhub-ngx-tw-date-picker-testing.d.ts +141 -0
  165. package/types/cdevhub-ngx-tw-date-picker.d.ts +37 -29
  166. package/types/cdevhub-ngx-tw-date-range-picker-testing.d.ts +148 -0
  167. package/types/cdevhub-ngx-tw-date-range-picker.d.ts +36 -29
  168. package/types/cdevhub-ngx-tw-dialog-testing.d.ts +98 -0
  169. package/types/cdevhub-ngx-tw-dialog.d.ts +89 -19
  170. package/types/cdevhub-ngx-tw-file-upload-testing.d.ts +120 -0
  171. package/types/cdevhub-ngx-tw-file-upload.d.ts +8 -10
  172. package/types/cdevhub-ngx-tw-flip-card.d.ts +18 -11
  173. package/types/cdevhub-ngx-tw-form-field.d.ts +19 -2
  174. package/types/cdevhub-ngx-tw-icon.d.ts +3 -3
  175. package/types/cdevhub-ngx-tw-input.d.ts +5 -8
  176. package/types/cdevhub-ngx-tw-item.d.ts +2 -0
  177. package/types/cdevhub-ngx-tw-menu-testing.d.ts +131 -0
  178. package/types/cdevhub-ngx-tw-menu.d.ts +2 -2
  179. package/types/cdevhub-ngx-tw-number-input.d.ts +20 -0
  180. package/types/cdevhub-ngx-tw-paginator.d.ts +58 -24
  181. package/types/cdevhub-ngx-tw-popover.d.ts +41 -10
  182. package/types/cdevhub-ngx-tw-progress-bar.d.ts +1 -1
  183. package/types/cdevhub-ngx-tw-radio.d.ts +68 -25
  184. package/types/cdevhub-ngx-tw-segmented-control.d.ts +79 -16
  185. package/types/cdevhub-ngx-tw-select-testing.d.ts +114 -0
  186. package/types/cdevhub-ngx-tw-select.d.ts +104 -33
  187. package/types/cdevhub-ngx-tw-sheet-testing.d.ts +104 -0
  188. package/types/cdevhub-ngx-tw-sheet.d.ts +96 -21
  189. package/types/cdevhub-ngx-tw-slider.d.ts +79 -25
  190. package/types/cdevhub-ngx-tw-sort.d.ts +45 -4
  191. package/types/cdevhub-ngx-tw-split.d.ts +32 -2
  192. package/types/cdevhub-ngx-tw-stat.d.ts +14 -4
  193. package/types/cdevhub-ngx-tw-stepper.d.ts +16 -2
  194. package/types/cdevhub-ngx-tw-switch.d.ts +35 -13
  195. package/types/cdevhub-ngx-tw-tab-nav.d.ts +7 -6
  196. package/types/cdevhub-ngx-tw-table.d.ts +53 -10
  197. package/types/cdevhub-ngx-tw-tabs.d.ts +41 -10
  198. package/types/cdevhub-ngx-tw-tags-input-testing.d.ts +135 -0
  199. package/types/cdevhub-ngx-tw-tags-input.d.ts +26 -11
  200. package/types/cdevhub-ngx-tw-textarea.d.ts +3 -2
  201. package/types/cdevhub-ngx-tw-theme.d.ts +245 -39
  202. package/types/cdevhub-ngx-tw-time-picker-testing.d.ts +129 -0
  203. package/types/cdevhub-ngx-tw-time-picker.d.ts +76 -19
  204. package/types/cdevhub-ngx-tw-timeline.d.ts +36 -12
  205. package/types/cdevhub-ngx-tw-toast.d.ts +61 -12
  206. package/types/cdevhub-ngx-tw-tooltip.d.ts +28 -6
  207. package/types/cdevhub-ngx-tw-transfer-testing.d.ts +152 -0
  208. package/types/cdevhub-ngx-tw-transfer.d.ts +21 -8
  209. package/types/cdevhub-ngx-tw-tree.d.ts +6 -1
@@ -0,0 +1,616 @@
1
+ import * as i0 from '@angular/core';
2
+ import { signal, inject, Injector, ElementRef, DestroyRef, computed, TemplateRef, untracked, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { Overlay, createGlobalPositionStrategy } from '@angular/cdk/overlay';
4
+ import { CdkPortalOutlet, ComponentPortal } from '@angular/cdk/portal';
5
+ import { NgTemplateOutlet } from '@angular/common';
6
+ import { LiveAnnouncer } from '@angular/cdk/a11y';
7
+ import { TW_TOAST_REF, TW_TOAST_DATA, ToastComponent, ToastActionDirective } from './cdevhub-ngx-tw-toast.mjs';
8
+
9
+ const POSITION_AXIS = {
10
+ 'top-right': 'right',
11
+ 'bottom-right': 'right',
12
+ 'top-left': 'left',
13
+ 'bottom-left': 'left',
14
+ 'top-center': 'top',
15
+ 'bottom-center': 'bottom',
16
+ };
17
+ const POSITION_HOST_CLASSES = {
18
+ 'top-right': 'items-end',
19
+ 'bottom-right': 'items-end',
20
+ 'top-left': 'items-start',
21
+ 'bottom-left': 'items-start',
22
+ 'top-center': 'items-center',
23
+ 'bottom-center': 'items-center',
24
+ };
25
+ const POSITION_ORDER_REVERSED = {
26
+ 'top-right': false,
27
+ 'top-left': false,
28
+ 'top-center': false,
29
+ 'bottom-right': true,
30
+ 'bottom-left': true,
31
+ 'bottom-center': true,
32
+ };
33
+ const SWIPE_DISMISS_FRACTION = 0.4;
34
+ const SWIPE_MAX_OPACITY_FADE = 0.6;
35
+ /**
36
+ * Internal flex-column host rendered inside each per-position CDK overlay.
37
+ * Stacks visible toasts via `@for`, wires pause-on-interaction, Escape
38
+ * dismissal, swipe gestures, and `LiveAnnouncer` announcements.
39
+ *
40
+ * @docs-private
41
+ */
42
+ class ToastContainerComponent {
43
+ /** Per-position stacking anchor. Mutated from {@link ToastService} via `.instance.position.set(...)`. */
44
+ position = signal('bottom-right', /* @ts-ignore */
45
+ ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
46
+ /** Accessible label applied to the `role="region"` host. Mutated from the service on init. */
47
+ regionLabel = signal('Notifications', /* @ts-ignore */
48
+ ...(ngDevMode ? [{ debugName: "regionLabel" }] : /* istanbul ignore next */ []));
49
+ /**
50
+ * Toasts currently assigned to this container. The service pushes toasts
51
+ * into this signal; the container filters by state to drive `animate.leave`.
52
+ */
53
+ visibleRefs = signal([], /* @ts-ignore */
54
+ ...(ngDevMode ? [{ debugName: "visibleRefs" }] : /* istanbul ignore next */ []));
55
+ injector = inject(Injector);
56
+ liveAnnouncer = inject(LiveAnnouncer);
57
+ host = inject((ElementRef));
58
+ /**
59
+ * Teardown for every swipe currently in flight.
60
+ *
61
+ * `swipeSessions` is a WeakMap and the listeners are bound to the toast
62
+ * element, so neither outlives the DOM — but a swipe interrupted by destroy
63
+ * (the toast auto-dismisses mid-drag) would otherwise leave the pointer
64
+ * capture unreleased. Each entry removes its listeners and releases capture.
65
+ */
66
+ activeSwipeTeardowns = new Set();
67
+ /** Per-toast handle into {@link activeSwipeTeardowns}. */
68
+ swipeTeardowns = new WeakMap();
69
+ swipeSessions = new WeakMap();
70
+ constructor() {
71
+ // A toast can auto-dismiss (or the whole container can be torn down) while
72
+ // a drag is still in flight, in which case `onSwipeEnd` never runs.
73
+ inject(DestroyRef).onDestroy(() => {
74
+ for (const teardown of [...this.activeSwipeTeardowns])
75
+ teardown();
76
+ this.activeSwipeTeardowns.clear();
77
+ });
78
+ }
79
+ entries = computed(() => {
80
+ const pos = this.position();
81
+ const axis = POSITION_AXIS[pos];
82
+ const enter = `toast-enter-${axis}`;
83
+ const leave = `toast-leave-${axis}`;
84
+ const refs = this.visibleRefs().filter((ref) => {
85
+ const s = ref.state();
86
+ return s === 'entering' || s === 'visible' || s === 'paused';
87
+ });
88
+ return refs.map((ref) => ({
89
+ ref,
90
+ kind: resolveKind(ref.content()),
91
+ enterClass: enter,
92
+ leaveClass: leave,
93
+ }));
94
+ }, /* @ts-ignore */
95
+ ...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
96
+ orderedEntries = computed(() => {
97
+ const list = this.entries();
98
+ return POSITION_ORDER_REVERSED[this.position()] ? [...list].reverse() : list;
99
+ }, /* @ts-ignore */
100
+ ...(ngDevMode ? [{ debugName: "orderedEntries" }] : /* istanbul ignore next */ []));
101
+ hostClasses = computed(() => {
102
+ const base = 'flex flex-col gap-2 w-full max-w-sm';
103
+ const align = POSITION_HOST_CLASSES[this.position()];
104
+ return `${base} ${align}`;
105
+ }, /* @ts-ignore */
106
+ ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
107
+ /** @internal Called by the service right after attaching a new toast. Runs `LiveAnnouncer`. */
108
+ _announceOpen(ref) {
109
+ const politeness = this.resolvePoliteness(ref);
110
+ if (politeness === 'off')
111
+ return;
112
+ const msg = this.resolveAnnouncementText(ref);
113
+ if (msg)
114
+ this.liveAnnouncer.announce(msg, politeness);
115
+ }
116
+ /** @internal Called by the service when `ref.update()` fires — re-announces with the new severity / content. */
117
+ _announceUpdate(ref) {
118
+ this._announceOpen(ref);
119
+ }
120
+ /** @internal Captures the component instance after `cdkPortalOutlet` attaches. */
121
+ onPortalAttached(ref, attached) {
122
+ if (attached && 'instance' in attached) {
123
+ ref.componentInstance = attached.instance;
124
+ }
125
+ }
126
+ /** @internal Injector factory for component-class content. Provides `TW_TOAST_DATA` + `TW_TOAST_REF`. */
127
+ _createContentInjector(ref) {
128
+ return Injector.create({
129
+ parent: this.injector,
130
+ providers: [
131
+ { provide: TW_TOAST_REF, useValue: ref },
132
+ { provide: TW_TOAST_DATA, useValue: ref.data() },
133
+ ],
134
+ });
135
+ }
136
+ // ── Template helpers ──
137
+ asString(content) {
138
+ return typeof content === 'string' ? content : '';
139
+ }
140
+ asTemplate(content) {
141
+ return content instanceof TemplateRef ? content : null;
142
+ }
143
+ templateContext(ref) {
144
+ return { $implicit: ref.data(), ref };
145
+ }
146
+ panelClassFor(ref) {
147
+ const raw = ref.config.panelClass;
148
+ if (!raw)
149
+ return '';
150
+ return Array.isArray(raw) ? raw.join(' ') : raw;
151
+ }
152
+ // ── Interaction handlers ──
153
+ onPointerEnter(ref) {
154
+ ref._setHovered(true);
155
+ }
156
+ onPointerLeave(ref) {
157
+ ref._setHovered(false);
158
+ }
159
+ onFocusIn(ref) {
160
+ ref._setFocused(true);
161
+ }
162
+ onFocusOut(ref, event) {
163
+ const related = event.relatedTarget;
164
+ const target = event.currentTarget;
165
+ if (related && target && target.contains(related))
166
+ return;
167
+ ref._setFocused(false);
168
+ }
169
+ onEscape(ref, event) {
170
+ event.stopPropagation();
171
+ event.preventDefault();
172
+ ref._dismissWith('manual');
173
+ }
174
+ onSwipeStart(ref, event, el) {
175
+ if (!ref.config.swipeToDismiss)
176
+ return;
177
+ if (event.button !== 0)
178
+ return;
179
+ const target = event.target;
180
+ if (target?.closest('button, a, input, select, textarea, [role="button"]'))
181
+ return;
182
+ const width = el.getBoundingClientRect().width;
183
+ this.swipeSessions.set(ref, {
184
+ pointerId: event.pointerId,
185
+ startX: event.clientX,
186
+ width,
187
+ active: false,
188
+ });
189
+ try {
190
+ el.setPointerCapture(event.pointerId);
191
+ }
192
+ catch {
193
+ // setPointerCapture throws when the pointerId is no longer active, and
194
+ // is absent entirely in jsdom. The swipe still tracks via the listeners
195
+ // below — capture is an enhancement, not a prerequisite. Matches the
196
+ // guards already on both `releasePointerCapture` call sites.
197
+ }
198
+ const onMove = (e) => this.onSwipeMove(ref, e, el);
199
+ const onUp = (e) => this.onSwipeEnd(ref, e, el, onMove, onUp);
200
+ el.addEventListener('pointermove', onMove);
201
+ el.addEventListener('pointerup', onUp);
202
+ el.addEventListener('pointercancel', onUp);
203
+ const teardown = () => {
204
+ el.removeEventListener('pointermove', onMove);
205
+ el.removeEventListener('pointerup', onUp);
206
+ el.removeEventListener('pointercancel', onUp);
207
+ try {
208
+ el.releasePointerCapture(event.pointerId);
209
+ }
210
+ catch {
211
+ /* capture already released, or the element is detached */
212
+ }
213
+ this.swipeSessions.delete(ref);
214
+ this.activeSwipeTeardowns.delete(teardown);
215
+ };
216
+ this.swipeTeardowns.set(ref, teardown);
217
+ this.activeSwipeTeardowns.add(teardown);
218
+ }
219
+ onSwipeMove(ref, event, _el) {
220
+ const session = this.swipeSessions.get(ref);
221
+ if (!session || event.pointerId !== session.pointerId)
222
+ return;
223
+ const dx = event.clientX - session.startX;
224
+ if (!session.active && Math.abs(dx) < 6)
225
+ return;
226
+ session.active = true;
227
+ ref.swipeTransform.set(`translate3d(${dx}px, 0, 0)`);
228
+ const fade = 1 - Math.min(Math.abs(dx) / session.width, 1) * SWIPE_MAX_OPACITY_FADE;
229
+ ref.swipeOpacity.set(fade);
230
+ }
231
+ onSwipeEnd(ref, event, el, onMove, onUp) {
232
+ const session = this.swipeSessions.get(ref);
233
+ el.removeEventListener('pointermove', onMove);
234
+ el.removeEventListener('pointerup', onUp);
235
+ el.removeEventListener('pointercancel', onUp);
236
+ const teardown = this.swipeTeardowns.get(ref);
237
+ if (teardown) {
238
+ this.activeSwipeTeardowns.delete(teardown);
239
+ this.swipeTeardowns.delete(ref);
240
+ }
241
+ if (!session || event.pointerId !== session.pointerId)
242
+ return;
243
+ try {
244
+ el.releasePointerCapture(session.pointerId);
245
+ }
246
+ catch {
247
+ /* no-op */
248
+ }
249
+ this.swipeSessions.delete(ref);
250
+ if (!session.active)
251
+ return;
252
+ const dx = event.clientX - session.startX;
253
+ const threshold = session.width * SWIPE_DISMISS_FRACTION;
254
+ const allowed = this.swipeDirectionAllowed(dx);
255
+ if (Math.abs(dx) >= threshold && allowed) {
256
+ untracked(() => {
257
+ ref.swipeTransform.set(`translate3d(${Math.sign(dx) * session.width * 1.2}px, 0, 0)`);
258
+ ref.swipeOpacity.set(0);
259
+ ref.leaveAnimationOverride.set('fade-out');
260
+ });
261
+ ref._dismissWith('swipe');
262
+ }
263
+ else {
264
+ ref.swipeTransform.set(null);
265
+ ref.swipeOpacity.set(null);
266
+ }
267
+ }
268
+ swipeDirectionAllowed(dx) {
269
+ const pos = this.position();
270
+ if (pos === 'top-right' || pos === 'bottom-right')
271
+ return dx > 0;
272
+ if (pos === 'top-left' || pos === 'bottom-left')
273
+ return dx < 0;
274
+ return true;
275
+ }
276
+ resolvePoliteness(ref) {
277
+ if (ref.config.politeness)
278
+ return ref.config.politeness;
279
+ return ref.severity() === 'error' ? 'assertive' : 'polite';
280
+ }
281
+ resolveAnnouncementText(ref) {
282
+ const explicit = ref.ariaLabel();
283
+ if (explicit)
284
+ return explicit;
285
+ const content = ref.content();
286
+ if (typeof content === 'string')
287
+ return content;
288
+ const host = this.host.nativeElement.querySelector(`[data-toast-id="${ref.id}"]`);
289
+ if (host)
290
+ return host.textContent?.trim() ?? '';
291
+ return this.host.nativeElement.textContent?.trim() ?? '';
292
+ }
293
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: ToastContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
294
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: ToastContainerComponent, isStandalone: true, selector: "tw-toast-container", host: { attributes: { "role": "region" }, properties: { "class": "hostClasses()", "attr.aria-label": "regionLabel()", "attr.data-position": "position()" } }, ngImport: i0, template: `
295
+ @for (entry of orderedEntries(); track entry.ref.id) {
296
+ <!--
297
+ Toast entry wrapper. Owns the keyboard and pointer contract for one toast.
298
+
299
+ Focus policy (SC 2.2.1 Timing Adjustable, SC 2.1.1 Keyboard):
300
+
301
+ - tabindex="0" makes the wrapper itself a tab stop. Auto-dismiss pauses on
302
+ focus-within, so without this a toast whose only affordances are opted
303
+ out (dismissible false, no action) has nothing focusable at all and a
304
+ keyboard-only user can never stop its 5s clock. Radix Toast puts the tab
305
+ stop on the toast root for the same reason.
306
+ - No focus trap. A toast is not modal; trapping would strand a user who
307
+ never asked for it.
308
+ - No autofocus. Moving focus on open would yank the caret out of whatever
309
+ the user was doing, which is worse than the delay it saves.
310
+ - No summon hotkey. Deliberately deferred: a document-level key would have
311
+ to pick one of six position containers, and the region landmark already
312
+ gives screen-reader users a direct route in.
313
+ - Escape dismisses the focused toast; the browser returns focus to the
314
+ document flow position on its own once the element is removed.
315
+
316
+ Pointer and focus events are forwarded to the ref so the container can
317
+ pause the auto-dismiss timer while the user is reading or interacting.
318
+ -->
319
+ <div
320
+ class="pointer-events-auto w-full max-w-sm rounded-lg focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500"
321
+ tabindex="0"
322
+ [attr.data-toast-id]="entry.ref.id"
323
+ [style.transform]="entry.ref.swipeTransform() || null"
324
+ [style.opacity]="entry.ref.swipeOpacity() ?? null"
325
+ [style.touch-action]="'pan-y'"
326
+ [animate.enter]="entry.enterClass"
327
+ [animate.leave]="entry.ref.leaveAnimationOverride() ?? entry.leaveClass"
328
+ (pointerenter)="onPointerEnter(entry.ref)"
329
+ (pointerleave)="onPointerLeave(entry.ref)"
330
+ (focusin)="onFocusIn(entry.ref)"
331
+ (focusout)="onFocusOut(entry.ref, $event)"
332
+ (keydown.escape)="onEscape(entry.ref, $event)"
333
+ (pointerdown)="onSwipeStart(entry.ref, $event, swipeEl)"
334
+ #swipeEl
335
+ >
336
+ @switch (entry.kind) {
337
+ @case ('string') {
338
+ <tw-toast
339
+ [severity]="entry.ref.severity()"
340
+ [dismissible]="entry.ref.dismissible()"
341
+ [icon]="entry.ref.icon()"
342
+ [aria-label]="entry.ref.ariaLabel()"
343
+ [class]="panelClassFor(entry.ref)"
344
+ (dismissed)="entry.ref._dismissWith('manual')"
345
+ (actionClicked)="entry.ref.triggerAction()"
346
+ >
347
+ {{ asString(entry.ref.content()) }}
348
+ @if (entry.ref.action(); as action) {
349
+ <button twToastAction>{{ action.label }}</button>
350
+ }
351
+ </tw-toast>
352
+ }
353
+ @case ('template') {
354
+ <tw-toast
355
+ [severity]="entry.ref.severity()"
356
+ [dismissible]="entry.ref.dismissible()"
357
+ [icon]="entry.ref.icon()"
358
+ [aria-label]="entry.ref.ariaLabel()"
359
+ [class]="panelClassFor(entry.ref)"
360
+ (dismissed)="entry.ref._dismissWith('manual')"
361
+ (actionClicked)="entry.ref.triggerAction()"
362
+ >
363
+ <ng-container
364
+ [ngTemplateOutlet]="asTemplate(entry.ref.content())"
365
+ [ngTemplateOutletContext]="templateContext(entry.ref)"
366
+ />
367
+ @if (entry.ref.action(); as action) {
368
+ <button twToastAction>{{ action.label }}</button>
369
+ }
370
+ </tw-toast>
371
+ }
372
+ @case ('component') {
373
+ <ng-template
374
+ [cdkPortalOutlet]="entry.ref._portal"
375
+ (attached)="onPortalAttached(entry.ref, $event)"
376
+ />
377
+ }
378
+ }
379
+ </div>
380
+ }
381
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "component", type: ToastComponent, selector: "tw-toast", inputs: ["severity", "dismissible", "icon", "aria-label"], outputs: ["dismissed", "actionClicked"] }, { kind: "directive", type: ToastActionDirective, selector: "[twToastAction]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
382
+ }
383
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: ToastContainerComponent, decorators: [{
384
+ type: Component,
385
+ args: [{
386
+ selector: 'tw-toast-container',
387
+ changeDetection: ChangeDetectionStrategy.OnPush,
388
+ encapsulation: ViewEncapsulation.None,
389
+ imports: [NgTemplateOutlet, CdkPortalOutlet, ToastComponent, ToastActionDirective],
390
+ host: {
391
+ role: 'region',
392
+ '[class]': 'hostClasses()',
393
+ '[attr.aria-label]': 'regionLabel()',
394
+ '[attr.data-position]': 'position()',
395
+ },
396
+ template: `
397
+ @for (entry of orderedEntries(); track entry.ref.id) {
398
+ <!--
399
+ Toast entry wrapper. Owns the keyboard and pointer contract for one toast.
400
+
401
+ Focus policy (SC 2.2.1 Timing Adjustable, SC 2.1.1 Keyboard):
402
+
403
+ - tabindex="0" makes the wrapper itself a tab stop. Auto-dismiss pauses on
404
+ focus-within, so without this a toast whose only affordances are opted
405
+ out (dismissible false, no action) has nothing focusable at all and a
406
+ keyboard-only user can never stop its 5s clock. Radix Toast puts the tab
407
+ stop on the toast root for the same reason.
408
+ - No focus trap. A toast is not modal; trapping would strand a user who
409
+ never asked for it.
410
+ - No autofocus. Moving focus on open would yank the caret out of whatever
411
+ the user was doing, which is worse than the delay it saves.
412
+ - No summon hotkey. Deliberately deferred: a document-level key would have
413
+ to pick one of six position containers, and the region landmark already
414
+ gives screen-reader users a direct route in.
415
+ - Escape dismisses the focused toast; the browser returns focus to the
416
+ document flow position on its own once the element is removed.
417
+
418
+ Pointer and focus events are forwarded to the ref so the container can
419
+ pause the auto-dismiss timer while the user is reading or interacting.
420
+ -->
421
+ <div
422
+ class="pointer-events-auto w-full max-w-sm rounded-lg focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500"
423
+ tabindex="0"
424
+ [attr.data-toast-id]="entry.ref.id"
425
+ [style.transform]="entry.ref.swipeTransform() || null"
426
+ [style.opacity]="entry.ref.swipeOpacity() ?? null"
427
+ [style.touch-action]="'pan-y'"
428
+ [animate.enter]="entry.enterClass"
429
+ [animate.leave]="entry.ref.leaveAnimationOverride() ?? entry.leaveClass"
430
+ (pointerenter)="onPointerEnter(entry.ref)"
431
+ (pointerleave)="onPointerLeave(entry.ref)"
432
+ (focusin)="onFocusIn(entry.ref)"
433
+ (focusout)="onFocusOut(entry.ref, $event)"
434
+ (keydown.escape)="onEscape(entry.ref, $event)"
435
+ (pointerdown)="onSwipeStart(entry.ref, $event, swipeEl)"
436
+ #swipeEl
437
+ >
438
+ @switch (entry.kind) {
439
+ @case ('string') {
440
+ <tw-toast
441
+ [severity]="entry.ref.severity()"
442
+ [dismissible]="entry.ref.dismissible()"
443
+ [icon]="entry.ref.icon()"
444
+ [aria-label]="entry.ref.ariaLabel()"
445
+ [class]="panelClassFor(entry.ref)"
446
+ (dismissed)="entry.ref._dismissWith('manual')"
447
+ (actionClicked)="entry.ref.triggerAction()"
448
+ >
449
+ {{ asString(entry.ref.content()) }}
450
+ @if (entry.ref.action(); as action) {
451
+ <button twToastAction>{{ action.label }}</button>
452
+ }
453
+ </tw-toast>
454
+ }
455
+ @case ('template') {
456
+ <tw-toast
457
+ [severity]="entry.ref.severity()"
458
+ [dismissible]="entry.ref.dismissible()"
459
+ [icon]="entry.ref.icon()"
460
+ [aria-label]="entry.ref.ariaLabel()"
461
+ [class]="panelClassFor(entry.ref)"
462
+ (dismissed)="entry.ref._dismissWith('manual')"
463
+ (actionClicked)="entry.ref.triggerAction()"
464
+ >
465
+ <ng-container
466
+ [ngTemplateOutlet]="asTemplate(entry.ref.content())"
467
+ [ngTemplateOutletContext]="templateContext(entry.ref)"
468
+ />
469
+ @if (entry.ref.action(); as action) {
470
+ <button twToastAction>{{ action.label }}</button>
471
+ }
472
+ </tw-toast>
473
+ }
474
+ @case ('component') {
475
+ <ng-template
476
+ [cdkPortalOutlet]="entry.ref._portal"
477
+ (attached)="onPortalAttached(entry.ref, $event)"
478
+ />
479
+ }
480
+ }
481
+ </div>
482
+ }
483
+ `,
484
+ }]
485
+ }], ctorParameters: () => [] });
486
+ function resolveKind(content) {
487
+ if (typeof content === 'string')
488
+ return 'string';
489
+ if (content instanceof TemplateRef)
490
+ return 'template';
491
+ return 'component';
492
+ }
493
+
494
+ const OVERLAY_EDGE_OFFSET = '1rem';
495
+ /**
496
+ * Rendering half of the toast feature: owns the CDK overlays, the per-position
497
+ * {@link ToastContainerComponent} instances, and every `LiveAnnouncer` call.
498
+ *
499
+ * This module is reached only through a dynamic `import()` in `ToastService`,
500
+ * which is what keeps `@angular/cdk/overlay`, the toast components, and
501
+ * `tailwind-variants` out of a consumer's initial bundle. Nothing here may be
502
+ * imported statically from `toast.ts` — a value import (as opposed to a
503
+ * `import type`) would pull the whole graph back into the eager chunk and
504
+ * silently undo the split. See `toast.spec.ts` for the guard test.
505
+ *
506
+ * @docs-private
507
+ */
508
+ class ToastRenderer {
509
+ injector;
510
+ regionAriaLabel;
511
+ overlay;
512
+ positionOverlays = new Map();
513
+ disposed = false;
514
+ constructor(injector, regionAriaLabel) {
515
+ this.injector = injector;
516
+ this.regionAriaLabel = regionAriaLabel;
517
+ // Resolved here rather than injected into `ToastService`, so the `Overlay`
518
+ // symbol lives in this lazily-loaded chunk. It is `providedIn: 'root'`, so
519
+ // no eager provider is required.
520
+ this.overlay = injector.get(Overlay);
521
+ }
522
+ /**
523
+ * Render a toast into its position container, creating the overlay on first
524
+ * use. Returns `false` if the renderer has already been disposed.
525
+ */
526
+ attach(ref, position) {
527
+ if (this.disposed)
528
+ return false;
529
+ const entry = this.getContainerForPosition(position);
530
+ const instance = entry.containerRef.instance;
531
+ // Component-class content needs an injector built from the container, so
532
+ // the portal cannot be created until the container exists.
533
+ const content = ref.content();
534
+ if (isComponentConstructor(content)) {
535
+ ref._portal = new ComponentPortal(content, null, instance._createContentInjector(ref));
536
+ }
537
+ instance.visibleRefs.update((list) => [...list, ref]);
538
+ ref._overlayPanelElement = entry.overlayRef.overlayElement;
539
+ return true;
540
+ }
541
+ /** Announce a freshly attached toast to assistive technology. */
542
+ announceOpen(ref) {
543
+ this.containerFor(ref)?._announceOpen(ref);
544
+ }
545
+ /** Re-announce a toast whose content or severity changed via `update()`. */
546
+ announceUpdate(ref) {
547
+ this.containerFor(ref)?._announceUpdate(ref);
548
+ }
549
+ /** Drop a dismissed toast from its container's render list. */
550
+ detach(ref) {
551
+ const instance = this.containerFor(ref);
552
+ if (!instance)
553
+ return;
554
+ instance.visibleRefs.update((list) => list.filter((r) => r !== ref));
555
+ }
556
+ /** Tear down every overlay this renderer created. */
557
+ dispose() {
558
+ this.disposed = true;
559
+ for (const { overlayRef } of this.positionOverlays.values()) {
560
+ overlayRef.dispose();
561
+ }
562
+ this.positionOverlays.clear();
563
+ }
564
+ containerFor(ref) {
565
+ return this.positionOverlays.get(ref.config.position ?? 'bottom-right')?.containerRef
566
+ .instance;
567
+ }
568
+ getContainerForPosition(position) {
569
+ const existing = this.positionOverlays.get(position);
570
+ if (existing)
571
+ return existing;
572
+ const overlayRef = this.overlay.create({
573
+ positionStrategy: this.buildPositionStrategy(position),
574
+ scrollStrategy: this.overlay.scrollStrategies.noop(),
575
+ hasBackdrop: false,
576
+ panelClass: ['tw-toast-overlay', `tw-toast-overlay-${position}`],
577
+ });
578
+ const containerPortal = new ComponentPortal(ToastContainerComponent, null, this.injector);
579
+ const containerRef = overlayRef.attach(containerPortal);
580
+ containerRef.instance.position.set(position);
581
+ containerRef.instance.regionLabel.set(this.regionAriaLabel);
582
+ const entry = { overlayRef, containerRef };
583
+ this.positionOverlays.set(position, entry);
584
+ return entry;
585
+ }
586
+ buildPositionStrategy(position) {
587
+ const strategy = createGlobalPositionStrategy(this.injector);
588
+ switch (position) {
589
+ case 'top-right':
590
+ strategy.top(OVERLAY_EDGE_OFFSET).right(OVERLAY_EDGE_OFFSET);
591
+ break;
592
+ case 'top-left':
593
+ strategy.top(OVERLAY_EDGE_OFFSET).left(OVERLAY_EDGE_OFFSET);
594
+ break;
595
+ case 'top-center':
596
+ strategy.top(OVERLAY_EDGE_OFFSET).centerHorizontally();
597
+ break;
598
+ case 'bottom-right':
599
+ strategy.bottom(OVERLAY_EDGE_OFFSET).right(OVERLAY_EDGE_OFFSET);
600
+ break;
601
+ case 'bottom-left':
602
+ strategy.bottom(OVERLAY_EDGE_OFFSET).left(OVERLAY_EDGE_OFFSET);
603
+ break;
604
+ case 'bottom-center':
605
+ strategy.bottom(OVERLAY_EDGE_OFFSET).centerHorizontally();
606
+ break;
607
+ }
608
+ return strategy;
609
+ }
610
+ }
611
+ function isComponentConstructor(value) {
612
+ return typeof value === 'function' && !(value instanceof TemplateRef);
613
+ }
614
+
615
+ export { ToastRenderer };
616
+ //# sourceMappingURL=cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs.map