forty-cdk 0.2.0 → 0.3.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 (220) hide show
  1. package/accordion/README.md +122 -0
  2. package/aspect-ratio/README.md +76 -0
  3. package/avatar/README.md +100 -0
  4. package/breadcrumbs/README.md +49 -0
  5. package/breakpoints/README.md +81 -0
  6. package/button/README.md +49 -0
  7. package/calendar/README.md +458 -0
  8. package/carousel/README.md +358 -0
  9. package/checkbox/README.md +146 -0
  10. package/combobox/README.md +535 -0
  11. package/context-menu/README.md +139 -0
  12. package/date-field/README.md +184 -0
  13. package/date-picker/README.md +338 -0
  14. package/dialog/README.md +388 -0
  15. package/disclosure/README.md +114 -0
  16. package/drag-drop/README.md +359 -0
  17. package/drawer/README.md +560 -0
  18. package/dropdown-menu/README.md +176 -0
  19. package/fesm2022/forty-cdk-accordion.mjs +348 -0
  20. package/fesm2022/forty-cdk-accordion.mjs.map +1 -0
  21. package/fesm2022/forty-cdk-aspect-ratio.mjs +74 -0
  22. package/fesm2022/forty-cdk-aspect-ratio.mjs.map +1 -0
  23. package/fesm2022/forty-cdk-avatar.mjs +308 -0
  24. package/fesm2022/forty-cdk-avatar.mjs.map +1 -0
  25. package/fesm2022/forty-cdk-breadcrumbs.mjs +125 -0
  26. package/fesm2022/forty-cdk-breadcrumbs.mjs.map +1 -0
  27. package/fesm2022/forty-cdk-breakpoints.mjs +117 -0
  28. package/fesm2022/forty-cdk-breakpoints.mjs.map +1 -0
  29. package/fesm2022/forty-cdk-button.mjs +134 -0
  30. package/fesm2022/forty-cdk-button.mjs.map +1 -0
  31. package/fesm2022/forty-cdk-calendar.mjs +2034 -0
  32. package/fesm2022/forty-cdk-calendar.mjs.map +1 -0
  33. package/fesm2022/forty-cdk-carousel.mjs +968 -0
  34. package/fesm2022/forty-cdk-carousel.mjs.map +1 -0
  35. package/fesm2022/forty-cdk-checkbox.mjs +226 -0
  36. package/fesm2022/forty-cdk-checkbox.mjs.map +1 -0
  37. package/fesm2022/forty-cdk-combobox.mjs +2596 -0
  38. package/fesm2022/forty-cdk-combobox.mjs.map +1 -0
  39. package/fesm2022/forty-cdk-context-menu.mjs +413 -0
  40. package/fesm2022/forty-cdk-context-menu.mjs.map +1 -0
  41. package/fesm2022/forty-cdk-core.mjs +9022 -0
  42. package/fesm2022/forty-cdk-core.mjs.map +1 -0
  43. package/fesm2022/forty-cdk-date-field.mjs +744 -0
  44. package/fesm2022/forty-cdk-date-field.mjs.map +1 -0
  45. package/fesm2022/forty-cdk-date-picker.mjs +1011 -0
  46. package/fesm2022/forty-cdk-date-picker.mjs.map +1 -0
  47. package/fesm2022/forty-cdk-dialog.mjs +707 -0
  48. package/fesm2022/forty-cdk-dialog.mjs.map +1 -0
  49. package/fesm2022/forty-cdk-disclosure.mjs +190 -0
  50. package/fesm2022/forty-cdk-disclosure.mjs.map +1 -0
  51. package/fesm2022/forty-cdk-drag-drop.mjs +1180 -0
  52. package/fesm2022/forty-cdk-drag-drop.mjs.map +1 -0
  53. package/fesm2022/forty-cdk-drawer.mjs +1641 -0
  54. package/fesm2022/forty-cdk-drawer.mjs.map +1 -0
  55. package/fesm2022/forty-cdk-dropdown-menu.mjs +350 -0
  56. package/fesm2022/forty-cdk-dropdown-menu.mjs.map +1 -0
  57. package/fesm2022/forty-cdk-field.mjs +425 -0
  58. package/fesm2022/forty-cdk-field.mjs.map +1 -0
  59. package/fesm2022/forty-cdk-fieldset.mjs +164 -0
  60. package/fesm2022/forty-cdk-fieldset.mjs.map +1 -0
  61. package/fesm2022/forty-cdk-file-upload.mjs +221 -0
  62. package/fesm2022/forty-cdk-file-upload.mjs.map +1 -0
  63. package/fesm2022/forty-cdk-hover-card.mjs +496 -0
  64. package/fesm2022/forty-cdk-hover-card.mjs.map +1 -0
  65. package/fesm2022/forty-cdk-input.mjs +274 -0
  66. package/fesm2022/forty-cdk-input.mjs.map +1 -0
  67. package/fesm2022/forty-cdk-internationalized-date.mjs +1 -1
  68. package/fesm2022/forty-cdk-internationalized-date.mjs.map +1 -1
  69. package/fesm2022/forty-cdk-listbox.mjs +1279 -0
  70. package/fesm2022/forty-cdk-listbox.mjs.map +1 -0
  71. package/fesm2022/forty-cdk-menu.mjs +1439 -0
  72. package/fesm2022/forty-cdk-menu.mjs.map +1 -0
  73. package/fesm2022/forty-cdk-menubar.mjs +787 -0
  74. package/fesm2022/forty-cdk-menubar.mjs.map +1 -0
  75. package/fesm2022/forty-cdk-meter.mjs +211 -0
  76. package/fesm2022/forty-cdk-meter.mjs.map +1 -0
  77. package/fesm2022/forty-cdk-navigation-menu.mjs +1145 -0
  78. package/fesm2022/forty-cdk-navigation-menu.mjs.map +1 -0
  79. package/fesm2022/forty-cdk-number-input.mjs +559 -0
  80. package/fesm2022/forty-cdk-number-input.mjs.map +1 -0
  81. package/fesm2022/forty-cdk-otp-input.mjs +527 -0
  82. package/fesm2022/forty-cdk-otp-input.mjs.map +1 -0
  83. package/fesm2022/forty-cdk-pagination.mjs +323 -0
  84. package/fesm2022/forty-cdk-pagination.mjs.map +1 -0
  85. package/fesm2022/forty-cdk-pane-resizer.mjs +297 -0
  86. package/fesm2022/forty-cdk-pane-resizer.mjs.map +1 -0
  87. package/fesm2022/forty-cdk-popover.mjs +698 -0
  88. package/fesm2022/forty-cdk-popover.mjs.map +1 -0
  89. package/fesm2022/forty-cdk-progress.mjs +226 -0
  90. package/fesm2022/forty-cdk-progress.mjs.map +1 -0
  91. package/fesm2022/forty-cdk-radio-group.mjs +378 -0
  92. package/fesm2022/forty-cdk-radio-group.mjs.map +1 -0
  93. package/fesm2022/forty-cdk-scroll-area.mjs +640 -0
  94. package/fesm2022/forty-cdk-scroll-area.mjs.map +1 -0
  95. package/fesm2022/forty-cdk-search.mjs +205 -0
  96. package/fesm2022/forty-cdk-search.mjs.map +1 -0
  97. package/fesm2022/forty-cdk-select.mjs +1661 -0
  98. package/fesm2022/forty-cdk-select.mjs.map +1 -0
  99. package/fesm2022/forty-cdk-separator.mjs +82 -0
  100. package/fesm2022/forty-cdk-separator.mjs.map +1 -0
  101. package/fesm2022/forty-cdk-signal-forms.mjs +97 -0
  102. package/fesm2022/forty-cdk-signal-forms.mjs.map +1 -0
  103. package/fesm2022/forty-cdk-slider.mjs +803 -0
  104. package/fesm2022/forty-cdk-slider.mjs.map +1 -0
  105. package/fesm2022/forty-cdk-stepper.mjs +886 -0
  106. package/fesm2022/forty-cdk-stepper.mjs.map +1 -0
  107. package/fesm2022/forty-cdk-switch.mjs +137 -0
  108. package/fesm2022/forty-cdk-switch.mjs.map +1 -0
  109. package/fesm2022/forty-cdk-table.mjs +1518 -0
  110. package/fesm2022/forty-cdk-table.mjs.map +1 -0
  111. package/fesm2022/forty-cdk-tabs.mjs +400 -0
  112. package/fesm2022/forty-cdk-tabs.mjs.map +1 -0
  113. package/fesm2022/forty-cdk-time-field.mjs +593 -0
  114. package/fesm2022/forty-cdk-time-field.mjs.map +1 -0
  115. package/fesm2022/forty-cdk-time-picker.mjs +1013 -0
  116. package/fesm2022/forty-cdk-time-picker.mjs.map +1 -0
  117. package/fesm2022/forty-cdk-toast.mjs +1153 -0
  118. package/fesm2022/forty-cdk-toast.mjs.map +1 -0
  119. package/fesm2022/forty-cdk-toggle.mjs +516 -0
  120. package/fesm2022/forty-cdk-toggle.mjs.map +1 -0
  121. package/fesm2022/forty-cdk-toolbar.mjs +374 -0
  122. package/fesm2022/forty-cdk-toolbar.mjs.map +1 -0
  123. package/fesm2022/forty-cdk-tooltip.mjs +672 -0
  124. package/fesm2022/forty-cdk-tooltip.mjs.map +1 -0
  125. package/fesm2022/forty-cdk-tree.mjs +2007 -0
  126. package/fesm2022/forty-cdk-tree.mjs.map +1 -0
  127. package/fesm2022/forty-cdk-virtualization.mjs +1 -1
  128. package/fesm2022/forty-cdk-virtualization.mjs.map +1 -1
  129. package/fesm2022/forty-cdk.mjs +0 -43310
  130. package/fesm2022/forty-cdk.mjs.map +1 -1
  131. package/field/README.md +97 -0
  132. package/fieldset/README.md +86 -0
  133. package/file-upload/README.md +73 -0
  134. package/hover-card/README.md +171 -0
  135. package/input/README.md +156 -0
  136. package/listbox/README.md +424 -0
  137. package/menu/README.md +181 -0
  138. package/menubar/README.md +140 -0
  139. package/meter/README.md +128 -0
  140. package/navigation-menu/README.md +253 -0
  141. package/number-input/README.md +171 -0
  142. package/otp-input/README.md +198 -0
  143. package/package.json +213 -1
  144. package/pagination/README.md +61 -0
  145. package/pane-resizer/README.md +136 -0
  146. package/popover/README.md +262 -0
  147. package/progress/README.md +115 -0
  148. package/radio-group/README.md +129 -0
  149. package/scroll-area/README.md +184 -0
  150. package/search/README.md +42 -0
  151. package/select/README.md +488 -0
  152. package/separator/README.md +84 -0
  153. package/signal-forms/README.md +72 -0
  154. package/slider/README.md +152 -0
  155. package/stepper/README.md +292 -0
  156. package/switch/README.md +116 -0
  157. package/table/README.md +769 -0
  158. package/tabs/README.md +130 -0
  159. package/time-field/README.md +157 -0
  160. package/time-picker/README.md +172 -0
  161. package/toast/README.md +398 -0
  162. package/toggle/README.md +224 -0
  163. package/toolbar/README.md +109 -0
  164. package/tooltip/README.md +274 -0
  165. package/tree/README.md +708 -0
  166. package/types/forty-cdk-accordion.d.ts +242 -0
  167. package/types/forty-cdk-aspect-ratio.d.ts +59 -0
  168. package/types/forty-cdk-avatar.d.ts +133 -0
  169. package/types/forty-cdk-breadcrumbs.d.ts +92 -0
  170. package/types/forty-cdk-breakpoints.d.ts +141 -0
  171. package/types/forty-cdk-button.d.ts +80 -0
  172. package/types/forty-cdk-calendar.d.ts +914 -0
  173. package/types/forty-cdk-carousel.d.ts +530 -0
  174. package/types/forty-cdk-checkbox.d.ts +141 -0
  175. package/types/forty-cdk-combobox.d.ts +1259 -0
  176. package/types/forty-cdk-context-menu.d.ts +313 -0
  177. package/types/forty-cdk-core.d.ts +5774 -0
  178. package/types/forty-cdk-date-field.d.ts +307 -0
  179. package/types/forty-cdk-date-picker.d.ts +622 -0
  180. package/types/forty-cdk-dialog.d.ts +546 -0
  181. package/types/forty-cdk-disclosure.d.ts +127 -0
  182. package/types/forty-cdk-drag-drop.d.ts +456 -0
  183. package/types/forty-cdk-drawer.d.ts +871 -0
  184. package/types/forty-cdk-dropdown-menu.d.ts +242 -0
  185. package/types/forty-cdk-field.d.ts +236 -0
  186. package/types/forty-cdk-fieldset.d.ts +119 -0
  187. package/types/forty-cdk-file-upload.d.ts +124 -0
  188. package/types/forty-cdk-hover-card.d.ts +320 -0
  189. package/types/forty-cdk-input.d.ts +169 -0
  190. package/types/forty-cdk-internationalized-date.d.ts +1 -1
  191. package/types/forty-cdk-listbox.d.ts +513 -0
  192. package/types/forty-cdk-menu.d.ts +629 -0
  193. package/types/forty-cdk-menubar.d.ts +451 -0
  194. package/types/forty-cdk-meter.d.ts +122 -0
  195. package/types/forty-cdk-navigation-menu.d.ts +514 -0
  196. package/types/forty-cdk-number-input.d.ts +319 -0
  197. package/types/forty-cdk-otp-input.d.ts +248 -0
  198. package/types/forty-cdk-pagination.d.ts +214 -0
  199. package/types/forty-cdk-pane-resizer.d.ts +145 -0
  200. package/types/forty-cdk-popover.d.ts +509 -0
  201. package/types/forty-cdk-progress.d.ts +143 -0
  202. package/types/forty-cdk-radio-group.d.ts +222 -0
  203. package/types/forty-cdk-scroll-area.d.ts +258 -0
  204. package/types/forty-cdk-search.d.ts +142 -0
  205. package/types/forty-cdk-select.d.ts +899 -0
  206. package/types/forty-cdk-separator.d.ts +59 -0
  207. package/types/forty-cdk-signal-forms.d.ts +58 -0
  208. package/types/forty-cdk-slider.d.ts +379 -0
  209. package/types/forty-cdk-stepper.d.ts +650 -0
  210. package/types/forty-cdk-switch.d.ts +87 -0
  211. package/types/forty-cdk-table.d.ts +723 -0
  212. package/types/forty-cdk-tabs.d.ts +235 -0
  213. package/types/forty-cdk-time-field.d.ts +307 -0
  214. package/types/forty-cdk-time-picker.d.ts +578 -0
  215. package/types/forty-cdk-toast.d.ts +598 -0
  216. package/types/forty-cdk-toggle.d.ts +310 -0
  217. package/types/forty-cdk-toolbar.d.ts +217 -0
  218. package/types/forty-cdk-tooltip.d.ts +436 -0
  219. package/types/forty-cdk-tree.d.ts +688 -0
  220. package/types/forty-cdk.d.ts +1 -19743
@@ -0,0 +1,672 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, computed, Injectable, model, input, numberAttribute, booleanAttribute, signal, DestroyRef, Directive, ElementRef, effect } from '@angular/core';
3
+ import { createDefaults, SkipDelayCoordinator, IdGenerator, ANCHORED_POSITIONING_DEFAULTS, injectPrefersReducedMotion, forceCloseWhenDisabled, createHoverIntent, adoptHostId, resolveGraceSide, buildSubmenuGracePolygon, attachPointerGrace, injectOverlayShell, toFloatingPositioner, registerHandle } from 'forty-cdk/core';
4
+
5
+ const FOR_TOOLTIP_CONTEXT = new InjectionToken('FOR_TOOLTIP_CONTEXT');
6
+ function injectTooltipContext(piece) {
7
+ const ctx = inject(FOR_TOOLTIP_CONTEXT, { optional: true });
8
+ if (!ctx) {
9
+ throw new Error(`[forty-cdk/tooltip] ${piece} must be used inside a [forTooltip] element. ` +
10
+ "If it is declared inside an ng-template, DI resolves at the template's declaration site — " +
11
+ 'not where it is stamped (e.g. via ngTemplateOutlet) — so declare the template inside the ' +
12
+ '[forTooltip] root.');
13
+ }
14
+ return ctx;
15
+ }
16
+ /**
17
+ * Resolves the trigger's root context: the explicit reference when the
18
+ * `[forTooltipTrigger]` input carries one, the injected `FOR_TOOLTIP_CONTEXT`
19
+ * otherwise. The orphan error only fires when neither resolves, on first read
20
+ * of the returned signal. Must be called in an injection context.
21
+ */
22
+ function injectTooltipTriggerContext(explicitRoot) {
23
+ const injected = inject(FOR_TOOLTIP_CONTEXT, { optional: true });
24
+ return computed(() => {
25
+ const explicit = explicitRoot();
26
+ if (explicit !== '') {
27
+ return explicit;
28
+ }
29
+ if (injected) {
30
+ return injected;
31
+ }
32
+ throw new Error('[forty-cdk/tooltip] ForTooltipTrigger could not resolve its [forTooltip] root: ' +
33
+ 'no FOR_TOOLTIP_CONTEXT provider is visible and no explicit root reference was passed. ' +
34
+ "If this trigger is declared inside an ng-template, DI resolves at the template's declaration " +
35
+ 'site — not where it is stamped — so either declare the template inside the root or pass the ' +
36
+ 'root explicitly: [forTooltipTrigger]="root" with #root="forTooltip".');
37
+ });
38
+ }
39
+
40
+ /**
41
+ * Library fallback for tooltip defaults, read at the root injector when no
42
+ * consumer has called `provideForTooltipDefaults`. Exported for the shared
43
+ * defaults contract spec; not re-exported from the primitive's public entry.
44
+ */
45
+ const FOR_TOOLTIP_FALLBACK_DEFAULTS = {
46
+ openDelay: 700,
47
+ closeDelay: 300,
48
+ skipDelayDuration: 300,
49
+ side: 'top',
50
+ align: 'center',
51
+ sideOffset: 8,
52
+ collisionPadding: 8,
53
+ showOnOverflow: false,
54
+ hoverableContent: false,
55
+ };
56
+ const { token, provideDefaults } = createDefaults('FOR_TOOLTIP_DEFAULTS', FOR_TOOLTIP_FALLBACK_DEFAULTS);
57
+ /** Token holding the resolved tooltip defaults for the current scope. */
58
+ const FOR_TOOLTIP_DEFAULTS = token;
59
+ /**
60
+ * Per-injector-scope state owned by forty-cdk tooltip. Thin subclass of the
61
+ * shared `SkipDelayCoordinator` bound to this primitive's own DI token, so
62
+ * each call to `provideForTooltipDefaults` re-provides it and the
63
+ * corresponding subtree gets its own skip-delay window, independent from any
64
+ * hover-card scope. Tooltips inject it on construction.
65
+ */
66
+ class TooltipCoordinator extends SkipDelayCoordinator {
67
+ constructor() {
68
+ super(inject(FOR_TOOLTIP_DEFAULTS));
69
+ }
70
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: TooltipCoordinator, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
71
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: TooltipCoordinator, providedIn: 'root' });
72
+ }
73
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: TooltipCoordinator, decorators: [{
74
+ type: Injectable,
75
+ args: [{ providedIn: 'root' }]
76
+ }], ctorParameters: () => [] });
77
+ /**
78
+ * Configures forty-cdk tooltip defaults for this injector scope.
79
+ * Partial overrides inherit unspecified keys from the parent scope (or
80
+ * library defaults at the root). Each call establishes a new
81
+ * coordinator scope: peer tooltips inside the scope share a skip-delay
82
+ * window; tooltips in other scopes don't.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * // application-level
87
+ * bootstrapApplication(App, {
88
+ * providers: [provideForTooltipDefaults({ openDelay: 500 })],
89
+ * });
90
+ *
91
+ * // component-level override (e.g. a toolbar with its own cadence)
92
+ * @Component({
93
+ * providers: [provideForTooltipDefaults({ skipDelayDuration: 100 })],
94
+ * ...
95
+ * })
96
+ * class Toolbar {}
97
+ * ```
98
+ */
99
+ function provideForTooltipDefaults(defaults = {}) {
100
+ return [...provideDefaults(defaults), TooltipCoordinator];
101
+ }
102
+
103
+ /**
104
+ * Headless implementation of the [WAI-ARIA Tooltip pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/).
105
+ *
106
+ * Wrapper directive that owns open / closed state, hover / focus delays, and
107
+ * placement. Provides the shared context to `ForTooltipTrigger`,
108
+ * `ForTooltipContent`, and the optional `ForTooltipArrow`.
109
+ *
110
+ * Tooltip content is portaled to `document.body` and positioned via
111
+ * `@floating-ui/dom`. Per APG, content must NOT be interactive — for
112
+ * interactive popups use a Popover primitive (not yet shipped).
113
+ */
114
+ class ForTooltip {
115
+ #idGen = inject(IdGenerator);
116
+ #defaults = inject(FOR_TOOLTIP_DEFAULTS);
117
+ /**
118
+ * Two-way bindable. Whether the tooltip is currently shown. The `model()`
119
+ * change emitter (`(openChange)`) fires only on internal transitions
120
+ * (hover/focus delays, Escape, and the force-close that runs when `disabled`
121
+ * flips to true), never on consumer writes through `[(open)]` — observe
122
+ * state changes without binding back.
123
+ */
124
+ open = model(false, /* @ts-ignore */
125
+ ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
126
+ /**
127
+ * Per-tooltip override for the side the tooltip is anchored to. Pair with
128
+ * `align` for the full positioning API. When `undefined` (default), falls
129
+ * back to `ForTooltipDefaults.side` from the surrounding
130
+ * `provideForTooltipDefaults` scope (`'top'` unless configured).
131
+ *
132
+ * The input is aliased to `side`; consumers bind `[side]="..."` and read
133
+ * the effective value via the public `side` computed below.
134
+ */
135
+ _sideInput = input(undefined, { ...(ngDevMode ? { debugName: "_sideInput" } : /* istanbul ignore next */ {}), alias: 'side' });
136
+ /** Effective anchor side: the `side` input when set, else the scope default. */
137
+ side = computed(() => this._sideInput() ?? this.#defaults.side, /* @ts-ignore */
138
+ ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
139
+ /**
140
+ * Per-tooltip override for the alignment along the chosen `side`. When
141
+ * `undefined` (default), falls back to `ForTooltipDefaults.align` from the
142
+ * surrounding `provideForTooltipDefaults` scope (`'center'` unless
143
+ * configured).
144
+ *
145
+ * The input is aliased to `align`; consumers bind `[align]="..."` and read
146
+ * the effective value via the public `align` computed below.
147
+ */
148
+ _alignInput = input(undefined, { ...(ngDevMode ? { debugName: "_alignInput" } : /* istanbul ignore next */ {}), alias: 'align' });
149
+ /** Effective alignment: the `align` input when set, else the scope default. */
150
+ align = computed(() => this._alignInput() ?? this.#defaults.align, /* @ts-ignore */
151
+ ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
152
+ /**
153
+ * Per-tooltip override for the gap (px) between trigger and content along
154
+ * the main axis. When `undefined` (default),
155
+ * falls back to `ForTooltipDefaults.sideOffset` from the surrounding
156
+ * `provideForTooltipDefaults` scope (`8` unless configured).
157
+ *
158
+ * The input is aliased to `sideOffset`; consumers bind `[sideOffset]="..."`
159
+ * and read the effective value via the public `sideOffset` computed below.
160
+ */
161
+ _sideOffsetInput = input(undefined, { ...(ngDevMode ? { debugName: "_sideOffsetInput" } : /* istanbul ignore next */ {}), alias: 'sideOffset',
162
+ transform: (v) => (v == null ? undefined : numberAttribute(v)) });
163
+ /** Effective main-axis gap (px): the `sideOffset` input when set, else the scope default. */
164
+ sideOffset = computed(() => this._sideOffsetInput() ?? this.#defaults.sideOffset, /* @ts-ignore */
165
+ ...(ngDevMode ? [{ debugName: "sideOffset" }] : /* istanbul ignore next */ []));
166
+ /** Gap (px) along the cross axis (parallel to `side`). Default `0`. */
167
+ alignOffset = input(ANCHORED_POSITIONING_DEFAULTS.alignOffset, { ...(ngDevMode ? { debugName: "alignOffset" } : /* istanbul ignore next */ {}), transform: numberAttribute });
168
+ /**
169
+ * When `true` (default), `flip` and `shift` keep the tooltip inside the
170
+ * viewport. Disable for strict positioning where overflow is acceptable.
171
+ */
172
+ avoidCollisions = input(ANCHORED_POSITIONING_DEFAULTS.avoidCollisions, { ...(ngDevMode ? { debugName: "avoidCollisions" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
173
+ /**
174
+ * Per-tooltip override for the padding (px) applied uniformly to the
175
+ * `flip`, `shift`, and `size` middlewares. When `undefined` (default),
176
+ * falls back to `ForTooltipDefaults.collisionPadding` from the surrounding
177
+ * `provideForTooltipDefaults` scope (`8` unless configured).
178
+ *
179
+ * The input is aliased to `collisionPadding`; consumers bind
180
+ * `[collisionPadding]="..."` and read the effective value via the public
181
+ * `collisionPadding` computed below.
182
+ */
183
+ _collisionPaddingInput = input(undefined, { ...(ngDevMode ? { debugName: "_collisionPaddingInput" } : /* istanbul ignore next */ {}), alias: 'collisionPadding',
184
+ transform: (v) => (v == null ? undefined : numberAttribute(v)) });
185
+ /** Effective collision padding (px): the `collisionPadding` input when set, else the scope default. */
186
+ collisionPadding = computed(() => this._collisionPaddingInput() ?? this.#defaults.collisionPadding, /* @ts-ignore */
187
+ ...(ngDevMode ? [{ debugName: "collisionPadding" }] : /* istanbul ignore next */ []));
188
+ /** Padding (px) for the `arrow` middleware. Default `0`. */
189
+ arrowPadding = input(ANCHORED_POSITIONING_DEFAULTS.arrowPadding, { ...(ngDevMode ? { debugName: "arrowPadding" } : /* istanbul ignore next */ {}), transform: numberAttribute });
190
+ /**
191
+ * Stickiness behaviour for `shift`. `'partial'` (default) lets the
192
+ * tooltip shift to stay visible. `'always'` keeps the requested
193
+ * placement even off-screen.
194
+ */
195
+ sticky = input(ANCHORED_POSITIONING_DEFAULTS.sticky, /* @ts-ignore */
196
+ ...(ngDevMode ? [{ debugName: "sticky" }] : /* istanbul ignore next */ []));
197
+ /**
198
+ * When `true`, sets `data-detached=""` while the trigger has scrolled
199
+ * off all clipping ancestors.
200
+ */
201
+ hideWhenDetached = input(ANCHORED_POSITIONING_DEFAULTS.hideWhenDetached, { ...(ngDevMode ? { debugName: "hideWhenDetached" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
202
+ /**
203
+ * When `true` (default), the content is clipped until floating-ui resolves
204
+ * its first position, preventing a flash at the viewport corner. Set to
205
+ * `false` so a dramatic `animate.enter` plays from its first frame (the
206
+ * surface may flash briefly at the unresolved position while positioning
207
+ * computes).
208
+ */
209
+ clipUntilPositioned = input(ANCHORED_POSITIONING_DEFAULTS.clipUntilPositioned, { ...(ngDevMode ? { debugName: "clipUntilPositioned" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
210
+ /**
211
+ * Per-tooltip override for the open delay (ms). When `undefined`
212
+ * (default), falls back to `ForTooltipDefaults.openDelay` from the
213
+ * surrounding `provideForTooltipDefaults` scope (700ms unless configured).
214
+ */
215
+ openDelay = input(undefined, /* @ts-ignore */
216
+ ...(ngDevMode ? [{ debugName: "openDelay" }] : /* istanbul ignore next */ []));
217
+ /**
218
+ * Per-tooltip override for the close delay (ms) after hover or focus
219
+ * leaves. `Escape` ignores this. When `undefined` (default), falls back to
220
+ * `ForTooltipDefaults.closeDelay` from the surrounding
221
+ * `provideForTooltipDefaults` scope (300ms unless configured).
222
+ */
223
+ closeDelay = input(undefined, /* @ts-ignore */
224
+ ...(ngDevMode ? [{ debugName: "closeDelay" }] : /* istanbul ignore next */ []));
225
+ /** When true, all hover / focus interaction is ignored and any open tooltip is forced closed. */
226
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
227
+ /**
228
+ * Per-tooltip override for whether the tooltip shows only when the
229
+ * trigger's own text is truncated (`scrollWidth > clientWidth`) — the
230
+ * common pattern for ellipsized labels where the tooltip adds nothing once
231
+ * the full text is visible. When `undefined` (default), falls back to
232
+ * `ForTooltipDefaults.showOnOverflow` from the surrounding
233
+ * `provideForTooltipDefaults` scope (`false` unless configured).
234
+ *
235
+ * The input is aliased to `showOnOverflow`; consumers bind
236
+ * `[showOnOverflow]="..."` (or the bare attribute) and read the effective
237
+ * value via the public `showOnOverflow` computed below.
238
+ */
239
+ _showOnOverflowInput = input(undefined, { ...(ngDevMode ? { debugName: "_showOnOverflowInput" } : /* istanbul ignore next */ {}), alias: 'showOnOverflow',
240
+ transform: (v) => (v == null ? undefined : booleanAttribute(v)) });
241
+ /** Effective overflow gate: the `showOnOverflow` input when set, else the scope default. */
242
+ showOnOverflow = computed(() => this._showOnOverflowInput() ?? this.#defaults.showOnOverflow, /* @ts-ignore */
243
+ ...(ngDevMode ? [{ debugName: "showOnOverflow" }] : /* istanbul ignore next */ []));
244
+ /**
245
+ * Per-tooltip override for whether the pointer may move into the content
246
+ * without dismissing the tooltip. When `true`, the content drops its
247
+ * default `pointer-events: none` while open and a pointer-grace "safe
248
+ * triangle" bridges the gap between trigger and content so a slow diagonal
249
+ * traversal doesn't close it. When `undefined` (default), falls back to
250
+ * `ForTooltipDefaults.hoverableContent` from the surrounding
251
+ * `provideForTooltipDefaults` scope (`false` unless configured).
252
+ *
253
+ * Per APG the content must stay non-interactive; this only allows the
254
+ * pointer to rest over descriptive text (e.g. to select it).
255
+ *
256
+ * The input is aliased to `hoverableContent`; consumers bind
257
+ * `[hoverableContent]="..."` (or the bare attribute) and read the effective
258
+ * value via the public `hoverableContent` computed below.
259
+ */
260
+ _hoverableContentInput = input(undefined, { ...(ngDevMode ? { debugName: "_hoverableContentInput" } : /* istanbul ignore next */ {}), alias: 'hoverableContent',
261
+ transform: (v) => (v == null ? undefined : booleanAttribute(v)) });
262
+ /** Effective hoverable-content flag: the `hoverableContent` input when set, else the scope default. */
263
+ hoverableContent = computed(() => this._hoverableContentInput() ?? this.#defaults.hoverableContent, /* @ts-ignore */
264
+ ...(ngDevMode ? [{ debugName: "hoverableContent" }] : /* istanbul ignore next */ []));
265
+ /**
266
+ * Whether the user has requested reduced motion via the OS
267
+ * `prefers-reduced-motion: reduce` media query. Reflected as the boolean
268
+ * `data-reduced-motion` attribute on the root and content so consumers can
269
+ * disable their own `animate.enter` / `animate.leave` and CSS transitions
270
+ * without re-deriving the media query. Tooltip's JS-coordinated timing (the
271
+ * open / close hover-intent delays) is intent debouncing, not motion, so it
272
+ * is deliberately unchanged under reduced motion.
273
+ */
274
+ reducedMotion = injectPrefersReducedMotion();
275
+ #generatedTriggerId = this.#idGen.next('for-tooltip-trigger');
276
+ /**
277
+ * Id of the trigger element. A consumer-set `id` on the trigger host is
278
+ * adopted at registration and preserved; the generated
279
+ * `for-tooltip-trigger-*` id is only assigned when the host has none.
280
+ */
281
+ triggerId = signal(this.#generatedTriggerId, /* @ts-ignore */
282
+ ...(ngDevMode ? [{ debugName: "triggerId" }] : /* istanbul ignore next */ []));
283
+ /** Generated id of the content element, wired to the trigger's `aria-describedby` while open. */
284
+ contentId = signal(this.#idGen.next('for-tooltip-content'), /* @ts-ignore */
285
+ ...(ngDevMode ? [{ debugName: "contentId" }] : /* istanbul ignore next */ []));
286
+ #triggerEl = signal(null, /* @ts-ignore */
287
+ ...(ngDevMode ? [{ debugName: "#triggerEl" }] : /* istanbul ignore next */ []));
288
+ trigger = this.#triggerEl.asReadonly();
289
+ #contentEl = signal(null, /* @ts-ignore */
290
+ ...(ngDevMode ? [{ debugName: "#contentEl" }] : /* istanbul ignore next */ []));
291
+ #arrowEl = signal(null, /* @ts-ignore */
292
+ ...(ngDevMode ? [{ debugName: "#arrowEl" }] : /* istanbul ignore next */ []));
293
+ arrow = this.#arrowEl.asReadonly();
294
+ #coordinator = inject(TooltipCoordinator);
295
+ #hoverIntent;
296
+ #triggerHovered = false;
297
+ #triggerFocused = false;
298
+ #contentHovered = false;
299
+ #detachGrace = null;
300
+ constructor() {
301
+ forceCloseWhenDisabled({
302
+ open: this.open,
303
+ disabled: this.disabled,
304
+ onForceClose: () => this.cancelPending(),
305
+ });
306
+ this.#hoverIntent = createHoverIntent({
307
+ open: this.open,
308
+ isDisabled: () => this.disabled(),
309
+ openDelay: () => this.openDelay() ?? this.#coordinator.openDelay,
310
+ closeDelay: () => this.closeDelay() ?? this.#coordinator.closeDelay,
311
+ coordinator: this.#coordinator,
312
+ });
313
+ inject(DestroyRef).onDestroy(() => this.cancelPending());
314
+ }
315
+ /**
316
+ * Registers the trigger host element. Adopts a pre-existing consumer-set
317
+ * `id` as the trigger id so external references (anchors, `aria-labelledby`,
318
+ * label `for`) keep resolving; falls back to the generated id otherwise.
319
+ */
320
+ registerTrigger(el) {
321
+ adoptHostId(el, this.triggerId);
322
+ this.#triggerEl.set(el);
323
+ }
324
+ unregisterTrigger(el) {
325
+ if (this.#triggerEl() === el) {
326
+ this.#triggerEl.set(null);
327
+ }
328
+ }
329
+ /** Registers the content host element so the hoverable-content grace polygon can measure it. */
330
+ registerContent(el) {
331
+ this.#contentEl.set(el);
332
+ }
333
+ unregisterContent(el) {
334
+ if (this.#contentEl() === el) {
335
+ this.#contentEl.set(null);
336
+ }
337
+ }
338
+ /** Adopts a consumer-set static `id` on the content host into `contentId`. */
339
+ adoptContentId(el) {
340
+ adoptHostId(el, this.contentId);
341
+ }
342
+ registerArrow(el) {
343
+ this.#arrowEl.set(el);
344
+ }
345
+ unregisterArrow(el) {
346
+ if (this.#arrowEl() === el) {
347
+ this.#arrowEl.set(null);
348
+ }
349
+ }
350
+ pointerEnterTrigger() {
351
+ this.#triggerHovered = true;
352
+ this.#disarmContentGrace();
353
+ if (this.#suppressedByOverflow()) {
354
+ return;
355
+ }
356
+ this.#hoverIntent.scheduleOpen();
357
+ }
358
+ pointerLeaveTrigger(cursor) {
359
+ this.#triggerHovered = false;
360
+ if (this.#triggerFocused) {
361
+ return;
362
+ }
363
+ if (this.hoverableContent() && this.open() && this.#contentEl()) {
364
+ this.#armContentGrace(cursor);
365
+ return;
366
+ }
367
+ this.#scheduleCloseIfInactive();
368
+ }
369
+ focusTrigger() {
370
+ this.#triggerFocused = true;
371
+ if (this.#suppressedByOverflow()) {
372
+ return;
373
+ }
374
+ this.#hoverIntent.scheduleOpen();
375
+ }
376
+ blurTrigger() {
377
+ this.#triggerFocused = false;
378
+ this.#scheduleCloseIfInactive();
379
+ }
380
+ pointerEnterContent() {
381
+ if (!this.hoverableContent()) {
382
+ return;
383
+ }
384
+ this.#contentHovered = true;
385
+ this.#disarmContentGrace();
386
+ this.#hoverIntent.cancelPending();
387
+ }
388
+ pointerLeaveContent() {
389
+ if (!this.hoverableContent()) {
390
+ return;
391
+ }
392
+ this.#contentHovered = false;
393
+ this.#scheduleCloseIfInactive();
394
+ }
395
+ scheduleOpen(_reason) {
396
+ this.#hoverIntent.scheduleOpen();
397
+ }
398
+ scheduleClose(reason) {
399
+ this.#disarmContentGrace();
400
+ this.#hoverIntent.scheduleClose(reason === 'escape');
401
+ }
402
+ cancelPending() {
403
+ this.#disarmContentGrace();
404
+ this.#hoverIntent.cancelPending();
405
+ }
406
+ /**
407
+ * Imperatively opens the tooltip — for programmatic control beyond hover and
408
+ * focus (e.g. a design-system wrapper driving the tooltip from a
409
+ * text-truncation observer). Schedules the show after the resolved
410
+ * `openDelay` (instant when the delay is `0` or the scope's skip-delay window
411
+ * is active) and applies the same gates as a hover / focus open: a no-op
412
+ * while `disabled`, and a no-op under `showOnOverflow` when the trigger's own
413
+ * text is not truncated. For an instant, unconditional open that bypasses the
414
+ * delay and both gates, write the `[(open)]` model directly (`open.set(true)`).
415
+ */
416
+ show() {
417
+ if (this.#suppressedByOverflow()) {
418
+ return;
419
+ }
420
+ this.#hoverIntent.scheduleOpen();
421
+ }
422
+ /**
423
+ * Imperatively closes the tooltip, mirroring a hover-leave / blur close:
424
+ * schedules the hide after the resolved `closeDelay` (instant when the delay
425
+ * is `0`) and disarms the hoverable-content grace bridge. For an instant
426
+ * close that ignores `closeDelay`, write the `[(open)]` model directly
427
+ * (`open.set(false)`).
428
+ */
429
+ hide() {
430
+ this.scheduleClose('hover');
431
+ }
432
+ /** Close only when no keep-alive source (trigger hover/focus, content hover) is active. */
433
+ #scheduleCloseIfInactive() {
434
+ if (this.#triggerHovered || this.#triggerFocused || this.#contentHovered) {
435
+ return;
436
+ }
437
+ this.#hoverIntent.scheduleClose(false);
438
+ }
439
+ /** True when `showOnOverflow` is on and the trigger's text is NOT truncated. */
440
+ #suppressedByOverflow() {
441
+ if (!this.showOnOverflow()) {
442
+ return false;
443
+ }
444
+ const el = this.#triggerEl();
445
+ return el !== null && el.scrollWidth <= el.clientWidth;
446
+ }
447
+ /**
448
+ * Arms a pointer-grace "safe triangle" from `cursor` toward the content so
449
+ * the pointer can travel across the trigger / content gap without closing.
450
+ * On exit (or when content hover takes over) the grace disarms and a close
451
+ * is scheduled if nothing else keeps the tooltip alive.
452
+ */
453
+ #armContentGrace(cursor) {
454
+ const content = this.#contentEl();
455
+ if (!content) {
456
+ this.#scheduleCloseIfInactive();
457
+ return;
458
+ }
459
+ const rect = content.getBoundingClientRect();
460
+ const trigger = this.#triggerEl();
461
+ const side = trigger ? resolveGraceSide(trigger.getBoundingClientRect(), rect) : this.side();
462
+ const polygon = buildSubmenuGracePolygon(cursor, rect, side);
463
+ this.#disarmContentGrace();
464
+ this.#detachGrace = attachPointerGrace(content.ownerDocument, polygon, () => {
465
+ this.#disarmContentGrace();
466
+ this.#scheduleCloseIfInactive();
467
+ });
468
+ }
469
+ #disarmContentGrace() {
470
+ if (this.#detachGrace) {
471
+ this.#detachGrace();
472
+ this.#detachGrace = null;
473
+ }
474
+ }
475
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTooltip, deps: [], target: i0.ɵɵFactoryTarget.Directive });
476
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForTooltip, isStandalone: true, selector: "[forTooltip]", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, _sideInput: { classPropertyName: "_sideInput", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, _alignInput: { classPropertyName: "_alignInput", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, _sideOffsetInput: { classPropertyName: "_sideOffsetInput", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, alignOffset: { classPropertyName: "alignOffset", publicName: "alignOffset", isSignal: true, isRequired: false, transformFunction: null }, avoidCollisions: { classPropertyName: "avoidCollisions", publicName: "avoidCollisions", isSignal: true, isRequired: false, transformFunction: null }, _collisionPaddingInput: { classPropertyName: "_collisionPaddingInput", publicName: "collisionPadding", isSignal: true, isRequired: false, transformFunction: null }, arrowPadding: { classPropertyName: "arrowPadding", publicName: "arrowPadding", isSignal: true, isRequired: false, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null }, hideWhenDetached: { classPropertyName: "hideWhenDetached", publicName: "hideWhenDetached", isSignal: true, isRequired: false, transformFunction: null }, clipUntilPositioned: { classPropertyName: "clipUntilPositioned", publicName: "clipUntilPositioned", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, _showOnOverflowInput: { classPropertyName: "_showOnOverflowInput", publicName: "showOnOverflow", isSignal: true, isRequired: false, transformFunction: null }, _hoverableContentInput: { classPropertyName: "_hoverableContentInput", publicName: "hoverableContent", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { properties: { "attr.data-state": "open() ? \"open\" : \"closed\"", "attr.data-disabled": "disabled() ? \"\" : null", "attr.data-reduced-motion": "reducedMotion() ? \"\" : null" } }, providers: [{ provide: FOR_TOOLTIP_CONTEXT, useExisting: ForTooltip }], exportAs: ["forTooltip"], ngImport: i0 });
477
+ }
478
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTooltip, decorators: [{
479
+ type: Directive,
480
+ args: [{
481
+ selector: '[forTooltip]',
482
+ exportAs: 'forTooltip',
483
+ host: {
484
+ '[attr.data-state]': 'open() ? "open" : "closed"',
485
+ '[attr.data-disabled]': 'disabled() ? "" : null',
486
+ '[attr.data-reduced-motion]': 'reducedMotion() ? "" : null',
487
+ },
488
+ providers: [{ provide: FOR_TOOLTIP_CONTEXT, useExisting: ForTooltip }],
489
+ }]
490
+ }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], _sideInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], _alignInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], _sideOffsetInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "sideOffset", required: false }] }], alignOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignOffset", required: false }] }], avoidCollisions: [{ type: i0.Input, args: [{ isSignal: true, alias: "avoidCollisions", required: false }] }], _collisionPaddingInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "collisionPadding", required: false }] }], arrowPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowPadding", required: false }] }], sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }], hideWhenDetached: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideWhenDetached", required: false }] }], clipUntilPositioned: [{ type: i0.Input, args: [{ isSignal: true, alias: "clipUntilPositioned", required: false }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], _showOnOverflowInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOnOverflow", required: false }] }], _hoverableContentInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverableContent", required: false }] }] } });
491
+
492
+ /**
493
+ * Element that activates the tooltip on mouse hover or keyboard focus. Apply on
494
+ * a focusable element — preferably a `<button>` so keyboard users can reach it.
495
+ * Receives `aria-describedby` only while the tooltip is open, per APG.
496
+ *
497
+ * A touch tap does NOT open the tooltip: touch pointers are filtered out of
498
+ * both the hover-open path and the focus-open path, because a tap is not a
499
+ * hover and the APG flags hover-tooltips as problematic on touch (no hover, no
500
+ * separate focus affordance, no obvious dismiss). Keyboard focus stays the
501
+ * touch-accessible fallback for descriptive content.
502
+ *
503
+ * The root is normally resolved via DI from the enclosing `[forTooltip]`.
504
+ * When the trigger is declared inside an `ng-template` stamped into the root
505
+ * (e.g. via `ngTemplateOutlet`), DI resolves at the template's declaration
506
+ * site and misses the root — pass it explicitly through the selector input,
507
+ * `routerLink`-style: `[forTooltipTrigger]="root"` with `#root="forTooltip"`.
508
+ */
509
+ class ForTooltipTrigger {
510
+ #host = inject(ElementRef);
511
+ /**
512
+ * Optional explicit reference to the `[forTooltip]` root, named after the
513
+ * selector `routerLink`-style. The bare valueless attribute keeps resolving
514
+ * the enclosing root via DI; pass the root explicitly
515
+ * (`[forTooltipTrigger]="root"`, with `#root="forTooltip"`) when the trigger
516
+ * is declared in an `ng-template` stamped inside the root — DI resolves at
517
+ * the template's declaration site, so the enclosing root is invisible there.
518
+ * The empty string (what the valueless attribute yields) is treated as unset.
519
+ */
520
+ forTooltipTrigger = input('', /* @ts-ignore */
521
+ ...(ngDevMode ? [{ debugName: "forTooltipTrigger" }] : /* istanbul ignore next */ []));
522
+ ctx = injectTooltipTriggerContext(this.forTooltipTrigger);
523
+ #lastPointerType = null;
524
+ constructor() {
525
+ const el = this.#host.nativeElement;
526
+ // Registration is an imperative call into the resolved root's registry,
527
+ // not state derivation — the effect only re-registers the element when the
528
+ // resolved root changes (explicit reference swapped at runtime).
529
+ effect((onCleanup) => {
530
+ const ctx = this.ctx();
531
+ ctx.registerTrigger(el);
532
+ onCleanup(() => ctx.unregisterTrigger(el));
533
+ });
534
+ }
535
+ onPointerEnter(event) {
536
+ if (event.pointerType === 'touch') {
537
+ return;
538
+ }
539
+ this.ctx().pointerEnterTrigger();
540
+ }
541
+ onPointerDown(event) {
542
+ this.#lastPointerType = event.pointerType;
543
+ }
544
+ onPointerLeave(event) {
545
+ this.ctx().pointerLeaveTrigger({ x: event.clientX, y: event.clientY });
546
+ }
547
+ onFocus() {
548
+ const touchInduced = this.#lastPointerType === 'touch';
549
+ this.#lastPointerType = null;
550
+ if (touchInduced) {
551
+ return;
552
+ }
553
+ this.ctx().focusTrigger();
554
+ }
555
+ onBlur() {
556
+ this.#lastPointerType = null;
557
+ this.ctx().blurTrigger();
558
+ }
559
+ onEscape(event) {
560
+ if (this.ctx().open()) {
561
+ event.preventDefault();
562
+ event.stopPropagation();
563
+ this.ctx().scheduleClose('escape');
564
+ }
565
+ }
566
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTooltipTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive });
567
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForTooltipTrigger, isStandalone: true, selector: "[forTooltipTrigger]", inputs: { forTooltipTrigger: { classPropertyName: "forTooltipTrigger", publicName: "forTooltipTrigger", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "pointerenter": "onPointerEnter($event)", "pointerdown": "onPointerDown($event)", "pointerleave": "onPointerLeave($event)", "focus": "onFocus()", "blur": "onBlur()", "keydown.escape": "onEscape($event)" }, properties: { "id": "ctx().triggerId()", "attr.aria-describedby": "ctx().open() ? ctx().contentId() : null", "attr.data-state": "ctx().open() ? \"open\" : \"closed\"" } }, exportAs: ["forTooltipTrigger"], ngImport: i0 });
568
+ }
569
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTooltipTrigger, decorators: [{
570
+ type: Directive,
571
+ args: [{
572
+ selector: '[forTooltipTrigger]',
573
+ exportAs: 'forTooltipTrigger',
574
+ host: {
575
+ '[id]': 'ctx().triggerId()',
576
+ '[attr.aria-describedby]': 'ctx().open() ? ctx().contentId() : null',
577
+ '[attr.data-state]': 'ctx().open() ? "open" : "closed"',
578
+ '(pointerenter)': 'onPointerEnter($event)',
579
+ '(pointerdown)': 'onPointerDown($event)',
580
+ '(pointerleave)': 'onPointerLeave($event)',
581
+ '(focus)': 'onFocus()',
582
+ '(blur)': 'onBlur()',
583
+ '(keydown.escape)': 'onEscape($event)',
584
+ },
585
+ }]
586
+ }], ctorParameters: () => [], propDecorators: { forTooltipTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "forTooltipTrigger", required: false }] }] } });
587
+
588
+ /**
589
+ * The tooltip bubble. Carries `role="tooltip"`, is portaled to
590
+ * `document.body`, and is positioned by `@floating-ui/dom` (via the shared
591
+ * `injectOverlayShell` helper) while mounted.
592
+ *
593
+ * Default `pointer-events: none` is applied via host styles so the bubble
594
+ * layers above content without intercepting hover. When the root opts in with
595
+ * `hoverableContent`, `pointer-events` is dropped while open so the pointer
596
+ * can rest over the bubble without dismissing it. Override with your own CSS
597
+ * if needed — but per APG, do not put interactive elements inside.
598
+ *
599
+ * The directive does not manage DOM presence — wrap with
600
+ * `@if (tip.open())` (using a template ref on `[forTooltip]`) so the
601
+ * bubble mounts and unmounts with the open state and `animate.enter` /
602
+ * `animate.leave` work natively.
603
+ *
604
+ * Tooltips have no dismissable layer (Escape is a tooltip controller
605
+ * concern, not an outside-pointer/focus one), no initial focus move, and
606
+ * no return focus on destroy — only the floating positioner is wired.
607
+ */
608
+ class ForTooltipContent {
609
+ ctx = injectTooltipContext('ForTooltipContent');
610
+ constructor() {
611
+ const el = inject(ElementRef).nativeElement;
612
+ this.ctx.adoptContentId(el);
613
+ this.ctx.registerContent(el);
614
+ inject(DestroyRef).onDestroy(() => this.ctx.unregisterContent(el));
615
+ injectOverlayShell({
616
+ positioner: toFloatingPositioner(this.ctx, this.ctx.trigger),
617
+ });
618
+ }
619
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTooltipContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
620
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: ForTooltipContent, isStandalone: true, selector: "[forTooltipContent]", host: { attributes: { "role": "tooltip" }, listeners: { "pointerenter": "ctx.pointerEnterContent()", "pointerleave": "ctx.pointerLeaveContent()" }, properties: { "id": "ctx.contentId()", "attr.data-state": "ctx.open() ? \"open\" : \"closed\"", "attr.data-reduced-motion": "ctx.reducedMotion() ? \"\" : null", "style.pointer-events": "ctx.hoverableContent() ? null : \"none\"" } }, exportAs: ["forTooltipContent"], ngImport: i0 });
621
+ }
622
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTooltipContent, decorators: [{
623
+ type: Directive,
624
+ args: [{
625
+ selector: '[forTooltipContent]',
626
+ exportAs: 'forTooltipContent',
627
+ host: {
628
+ role: 'tooltip',
629
+ '[id]': 'ctx.contentId()',
630
+ '[attr.data-state]': 'ctx.open() ? "open" : "closed"',
631
+ '[attr.data-reduced-motion]': 'ctx.reducedMotion() ? "" : null',
632
+ '[style.pointer-events]': 'ctx.hoverableContent() ? null : "none"',
633
+ '(pointerenter)': 'ctx.pointerEnterContent()',
634
+ '(pointerleave)': 'ctx.pointerLeaveContent()',
635
+ },
636
+ }]
637
+ }], ctorParameters: () => [] });
638
+
639
+ /**
640
+ * Optional visual arrow inside `ForTooltipContent`. Registers itself with
641
+ * the tooltip context so floating-ui's `arrow` middleware can position it
642
+ * along the bubble edge that points at the trigger. Style size and color
643
+ * yourself — the directive only sets `position`, `left`/`top`, and the
644
+ * opposite-side offset.
645
+ */
646
+ class ForTooltipArrow {
647
+ #ctx = injectTooltipContext('ForTooltipArrow');
648
+ #host = inject(ElementRef);
649
+ constructor() {
650
+ registerHandle(this.#host.nativeElement, (el) => this.#ctx.registerArrow(el), (el) => this.#ctx.unregisterArrow(el));
651
+ }
652
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTooltipArrow, deps: [], target: i0.ɵɵFactoryTarget.Directive });
653
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: ForTooltipArrow, isStandalone: true, selector: "[forTooltipArrow]", host: { attributes: { "aria-hidden": "true", "data-tooltip-arrow": "" } }, exportAs: ["forTooltipArrow"], ngImport: i0 });
654
+ }
655
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTooltipArrow, decorators: [{
656
+ type: Directive,
657
+ args: [{
658
+ selector: '[forTooltipArrow]',
659
+ exportAs: 'forTooltipArrow',
660
+ host: {
661
+ 'aria-hidden': 'true',
662
+ 'data-tooltip-arrow': '',
663
+ },
664
+ }]
665
+ }], ctorParameters: () => [] });
666
+
667
+ /**
668
+ * Generated bundle index. Do not edit.
669
+ */
670
+
671
+ export { FOR_TOOLTIP_CONTEXT, FOR_TOOLTIP_DEFAULTS, ForTooltip, ForTooltipArrow, ForTooltipContent, ForTooltipTrigger, provideForTooltipDefaults };
672
+ //# sourceMappingURL=forty-cdk-tooltip.mjs.map