@cdevhub/ngx-tw 0.2.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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +134 -0
  3. package/fesm2022/cdevhub-ngx-tw-accordion.mjs +108 -0
  4. package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -0
  5. package/fesm2022/cdevhub-ngx-tw-alert.mjs +240 -0
  6. package/fesm2022/cdevhub-ngx-tw-alert.mjs.map +1 -0
  7. package/fesm2022/cdevhub-ngx-tw-avatar.mjs +287 -0
  8. package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -0
  9. package/fesm2022/cdevhub-ngx-tw-badge.mjs +332 -0
  10. package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -0
  11. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +452 -0
  12. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -0
  13. package/fesm2022/cdevhub-ngx-tw-button.mjs +227 -0
  14. package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -0
  15. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +417 -0
  16. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -0
  17. package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +232 -0
  18. package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -0
  19. package/fesm2022/cdevhub-ngx-tw-calendar.mjs +4482 -0
  20. package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -0
  21. package/fesm2022/cdevhub-ngx-tw-card.mjs +157 -0
  22. package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -0
  23. package/fesm2022/cdevhub-ngx-tw-carousel.mjs +1454 -0
  24. package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -0
  25. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +593 -0
  26. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -0
  27. package/fesm2022/cdevhub-ngx-tw-code-block.mjs +228 -0
  28. package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -0
  29. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +510 -0
  30. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -0
  31. package/fesm2022/cdevhub-ngx-tw-combobox.mjs +1721 -0
  32. package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -0
  33. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +721 -0
  34. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -0
  35. package/fesm2022/cdevhub-ngx-tw-core.mjs +861 -0
  36. package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -0
  37. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +1558 -0
  38. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -0
  39. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +1833 -0
  40. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -0
  41. package/fesm2022/cdevhub-ngx-tw-dialog.mjs +693 -0
  42. package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -0
  43. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +331 -0
  44. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -0
  45. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +289 -0
  46. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -0
  47. package/fesm2022/cdevhub-ngx-tw-form-field.mjs +572 -0
  48. package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -0
  49. package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs +36 -0
  50. package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs.map +1 -0
  51. package/fesm2022/cdevhub-ngx-tw-icon.mjs +278 -0
  52. package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -0
  53. package/fesm2022/cdevhub-ngx-tw-input.mjs +355 -0
  54. package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -0
  55. package/fesm2022/cdevhub-ngx-tw-item.mjs +241 -0
  56. package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -0
  57. package/fesm2022/cdevhub-ngx-tw-menu.mjs +433 -0
  58. package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -0
  59. package/fesm2022/cdevhub-ngx-tw-paginator.mjs +691 -0
  60. package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -0
  61. package/fesm2022/cdevhub-ngx-tw-popover.mjs +678 -0
  62. package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -0
  63. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +335 -0
  64. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -0
  65. package/fesm2022/cdevhub-ngx-tw-radio.mjs +708 -0
  66. package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -0
  67. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +319 -0
  68. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -0
  69. package/fesm2022/cdevhub-ngx-tw-select.mjs +1722 -0
  70. package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -0
  71. package/fesm2022/cdevhub-ngx-tw-separator.mjs +115 -0
  72. package/fesm2022/cdevhub-ngx-tw-separator.mjs.map +1 -0
  73. package/fesm2022/cdevhub-ngx-tw-sheet.mjs +768 -0
  74. package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -0
  75. package/fesm2022/cdevhub-ngx-tw-skeleton.mjs +149 -0
  76. package/fesm2022/cdevhub-ngx-tw-skeleton.mjs.map +1 -0
  77. package/fesm2022/cdevhub-ngx-tw-slider.mjs +1147 -0
  78. package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -0
  79. package/fesm2022/cdevhub-ngx-tw-sort.mjs +346 -0
  80. package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -0
  81. package/fesm2022/cdevhub-ngx-tw-spinner.mjs +186 -0
  82. package/fesm2022/cdevhub-ngx-tw-spinner.mjs.map +1 -0
  83. package/fesm2022/cdevhub-ngx-tw-split.mjs +1082 -0
  84. package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -0
  85. package/fesm2022/cdevhub-ngx-tw-stat.mjs +579 -0
  86. package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -0
  87. package/fesm2022/cdevhub-ngx-tw-stepper.mjs +443 -0
  88. package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -0
  89. package/fesm2022/cdevhub-ngx-tw-switch.mjs +391 -0
  90. package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -0
  91. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +315 -0
  92. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -0
  93. package/fesm2022/cdevhub-ngx-tw-table.mjs +994 -0
  94. package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -0
  95. package/fesm2022/cdevhub-ngx-tw-tabs.mjs +508 -0
  96. package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -0
  97. package/fesm2022/cdevhub-ngx-tw-textarea.mjs +147 -0
  98. package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -0
  99. package/fesm2022/cdevhub-ngx-tw-theme.mjs +178 -0
  100. package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -0
  101. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +1344 -0
  102. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -0
  103. package/fesm2022/cdevhub-ngx-tw-timeline.mjs +1136 -0
  104. package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -0
  105. package/fesm2022/cdevhub-ngx-tw-toast.mjs +1311 -0
  106. package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -0
  107. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +533 -0
  108. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -0
  109. package/fesm2022/cdevhub-ngx-tw.mjs +61 -0
  110. package/fesm2022/cdevhub-ngx-tw.mjs.map +1 -0
  111. package/package.json +265 -0
  112. package/theme/_base.css +394 -0
  113. package/theme/_dark.css +510 -0
  114. package/theme/_high-contrast.css +290 -0
  115. package/theme/_semantic.css +317 -0
  116. package/theme/_typography.css +9 -0
  117. package/theme/index.css +54 -0
  118. package/types/cdevhub-ngx-tw-accordion.d.ts +48 -0
  119. package/types/cdevhub-ngx-tw-alert.d.ts +67 -0
  120. package/types/cdevhub-ngx-tw-avatar.d.ts +79 -0
  121. package/types/cdevhub-ngx-tw-badge.d.ts +94 -0
  122. package/types/cdevhub-ngx-tw-breadcrumbs.d.ts +227 -0
  123. package/types/cdevhub-ngx-tw-button.d.ts +74 -0
  124. package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +200 -0
  125. package/types/cdevhub-ngx-tw-calendar-testing.d.ts +113 -0
  126. package/types/cdevhub-ngx-tw-calendar.d.ts +1704 -0
  127. package/types/cdevhub-ngx-tw-card.d.ts +48 -0
  128. package/types/cdevhub-ngx-tw-carousel.d.ts +406 -0
  129. package/types/cdevhub-ngx-tw-checkbox.d.ts +136 -0
  130. package/types/cdevhub-ngx-tw-code-block.d.ts +93 -0
  131. package/types/cdevhub-ngx-tw-collapsible.d.ts +151 -0
  132. package/types/cdevhub-ngx-tw-combobox.d.ts +389 -0
  133. package/types/cdevhub-ngx-tw-command-palette.d.ts +215 -0
  134. package/types/cdevhub-ngx-tw-core.d.ts +719 -0
  135. package/types/cdevhub-ngx-tw-date-picker.d.ts +317 -0
  136. package/types/cdevhub-ngx-tw-date-range-picker.d.ts +313 -0
  137. package/types/cdevhub-ngx-tw-dialog.d.ts +303 -0
  138. package/types/cdevhub-ngx-tw-empty-state.d.ts +104 -0
  139. package/types/cdevhub-ngx-tw-flip-card.d.ts +95 -0
  140. package/types/cdevhub-ngx-tw-form-field.d.ts +210 -0
  141. package/types/cdevhub-ngx-tw-icon-lucide.d.ts +29 -0
  142. package/types/cdevhub-ngx-tw-icon.d.ts +134 -0
  143. package/types/cdevhub-ngx-tw-input.d.ts +110 -0
  144. package/types/cdevhub-ngx-tw-item.d.ts +70 -0
  145. package/types/cdevhub-ngx-tw-menu.d.ts +99 -0
  146. package/types/cdevhub-ngx-tw-paginator.d.ts +305 -0
  147. package/types/cdevhub-ngx-tw-popover.d.ts +157 -0
  148. package/types/cdevhub-ngx-tw-progress-bar.d.ts +100 -0
  149. package/types/cdevhub-ngx-tw-radio.d.ts +174 -0
  150. package/types/cdevhub-ngx-tw-segmented-control.d.ts +66 -0
  151. package/types/cdevhub-ngx-tw-select.d.ts +384 -0
  152. package/types/cdevhub-ngx-tw-separator.d.ts +28 -0
  153. package/types/cdevhub-ngx-tw-sheet.d.ts +335 -0
  154. package/types/cdevhub-ngx-tw-skeleton.d.ts +52 -0
  155. package/types/cdevhub-ngx-tw-slider.d.ts +258 -0
  156. package/types/cdevhub-ngx-tw-sort.d.ts +136 -0
  157. package/types/cdevhub-ngx-tw-spinner.d.ts +50 -0
  158. package/types/cdevhub-ngx-tw-split.d.ts +265 -0
  159. package/types/cdevhub-ngx-tw-stat.d.ts +140 -0
  160. package/types/cdevhub-ngx-tw-stepper.d.ts +127 -0
  161. package/types/cdevhub-ngx-tw-switch.d.ts +88 -0
  162. package/types/cdevhub-ngx-tw-tab-nav.d.ts +107 -0
  163. package/types/cdevhub-ngx-tw-table.d.ts +479 -0
  164. package/types/cdevhub-ngx-tw-tabs.d.ts +121 -0
  165. package/types/cdevhub-ngx-tw-textarea.d.ts +62 -0
  166. package/types/cdevhub-ngx-tw-theme.d.ts +106 -0
  167. package/types/cdevhub-ngx-tw-time-picker.d.ts +303 -0
  168. package/types/cdevhub-ngx-tw-timeline.d.ts +278 -0
  169. package/types/cdevhub-ngx-tw-toast.d.ts +388 -0
  170. package/types/cdevhub-ngx-tw-tooltip.d.ts +95 -0
  171. package/types/cdevhub-ngx-tw.d.ts +49 -0
@@ -0,0 +1,678 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, signal, computed, ChangeDetectionStrategy, Component, input, model, output, inject, ElementRef, ViewContainerRef, Injector, DestroyRef, effect, untracked, TemplateRef, Directive } from '@angular/core';
3
+ import { Overlay } from '@angular/cdk/overlay';
4
+ import { CdkPortalOutlet, ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
5
+ import { FocusTrapFactory, _IdGenerator } from '@angular/cdk/a11y';
6
+ import { Subscription } from 'rxjs';
7
+ import { tv } from 'tailwind-variants';
8
+
9
+ /** Injection token providing arbitrary data to popover component content. */
10
+ const POPOVER_DATA = new InjectionToken('POPOVER_DATA');
11
+ /** Injection token providing a `PopoverRef` to popover component content. */
12
+ const POPOVER_REF = new InjectionToken('POPOVER_REF');
13
+
14
+ /** Duration of leave animation in ms (must match _base.css scale-out/fade-out). */
15
+ const ANIMATION_DURATION = 120;
16
+ // ── Variant config ──
17
+ const popoverVariants = tv({
18
+ slots: {
19
+ wrapper: 'relative',
20
+ panel: 'bg-surface-overlay text-fg text-sm border border-border rounded-lg shadow-md overflow-hidden',
21
+ arrow: 'absolute size-2.5 rotate-45 bg-surface-overlay border border-border',
22
+ },
23
+ variants: {
24
+ size: {
25
+ xs: { panel: 'p-2' },
26
+ sm: { panel: 'p-3' },
27
+ md: { panel: 'p-4' },
28
+ lg: { panel: 'p-6' },
29
+ xl: { panel: 'p-8' },
30
+ },
31
+ },
32
+ defaultVariants: { size: 'md' },
33
+ }, { twMerge: true });
34
+ // ── Color accent classes ──
35
+ const COLOR_ACCENT_CLASSES = {
36
+ primary: 'border-t-2 border-t-primary-500',
37
+ secondary: 'border-t-2 border-t-secondary-500',
38
+ accent: 'border-t-2 border-t-accent-500',
39
+ neutral: 'border-t-2 border-t-neutral-500',
40
+ info: 'border-t-2 border-t-info-500',
41
+ success: 'border-t-2 border-t-success-500',
42
+ warning: 'border-t-2 border-t-warning-500',
43
+ error: 'border-t-2 border-t-error-500',
44
+ };
45
+ // ── Position mappings ──
46
+ function buildPositionMap(offset) {
47
+ return {
48
+ top: {
49
+ originX: 'center',
50
+ originY: 'top',
51
+ overlayX: 'center',
52
+ overlayY: 'bottom',
53
+ offsetY: -offset,
54
+ },
55
+ 'top-start': {
56
+ originX: 'start',
57
+ originY: 'top',
58
+ overlayX: 'start',
59
+ overlayY: 'bottom',
60
+ offsetY: -offset,
61
+ },
62
+ 'top-end': {
63
+ originX: 'end',
64
+ originY: 'top',
65
+ overlayX: 'end',
66
+ overlayY: 'bottom',
67
+ offsetY: -offset,
68
+ },
69
+ bottom: {
70
+ originX: 'center',
71
+ originY: 'bottom',
72
+ overlayX: 'center',
73
+ overlayY: 'top',
74
+ offsetY: offset,
75
+ },
76
+ 'bottom-start': {
77
+ originX: 'start',
78
+ originY: 'bottom',
79
+ overlayX: 'start',
80
+ overlayY: 'top',
81
+ offsetY: offset,
82
+ },
83
+ 'bottom-end': {
84
+ originX: 'end',
85
+ originY: 'bottom',
86
+ overlayX: 'end',
87
+ overlayY: 'top',
88
+ offsetY: offset,
89
+ },
90
+ left: {
91
+ originX: 'start',
92
+ originY: 'center',
93
+ overlayX: 'end',
94
+ overlayY: 'center',
95
+ offsetX: -offset,
96
+ },
97
+ 'left-start': {
98
+ originX: 'start',
99
+ originY: 'top',
100
+ overlayX: 'end',
101
+ overlayY: 'top',
102
+ offsetX: -offset,
103
+ },
104
+ 'left-end': {
105
+ originX: 'start',
106
+ originY: 'bottom',
107
+ overlayX: 'end',
108
+ overlayY: 'bottom',
109
+ offsetX: -offset,
110
+ },
111
+ right: {
112
+ originX: 'end',
113
+ originY: 'center',
114
+ overlayX: 'start',
115
+ overlayY: 'center',
116
+ offsetX: offset,
117
+ },
118
+ 'right-start': {
119
+ originX: 'end',
120
+ originY: 'top',
121
+ overlayX: 'start',
122
+ overlayY: 'top',
123
+ offsetX: offset,
124
+ },
125
+ 'right-end': {
126
+ originX: 'end',
127
+ originY: 'bottom',
128
+ overlayX: 'start',
129
+ overlayY: 'bottom',
130
+ offsetX: offset,
131
+ },
132
+ };
133
+ }
134
+ const FALLBACK_ORDER = {
135
+ top: ['bottom', 'left', 'right'],
136
+ bottom: ['top', 'left', 'right'],
137
+ left: ['right', 'top', 'bottom'],
138
+ right: ['left', 'top', 'bottom'],
139
+ };
140
+ function buildPositions(preferred, offset) {
141
+ const positionMap = buildPositionMap(offset);
142
+ const primary = preferred.split('-')[0];
143
+ const positions = [positionMap[preferred]];
144
+ const fallbacks = FALLBACK_ORDER[primary] ?? FALLBACK_ORDER['top'];
145
+ for (const fb of fallbacks) {
146
+ positions.push(positionMap[fb]);
147
+ }
148
+ return positions;
149
+ }
150
+ function resolveArrowDirection(position) {
151
+ if (position.overlayY === 'bottom')
152
+ return 'bottom';
153
+ if (position.overlayY === 'top')
154
+ return 'top';
155
+ if (position.overlayX === 'end')
156
+ return 'right';
157
+ return 'left';
158
+ }
159
+ /** Arrow position classes keyed by which side the arrow sits on. */
160
+ const ARROW_POSITION_CLASSES = {
161
+ bottom: 'left-1/2 -translate-x-1/2 bottom-0 translate-y-1/2 border-t-0 border-l-0',
162
+ top: 'left-1/2 -translate-x-1/2 top-0 -translate-y-1/2 border-b-0 border-r-0',
163
+ right: 'top-1/2 -translate-y-1/2 right-0 translate-x-1/2 border-b-0 border-l-0',
164
+ left: 'top-1/2 -translate-y-1/2 left-0 -translate-x-1/2 border-t-0 border-r-0',
165
+ };
166
+ // ── Internal overlay component (not exported) ──
167
+ let nextPopoverId = 0;
168
+ class PopoverOverlayComponent {
169
+ id = `tw-popover-${nextPopoverId++}`;
170
+ size = signal('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
171
+ color = signal(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
172
+ showArrow = signal(true, ...(ngDevMode ? [{ debugName: "showArrow" }] : /* istanbul ignore next */ []));
173
+ arrowDirection = signal('top', ...(ngDevMode ? [{ debugName: "arrowDirection" }] : /* istanbul ignore next */ []));
174
+ ariaLabel = signal(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
175
+ ariaModal = signal(true, ...(ngDevMode ? [{ debugName: "ariaModal" }] : /* istanbul ignore next */ []));
176
+ ariaLabelledByQueue = signal([], ...(ngDevMode ? [{ debugName: "ariaLabelledByQueue" }] : /* istanbul ignore next */ []));
177
+ panelClass = signal('', ...(ngDevMode ? [{ debugName: "panelClass" }] : /* istanbul ignore next */ []));
178
+ portal = signal(null, ...(ngDevMode ? [{ debugName: "portal" }] : /* istanbul ignore next */ []));
179
+ computedAriaLabelledBy = computed(() => {
180
+ if (this.ariaLabel())
181
+ return null;
182
+ return this.ariaLabelledByQueue()[0] ?? null;
183
+ }, ...(ngDevMode ? [{ debugName: "computedAriaLabelledBy" }] : /* istanbul ignore next */ []));
184
+ _addAriaLabelledBy(id) {
185
+ this.ariaLabelledByQueue.update((q) => (q.includes(id) ? q : [...q, id]));
186
+ }
187
+ _removeAriaLabelledBy(id) {
188
+ this.ariaLabelledByQueue.update((q) => q.filter((existing) => existing !== id));
189
+ }
190
+ variantResult = computed(() => popoverVariants({ size: this.size() }), ...(ngDevMode ? [{ debugName: "variantResult" }] : /* istanbul ignore next */ []));
191
+ wrapperClasses = computed(() => this.variantResult().wrapper(), ...(ngDevMode ? [{ debugName: "wrapperClasses" }] : /* istanbul ignore next */ []));
192
+ panelClasses = computed(() => {
193
+ const base = this.variantResult().panel();
194
+ const colorClass = this.color() ? COLOR_ACCENT_CLASSES[this.color()] : '';
195
+ const custom = this.panelClass();
196
+ return [base, colorClass, custom].filter(Boolean).join(' ');
197
+ }, ...(ngDevMode ? [{ debugName: "panelClasses" }] : /* istanbul ignore next */ []));
198
+ arrowClasses = computed(() => {
199
+ const base = this.variantResult().arrow();
200
+ const position = ARROW_POSITION_CLASSES[this.arrowDirection()];
201
+ return `${base} ${position}`;
202
+ }, ...(ngDevMode ? [{ debugName: "arrowClasses" }] : /* istanbul ignore next */ []));
203
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PopoverOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
204
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PopoverOverlayComponent, isStandalone: true, selector: "tw-popover-overlay", host: { properties: { "id": "id", "attr.role": "\"dialog\"", "attr.aria-modal": "ariaModal() ? \"true\" : null", "attr.aria-label": "ariaLabel() ?? null", "attr.aria-labelledby": "computedAriaLabelledBy()", "animate.enter": "\"scale-in\"", "animate.leave": "\"scale-out\"" }, classAttribute: "origin-center" }, ngImport: i0, template: `
205
+ <div [class]="wrapperClasses()">
206
+ <div [class]="panelClasses()">
207
+ <ng-template [cdkPortalOutlet]="portal()" />
208
+ </div>
209
+ @if (showArrow()) {
210
+ <span [class]="arrowClasses()" aria-hidden="true"></span>
211
+ }
212
+ </div>
213
+ `, isInline: true, dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
214
+ }
215
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PopoverOverlayComponent, decorators: [{
216
+ type: Component,
217
+ args: [{
218
+ selector: 'tw-popover-overlay',
219
+ changeDetection: ChangeDetectionStrategy.OnPush,
220
+ imports: [CdkPortalOutlet],
221
+ host: {
222
+ class: 'origin-center',
223
+ '[id]': 'id',
224
+ '[attr.role]': '"dialog"',
225
+ '[attr.aria-modal]': 'ariaModal() ? "true" : null',
226
+ '[attr.aria-label]': 'ariaLabel() ?? null',
227
+ '[attr.aria-labelledby]': 'computedAriaLabelledBy()',
228
+ '[animate.enter]': '"scale-in"',
229
+ '[animate.leave]': '"scale-out"',
230
+ },
231
+ template: `
232
+ <div [class]="wrapperClasses()">
233
+ <div [class]="panelClasses()">
234
+ <ng-template [cdkPortalOutlet]="portal()" />
235
+ </div>
236
+ @if (showArrow()) {
237
+ <span [class]="arrowClasses()" aria-hidden="true"></span>
238
+ }
239
+ </div>
240
+ `,
241
+ }]
242
+ }] });
243
+ // ── Popover directive ──
244
+ class PopoverDirective {
245
+ /** The content to render. An `ng-template` receives context with `$implicit` (data) and `close` (function). A component class receives data and a ref via injection tokens. */
246
+ twPopover = input.required(...(ngDevMode ? [{ debugName: "twPopover" }] : /* istanbul ignore next */ []));
247
+ /** Preferred placement relative to the trigger. CDK handles fallback when space is insufficient. Defaults to `'bottom'`. */
248
+ twPopoverPosition = input('bottom', ...(ngDevMode ? [{ debugName: "twPopoverPosition" }] : /* istanbul ignore next */ []));
249
+ /** What user interaction opens the popover. `'manual'` means consumers call `open()`/`close()` programmatically. Defaults to `'click'`. */
250
+ twPopoverTriggerOn = input('click', ...(ngDevMode ? [{ debugName: "twPopoverTriggerOn" }] : /* istanbul ignore next */ []));
251
+ /** When true, all trigger interactions are suppressed. Defaults to `false`. */
252
+ twPopoverDisabled = input(false, ...(ngDevMode ? [{ debugName: "twPopoverDisabled" }] : /* istanbul ignore next */ []));
253
+ /** Two-way bindable open state. Setting to `true` opens the popover; the popover sets it to `false` on close. */
254
+ twPopoverOpen = model(false, ...(ngDevMode ? [{ debugName: "twPopoverOpen" }] : /* istanbul ignore next */ []));
255
+ /** Controls panel padding using the standard spacing scale. Defaults to `'md'`. */
256
+ twPopoverSize = input('md', ...(ngDevMode ? [{ debugName: "twPopoverSize" }] : /* istanbul ignore next */ []));
257
+ /** Pixel distance between trigger and panel edge. Defaults to `8`. */
258
+ twPopoverOffset = input(8, ...(ngDevMode ? [{ debugName: "twPopoverOffset" }] : /* istanbul ignore next */ []));
259
+ // Default true: the panel reads as a floating callout without the arrow; opt-out
260
+ // is intended for compact iconic triggers where the arrow would crowd the layout.
261
+ /** Whether to render a directional arrow pointing at the trigger. Defaults to `true`. */
262
+ twPopoverArrow = input(true, ...(ngDevMode ? [{ debugName: "twPopoverArrow" }] : /* istanbul ignore next */ []));
263
+ /** Backdrop behavior. `'transparent'` catches outside clicks invisibly. `'dimmed'` adds a semi-transparent overlay. `'none'` disables the backdrop. Defaults to `'transparent'`. */
264
+ twPopoverBackdrop = input('transparent', ...(ngDevMode ? [{ debugName: "twPopoverBackdrop" }] : /* istanbul ignore next */ []));
265
+ // Default true: clicking away is the universal dismiss gesture for floating panels;
266
+ // opt-out is for popovers that own multi-step flows the user must complete.
267
+ /** Whether clicking outside the panel closes the popover. Only relevant when backdrop is `'none'`. Defaults to `true`. */
268
+ twPopoverCloseOnOutside = input(true, ...(ngDevMode ? [{ debugName: "twPopoverCloseOnOutside" }] : /* istanbul ignore next */ []));
269
+ // Default true: WAI-ARIA dialog pattern mandates Escape closes; opt-out is for
270
+ // popovers that own a child layer (nested dialog/menu) that should consume Escape first.
271
+ /** Whether pressing Escape closes the popover. Defaults to `true`. */
272
+ twPopoverCloseOnEscape = input(true, ...(ngDevMode ? [{ debugName: "twPopoverCloseOnEscape" }] : /* istanbul ignore next */ []));
273
+ /** CDK scroll strategy for the overlay. Defaults to `'reposition'`. */
274
+ twPopoverScrollStrategy = input('reposition', ...(ngDevMode ? [{ debugName: "twPopoverScrollStrategy" }] : /* istanbul ignore next */ []));
275
+ // Default true: matches the role="dialog" baseline — a focus-trapped panel announces
276
+ // itself as modal-ish; opt-out for inline popovers acting as informational tooltips.
277
+ /** Whether to trap focus inside the popover panel using CDK FocusTrapFactory. Defaults to `true`. */
278
+ twPopoverTrapFocus = input(true, ...(ngDevMode ? [{ debugName: "twPopoverTrapFocus" }] : /* istanbul ignore next */ []));
279
+ /** Arbitrary data passed to template context or component via `POPOVER_DATA` token. */
280
+ twPopoverData = input(undefined, ...(ngDevMode ? [{ debugName: "twPopoverData" }] : /* istanbul ignore next */ []));
281
+ /** Additional CSS classes applied to the overlay panel for consumer customization. */
282
+ twPopoverPanelClass = input('', ...(ngDevMode ? [{ debugName: "twPopoverPanelClass" }] : /* istanbul ignore next */ []));
283
+ /** Optional semantic color. When set, adds a colored top border accent to the panel. */
284
+ twPopoverColor = input(undefined, ...(ngDevMode ? [{ debugName: "twPopoverColor" }] : /* istanbul ignore next */ []));
285
+ /** Explicit `aria-label` for the dialog panel. */
286
+ twPopoverAriaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "twPopoverAriaLabel" }] : /* istanbul ignore next */ []));
287
+ /** Fires after the popover becomes visible. */
288
+ twPopoverOpened = output();
289
+ /** Fires after the popover is fully removed. */
290
+ twPopoverClosed = output();
291
+ overlay = inject(Overlay);
292
+ elementRef = inject((ElementRef));
293
+ viewContainerRef = inject(ViewContainerRef);
294
+ injector = inject(Injector);
295
+ destroyRef = inject(DestroyRef);
296
+ focusTrapFactory = inject(FocusTrapFactory);
297
+ overlayRef = null;
298
+ popoverInstance = null;
299
+ focusTrap = null;
300
+ perOpenSubs = null;
301
+ closing = false;
302
+ closeTimer = null;
303
+ /** Tracked focus-blur close timer; cleared on destroy so it can't fire post-teardown. */
304
+ blurCloseTimer = null;
305
+ overlayId = signal(null, ...(ngDevMode ? [{ debugName: "overlayId" }] : /* istanbul ignore next */ []));
306
+ /** The overlay component's id for aria-controls binding. */
307
+ overlayComponentId = computed(() => this.overlayId(), ...(ngDevMode ? [{ debugName: "overlayComponentId" }] : /* istanbul ignore next */ []));
308
+ constructor() {
309
+ // React to model changes from the parent
310
+ effect(() => {
311
+ const isOpen = this.twPopoverOpen();
312
+ const disabled = this.twPopoverDisabled();
313
+ if (disabled && this.popoverInstance) {
314
+ this.closePopover();
315
+ return;
316
+ }
317
+ if (isOpen && !this.popoverInstance && !disabled && !this.closing) {
318
+ this.openPopover();
319
+ }
320
+ else if (!isOpen && this.popoverInstance) {
321
+ this.closePopover();
322
+ }
323
+ });
324
+ this.destroyRef.onDestroy(() => {
325
+ this.clearCloseTimer();
326
+ if (this.blurCloseTimer !== null) {
327
+ clearTimeout(this.blurCloseTimer);
328
+ this.blurCloseTimer = null;
329
+ }
330
+ this.destroyFocusTrap();
331
+ this.perOpenSubs?.unsubscribe();
332
+ this.disposeOverlay();
333
+ });
334
+ }
335
+ /** Programmatically open the popover. */
336
+ open() {
337
+ if (this.twPopoverDisabled() || this.popoverInstance || this.closing)
338
+ return;
339
+ this.twPopoverOpen.set(true);
340
+ }
341
+ /** Programmatically close the popover. */
342
+ close() {
343
+ if (!this.popoverInstance && !this.closing)
344
+ return;
345
+ this.twPopoverOpen.set(false);
346
+ }
347
+ /** Toggle open/close. */
348
+ toggle() {
349
+ if (this.popoverInstance || this.closing) {
350
+ this.close();
351
+ }
352
+ else {
353
+ this.open();
354
+ }
355
+ }
356
+ /** Force CDK to recalculate overlay position. */
357
+ reposition() {
358
+ this.overlayRef?.updatePosition();
359
+ }
360
+ // ── Host event handlers ──
361
+ onHostClick() {
362
+ if (this.twPopoverTriggerOn() === 'click') {
363
+ this.toggle();
364
+ }
365
+ }
366
+ onHostFocus() {
367
+ if (this.twPopoverTriggerOn() === 'focus') {
368
+ this.open();
369
+ }
370
+ }
371
+ onHostBlur() {
372
+ if (this.twPopoverTriggerOn() === 'focus') {
373
+ if (this.blurCloseTimer !== null)
374
+ clearTimeout(this.blurCloseTimer);
375
+ this.blurCloseTimer = setTimeout(() => {
376
+ this.blurCloseTimer = null;
377
+ const activeEl = document.activeElement;
378
+ const overlayEl = this.overlayRef?.overlayElement;
379
+ if (overlayEl && overlayEl.contains(activeEl))
380
+ return;
381
+ this.close();
382
+ });
383
+ }
384
+ }
385
+ onEscape() {
386
+ if (this.twPopoverCloseOnEscape() && this.popoverInstance) {
387
+ this.close();
388
+ }
389
+ }
390
+ // ── Private ──
391
+ openPopover() {
392
+ this.ensureOverlay();
393
+ this.updatePositionStrategy();
394
+ this.attachContent();
395
+ this.subscribePerOpen();
396
+ this.overlayId.set(this.popoverInstance?.id ?? null);
397
+ this.setupFocusTrap();
398
+ this.twPopoverOpened.emit();
399
+ }
400
+ closePopover() {
401
+ if (this.closing)
402
+ return;
403
+ this.closing = true;
404
+ // Restore focus to the trigger UNLESS the consumer has deliberately moved
405
+ // focus to a different focusable element outside the overlay. We detect
406
+ // that by checking whether the active element is a real focusable target
407
+ // outside the overlay — body/null means focus is "unset" and we should
408
+ // still restore (the typical case after Escape or backdrop click).
409
+ const overlayEl = this.overlayRef?.overlayElement;
410
+ const activeEl = document.activeElement;
411
+ const focusOutsideOverlayIntentionally = !!activeEl &&
412
+ activeEl !== document.body &&
413
+ activeEl !== this.elementRef.nativeElement &&
414
+ !overlayEl?.contains(activeEl);
415
+ // 1. Destroy focus trap so focus can leave
416
+ this.destroyFocusTrap();
417
+ // 2. Return focus to trigger only when appropriate
418
+ if (!focusOutsideOverlayIntentionally) {
419
+ this.elementRef.nativeElement.focus();
420
+ }
421
+ // 3. Wait for leave animation, then detach
422
+ this.closeTimer = setTimeout(() => {
423
+ this.closeTimer = null;
424
+ if (this.overlayRef?.hasAttached()) {
425
+ this.overlayRef.detach();
426
+ }
427
+ this.perOpenSubs?.unsubscribe();
428
+ this.perOpenSubs = null;
429
+ this.popoverInstance = null;
430
+ this.overlayId.set(null);
431
+ // Use untracked to prevent effect re-trigger
432
+ untracked(() => this.twPopoverOpen.set(false));
433
+ this.twPopoverClosed.emit();
434
+ this.closing = false;
435
+ }, ANIMATION_DURATION);
436
+ }
437
+ currentPositionStrategy = null;
438
+ buildPositionStrategy() {
439
+ const positions = buildPositions(this.twPopoverPosition(), this.twPopoverOffset());
440
+ return this.overlay
441
+ .position()
442
+ .flexibleConnectedTo(this.elementRef)
443
+ .withPositions(positions)
444
+ .withFlexibleDimensions(false)
445
+ .withPush(true)
446
+ .withViewportMargin(8);
447
+ }
448
+ ensureOverlay() {
449
+ if (this.overlayRef)
450
+ return;
451
+ const positionStrategy = this.buildPositionStrategy();
452
+ this.currentPositionStrategy = positionStrategy;
453
+ const backdrop = this.twPopoverBackdrop();
454
+ const hasBackdrop = backdrop !== 'none';
455
+ const backdropClass = backdrop === 'dimmed' ? 'bg-black/20' : 'cdk-overlay-transparent-backdrop';
456
+ const scrollStrategy = this.resolveScrollStrategy();
457
+ this.overlayRef = this.overlay.create({
458
+ positionStrategy,
459
+ scrollStrategy,
460
+ hasBackdrop,
461
+ backdropClass,
462
+ panelClass: 'tw-popover-panel',
463
+ });
464
+ }
465
+ updatePositionStrategy() {
466
+ if (!this.overlayRef)
467
+ return;
468
+ const positionStrategy = this.buildPositionStrategy();
469
+ this.currentPositionStrategy = positionStrategy;
470
+ this.overlayRef.updatePositionStrategy(positionStrategy);
471
+ }
472
+ subscribePerOpen() {
473
+ this.perOpenSubs?.unsubscribe();
474
+ this.perOpenSubs = new Subscription();
475
+ const backdrop = this.twPopoverBackdrop();
476
+ const hasBackdrop = backdrop !== 'none';
477
+ // Backdrop click closes
478
+ if (hasBackdrop) {
479
+ this.perOpenSubs.add(this.overlayRef.backdropClick().subscribe(() => this.close()));
480
+ }
481
+ // Outside pointer events when no backdrop
482
+ if (!hasBackdrop && this.twPopoverCloseOnOutside()) {
483
+ this.perOpenSubs.add(this.overlayRef.outsidePointerEvents().subscribe(() => this.close()));
484
+ }
485
+ // Escape from within the overlay
486
+ this.perOpenSubs.add(this.overlayRef.keydownEvents().subscribe((event) => {
487
+ if (event.key === 'Escape' && this.twPopoverCloseOnEscape()) {
488
+ this.close();
489
+ }
490
+ }));
491
+ // Per-open position change subscription — torn down on close to prevent
492
+ // accumulation when the directive is opened/closed many times.
493
+ if (this.currentPositionStrategy) {
494
+ this.perOpenSubs.add(this.currentPositionStrategy.positionChanges.subscribe((change) => {
495
+ if (this.popoverInstance) {
496
+ const dir = resolveArrowDirection(change.connectionPair);
497
+ this.popoverInstance.arrowDirection.set(dir);
498
+ }
499
+ }));
500
+ }
501
+ }
502
+ attachContent() {
503
+ const content = this.twPopover();
504
+ // Attach the internal overlay component
505
+ const overlayPortal = new ComponentPortal(PopoverOverlayComponent, this.viewContainerRef);
506
+ const componentRef = this.overlayRef.attach(overlayPortal);
507
+ this.popoverInstance = componentRef.instance;
508
+ // Configure the overlay component
509
+ this.popoverInstance.size.set(this.twPopoverSize());
510
+ this.popoverInstance.color.set(this.twPopoverColor());
511
+ this.popoverInstance.showArrow.set(this.twPopoverArrow());
512
+ this.popoverInstance.ariaLabel.set(this.twPopoverAriaLabel());
513
+ this.popoverInstance.ariaModal.set(this.twPopoverTrapFocus());
514
+ this.popoverInstance.ariaLabelledByQueue.set([]);
515
+ this.popoverInstance.panelClass.set(this.resolvePanelClass());
516
+ // Provide POPOVER_REF for both template and component content. Title directives
517
+ // call _addAriaLabelledBy / _removeAriaLabelledBy to register their id with the
518
+ // overlay's aria-labelledby queue.
519
+ const overlayInstance = this.popoverInstance;
520
+ const popoverRef = {
521
+ close: () => this.close(),
522
+ _addAriaLabelledBy: (id) => overlayInstance._addAriaLabelledBy(id),
523
+ _removeAriaLabelledBy: (id) => overlayInstance._removeAriaLabelledBy(id),
524
+ };
525
+ // Create the content portal
526
+ if (content instanceof TemplateRef) {
527
+ const context = {
528
+ $implicit: this.twPopoverData(),
529
+ close: () => this.close(),
530
+ };
531
+ const templateInjector = Injector.create({
532
+ parent: this.injector,
533
+ providers: [
534
+ { provide: POPOVER_DATA, useValue: this.twPopoverData() },
535
+ { provide: POPOVER_REF, useValue: popoverRef },
536
+ ],
537
+ });
538
+ const templatePortal = new TemplatePortal(content, this.viewContainerRef, context, templateInjector);
539
+ this.popoverInstance.portal.set(templatePortal);
540
+ }
541
+ else {
542
+ const contentInjector = Injector.create({
543
+ parent: this.injector,
544
+ providers: [
545
+ { provide: POPOVER_DATA, useValue: this.twPopoverData() },
546
+ { provide: POPOVER_REF, useValue: popoverRef },
547
+ ],
548
+ });
549
+ const componentPortal = new ComponentPortal(content, this.viewContainerRef, contentInjector);
550
+ this.popoverInstance.portal.set(componentPortal);
551
+ }
552
+ }
553
+ setupFocusTrap() {
554
+ if (!this.twPopoverTrapFocus() || !this.overlayRef)
555
+ return;
556
+ const overlayEl = this.overlayRef.overlayElement;
557
+ this.focusTrap = this.focusTrapFactory.create(overlayEl);
558
+ this.focusTrap.focusInitialElementWhenReady();
559
+ }
560
+ destroyFocusTrap() {
561
+ this.focusTrap?.destroy();
562
+ this.focusTrap = null;
563
+ }
564
+ disposeOverlay() {
565
+ this.overlayRef?.dispose();
566
+ this.overlayRef = null;
567
+ this.popoverInstance = null;
568
+ }
569
+ clearCloseTimer() {
570
+ if (this.closeTimer !== null) {
571
+ clearTimeout(this.closeTimer);
572
+ this.closeTimer = null;
573
+ }
574
+ }
575
+ resolveScrollStrategy() {
576
+ const strategy = this.twPopoverScrollStrategy();
577
+ switch (strategy) {
578
+ case 'close':
579
+ return this.overlay.scrollStrategies.close();
580
+ case 'block':
581
+ return this.overlay.scrollStrategies.block();
582
+ case 'noop':
583
+ return this.overlay.scrollStrategies.noop();
584
+ default:
585
+ return this.overlay.scrollStrategies.reposition();
586
+ }
587
+ }
588
+ resolvePanelClass() {
589
+ const raw = this.twPopoverPanelClass();
590
+ return Array.isArray(raw) ? raw.join(' ') : raw;
591
+ }
592
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PopoverDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
593
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.14", type: PopoverDirective, isStandalone: true, selector: "[twPopover]", inputs: { twPopover: { classPropertyName: "twPopover", publicName: "twPopover", isSignal: true, isRequired: true, transformFunction: null }, twPopoverPosition: { classPropertyName: "twPopoverPosition", publicName: "twPopoverPosition", isSignal: true, isRequired: false, transformFunction: null }, twPopoverTriggerOn: { classPropertyName: "twPopoverTriggerOn", publicName: "twPopoverTriggerOn", isSignal: true, isRequired: false, transformFunction: null }, twPopoverDisabled: { classPropertyName: "twPopoverDisabled", publicName: "twPopoverDisabled", isSignal: true, isRequired: false, transformFunction: null }, twPopoverOpen: { classPropertyName: "twPopoverOpen", publicName: "twPopoverOpen", isSignal: true, isRequired: false, transformFunction: null }, twPopoverSize: { classPropertyName: "twPopoverSize", publicName: "twPopoverSize", isSignal: true, isRequired: false, transformFunction: null }, twPopoverOffset: { classPropertyName: "twPopoverOffset", publicName: "twPopoverOffset", isSignal: true, isRequired: false, transformFunction: null }, twPopoverArrow: { classPropertyName: "twPopoverArrow", publicName: "twPopoverArrow", isSignal: true, isRequired: false, transformFunction: null }, twPopoverBackdrop: { classPropertyName: "twPopoverBackdrop", publicName: "twPopoverBackdrop", isSignal: true, isRequired: false, transformFunction: null }, twPopoverCloseOnOutside: { classPropertyName: "twPopoverCloseOnOutside", publicName: "twPopoverCloseOnOutside", isSignal: true, isRequired: false, transformFunction: null }, twPopoverCloseOnEscape: { classPropertyName: "twPopoverCloseOnEscape", publicName: "twPopoverCloseOnEscape", isSignal: true, isRequired: false, transformFunction: null }, twPopoverScrollStrategy: { classPropertyName: "twPopoverScrollStrategy", publicName: "twPopoverScrollStrategy", isSignal: true, isRequired: false, transformFunction: null }, twPopoverTrapFocus: { classPropertyName: "twPopoverTrapFocus", publicName: "twPopoverTrapFocus", isSignal: true, isRequired: false, transformFunction: null }, twPopoverData: { classPropertyName: "twPopoverData", publicName: "twPopoverData", isSignal: true, isRequired: false, transformFunction: null }, twPopoverPanelClass: { classPropertyName: "twPopoverPanelClass", publicName: "twPopoverPanelClass", isSignal: true, isRequired: false, transformFunction: null }, twPopoverColor: { classPropertyName: "twPopoverColor", publicName: "twPopoverColor", isSignal: true, isRequired: false, transformFunction: null }, twPopoverAriaLabel: { classPropertyName: "twPopoverAriaLabel", publicName: "twPopoverAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { twPopoverOpen: "twPopoverOpenChange", twPopoverOpened: "twPopoverOpened", twPopoverClosed: "twPopoverClosed" }, host: { listeners: { "click": "onHostClick()", "focus": "onHostFocus()", "blur": "onHostBlur()", "keydown.escape": "onEscape()" }, properties: { "attr.aria-haspopup": "\"dialog\"", "attr.aria-expanded": "twPopoverOpen()", "attr.aria-controls": "overlayComponentId()" } }, exportAs: ["twPopover"], ngImport: i0 });
594
+ }
595
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PopoverDirective, decorators: [{
596
+ type: Directive,
597
+ args: [{
598
+ selector: '[twPopover]',
599
+ exportAs: 'twPopover',
600
+ host: {
601
+ '[attr.aria-haspopup]': '"dialog"',
602
+ '[attr.aria-expanded]': 'twPopoverOpen()',
603
+ '[attr.aria-controls]': 'overlayComponentId()',
604
+ '(click)': 'onHostClick()',
605
+ '(focus)': 'onHostFocus()',
606
+ '(blur)': 'onHostBlur()',
607
+ '(keydown.escape)': 'onEscape()',
608
+ },
609
+ }]
610
+ }], ctorParameters: () => [], propDecorators: { twPopover: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopover", required: true }] }], twPopoverPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverPosition", required: false }] }], twPopoverTriggerOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverTriggerOn", required: false }] }], twPopoverDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverDisabled", required: false }] }], twPopoverOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverOpen", required: false }] }, { type: i0.Output, args: ["twPopoverOpenChange"] }], twPopoverSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverSize", required: false }] }], twPopoverOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverOffset", required: false }] }], twPopoverArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverArrow", required: false }] }], twPopoverBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverBackdrop", required: false }] }], twPopoverCloseOnOutside: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverCloseOnOutside", required: false }] }], twPopoverCloseOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverCloseOnEscape", required: false }] }], twPopoverScrollStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverScrollStrategy", required: false }] }], twPopoverTrapFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverTrapFocus", required: false }] }], twPopoverData: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverData", required: false }] }], twPopoverPanelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverPanelClass", required: false }] }], twPopoverColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverColor", required: false }] }], twPopoverAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "twPopoverAriaLabel", required: false }] }], twPopoverOpened: [{ type: i0.Output, args: ["twPopoverOpened"] }], twPopoverClosed: [{ type: i0.Output, args: ["twPopoverClosed"] }] } });
611
+
612
+ /**
613
+ * Convenience directive that closes the enclosing popover when the host element is clicked.
614
+ * Place on any element inside popover content.
615
+ *
616
+ * ```html
617
+ * <button twPopoverClose>Cancel</button>
618
+ * ```
619
+ */
620
+ class PopoverCloseDirective {
621
+ popoverRef = inject(POPOVER_REF, { optional: true });
622
+ closePopover() {
623
+ this.popoverRef?.close();
624
+ }
625
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PopoverCloseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
626
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.14", type: PopoverCloseDirective, isStandalone: true, selector: "[twPopoverClose]", host: { listeners: { "click": "closePopover()" }, properties: { "attr.type": "\"button\"" } }, ngImport: i0 });
627
+ }
628
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PopoverCloseDirective, decorators: [{
629
+ type: Directive,
630
+ args: [{
631
+ selector: '[twPopoverClose]',
632
+ host: {
633
+ '(click)': 'closePopover()',
634
+ '[attr.type]': '"button"',
635
+ },
636
+ }]
637
+ }] });
638
+
639
+ /**
640
+ * Popover title. Registers its ID with the enclosing popover overlay's
641
+ * `aria-labelledby` queue so screen readers announce it automatically.
642
+ *
643
+ * Mirrors `DialogTitleDirective` and is the recommended way to label a
644
+ * popover whose content has a heading. Use `twPopoverAriaLabel` when no
645
+ * heading is present.
646
+ */
647
+ class PopoverTitleDirective {
648
+ generatedId = inject(_IdGenerator).getId('tw-popover-title-');
649
+ elementRef = inject(ElementRef);
650
+ popoverRef = inject(POPOVER_REF, { optional: true });
651
+ /** Custom id for the title element. Defaults to a generated unique id. */
652
+ id = input(this.generatedId, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
653
+ ngOnInit() {
654
+ this.popoverRef?._addAriaLabelledBy?.(this.id());
655
+ }
656
+ ngOnDestroy() {
657
+ this.popoverRef?._removeAriaLabelledBy?.(this.id());
658
+ }
659
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PopoverTitleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
660
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.14", type: PopoverTitleDirective, isStandalone: true, selector: "[twPopoverTitle], tw-popover-title", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "id()" }, classAttribute: "text-sm font-semibold text-fg" }, ngImport: i0 });
661
+ }
662
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PopoverTitleDirective, decorators: [{
663
+ type: Directive,
664
+ args: [{
665
+ selector: '[twPopoverTitle], tw-popover-title',
666
+ host: {
667
+ class: 'text-sm font-semibold text-fg',
668
+ '[id]': 'id()',
669
+ },
670
+ }]
671
+ }], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
672
+
673
+ /**
674
+ * Generated bundle index. Do not edit.
675
+ */
676
+
677
+ export { POPOVER_DATA, POPOVER_REF, PopoverCloseDirective, PopoverDirective, PopoverTitleDirective };
678
+ //# sourceMappingURL=cdevhub-ngx-tw-popover.mjs.map