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,640 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, input, numberAttribute, signal, DestroyRef, Directive, ElementRef, DOCUMENT, PLATFORM_ID, afterNextRender, effect, computed } from '@angular/core';
3
+ import { createDefaults, injectTextDirection, injectElementSize } from 'forty-cdk/core';
4
+ import { isPlatformBrowser } from '@angular/common';
5
+
6
+ const FOR_SCROLL_AREA_CONTEXT = new InjectionToken('FOR_SCROLL_AREA_CONTEXT');
7
+ function injectScrollAreaContext(piece) {
8
+ const ctx = inject(FOR_SCROLL_AREA_CONTEXT, { optional: true });
9
+ if (!ctx) {
10
+ throw new Error(`[forty-cdk/scroll-area] ${piece} must be used inside a [forScrollArea] element.`);
11
+ }
12
+ return ctx;
13
+ }
14
+
15
+ /**
16
+ * Library fallback for scroll area defaults, read at the root injector when no
17
+ * consumer has called `provideForScrollAreaDefaults`. Exported for the shared defaults
18
+ * contract spec; not re-exported from the primitive's public entry.
19
+ */
20
+ const FOR_SCROLL_AREA_FALLBACK_DEFAULTS = {
21
+ scrollHideDelay: 600,
22
+ };
23
+ const { token, provideDefaults } = createDefaults('FOR_SCROLL_AREA_DEFAULTS', FOR_SCROLL_AREA_FALLBACK_DEFAULTS);
24
+ /** Token holding the resolved scroll-area defaults for the current scope. */
25
+ const FOR_SCROLL_AREA_DEFAULTS = token;
26
+ /**
27
+ * Configures forty-cdk scroll-area defaults for this injector scope. Partial
28
+ * overrides inherit unspecified keys from the parent scope (or library
29
+ * defaults at the root).
30
+ */
31
+ function provideForScrollAreaDefaults(defaults = {}) {
32
+ return provideDefaults(defaults);
33
+ }
34
+
35
+ /**
36
+ * Root of the custom-scrollbar primitive. Owns the viewport reference,
37
+ * scroll geometry signals, and visibility state for the synthetic
38
+ * scrollbars.
39
+ *
40
+ * Native scrollbars on the inner viewport are hidden via styles injected
41
+ * by `[forScrollAreaViewport]` (the only place in forty-cdk that
42
+ * imperatively touches CSS); the consumer styles `[forScrollAreaThumb]`
43
+ * however they like.
44
+ *
45
+ * @example
46
+ * ```html
47
+ * <div forScrollArea>
48
+ * <div forScrollAreaViewport>
49
+ * <div forScrollAreaContent>… long content …</div>
50
+ * </div>
51
+ * <div forScrollAreaScrollbar orientation="vertical">
52
+ * <div forScrollAreaThumb></div>
53
+ * </div>
54
+ * <div forScrollAreaScrollbar orientation="horizontal">
55
+ * <div forScrollAreaThumb></div>
56
+ * </div>
57
+ * <div forScrollAreaCorner></div>
58
+ * </div>
59
+ * ```
60
+ */
61
+ class ForScrollArea {
62
+ #defaults = inject(FOR_SCROLL_AREA_DEFAULTS);
63
+ /**
64
+ * When the synthetic scrollbars are visible:
65
+ * - `auto`: shown whenever the axis overflows, regardless of interaction;
66
+ * self-hides when the content fits.
67
+ * - `always`: the scrollbar (and corner) stay mounted and
68
+ * `data-state="visible"` regardless of overflow — a stable, always-painted
69
+ * track. When the axis does not overflow the thumb fills
70
+ * the full track and dragging is a no-op. The library is headless and does
71
+ * not own layout, so to actually *reserve* the gutter (no content shift
72
+ * when crossing the overflow boundary) the consumer lays the scrollbar out
73
+ * in flow — see the ScrollArea README's grid example.
74
+ * - `scroll`: shown during scroll, faded after `scrollHideDelay` ms.
75
+ * - `hover`: shown while the cursor is over the area (and during scroll).
76
+ */
77
+ type = input('hover', /* @ts-ignore */
78
+ ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
79
+ /**
80
+ * ms after the most recent scroll before scrollbars fade (only
81
+ * `type="scroll"` and `"hover"`). The default is read from
82
+ * `provideForScrollAreaDefaults` for the surrounding scope.
83
+ */
84
+ scrollHideDelay = input(this.#defaults.scrollHideDelay, { ...(ngDevMode ? { debugName: "scrollHideDelay" } : /* istanbul ignore next */ {}), transform: numberAttribute });
85
+ /**
86
+ * Writing direction. When unset (default `null`), the inherited ambient
87
+ * direction is resolved from the nearest ancestor carrying a `dir` attribute
88
+ * (or `<html dir>`), defaulting to `'ltr'`. An explicit `[dir]` always wins.
89
+ * The resolved value is reflected to the host `dir` attribute and positions
90
+ * the vertical scrollbar on the left in RTL.
91
+ */
92
+ _dirInput = input(null, { ...(ngDevMode ? { debugName: "_dirInput" } : /* istanbul ignore next */ {}), alias: 'dir' });
93
+ dir = injectTextDirection(this._dirInput);
94
+ #viewport = signal(null, /* @ts-ignore */
95
+ ...(ngDevMode ? [{ debugName: "#viewport" }] : /* istanbul ignore next */ []));
96
+ viewport = this.#viewport.asReadonly();
97
+ #content = signal(null, /* @ts-ignore */
98
+ ...(ngDevMode ? [{ debugName: "#content" }] : /* istanbul ignore next */ []));
99
+ content = this.#content.asReadonly();
100
+ #scrollLeft = signal(0, /* @ts-ignore */
101
+ ...(ngDevMode ? [{ debugName: "#scrollLeft" }] : /* istanbul ignore next */ []));
102
+ #scrollTop = signal(0, /* @ts-ignore */
103
+ ...(ngDevMode ? [{ debugName: "#scrollTop" }] : /* istanbul ignore next */ []));
104
+ scrollLeft = this.#scrollLeft.asReadonly();
105
+ scrollTop = this.#scrollTop.asReadonly();
106
+ #clientW = signal(0, /* @ts-ignore */
107
+ ...(ngDevMode ? [{ debugName: "#clientW" }] : /* istanbul ignore next */ []));
108
+ #clientH = signal(0, /* @ts-ignore */
109
+ ...(ngDevMode ? [{ debugName: "#clientH" }] : /* istanbul ignore next */ []));
110
+ #scrollW = signal(0, /* @ts-ignore */
111
+ ...(ngDevMode ? [{ debugName: "#scrollW" }] : /* istanbul ignore next */ []));
112
+ #scrollH = signal(0, /* @ts-ignore */
113
+ ...(ngDevMode ? [{ debugName: "#scrollH" }] : /* istanbul ignore next */ []));
114
+ clientWidth = this.#clientW.asReadonly();
115
+ clientHeight = this.#clientH.asReadonly();
116
+ scrollWidth = this.#scrollW.asReadonly();
117
+ scrollHeight = this.#scrollH.asReadonly();
118
+ #hovering = signal(false, /* @ts-ignore */
119
+ ...(ngDevMode ? [{ debugName: "#hovering" }] : /* istanbul ignore next */ []));
120
+ hovering = this.#hovering.asReadonly();
121
+ #scrolling = signal(false, /* @ts-ignore */
122
+ ...(ngDevMode ? [{ debugName: "#scrolling" }] : /* istanbul ignore next */ []));
123
+ scrolling = this.#scrolling.asReadonly();
124
+ #scrollTimer = null;
125
+ registerViewport(el) {
126
+ this.#viewport.set(el);
127
+ }
128
+ registerContent(el) {
129
+ this.#content.set(el);
130
+ }
131
+ unregisterContent(el) {
132
+ // Only clear if the unregistering element is the one we currently track,
133
+ // so a late teardown of an old content piece doesn't blow away a freshly
134
+ // registered replacement.
135
+ if (this.#content() === el) {
136
+ this.#content.set(null);
137
+ }
138
+ }
139
+ reportScroll(left, top) {
140
+ this.#scrollLeft.set(left);
141
+ this.#scrollTop.set(top);
142
+ }
143
+ reportSize(clientW, clientH, scrollW, scrollH) {
144
+ this.#clientW.set(clientW);
145
+ this.#clientH.set(clientH);
146
+ this.#scrollW.set(scrollW);
147
+ this.#scrollH.set(scrollH);
148
+ }
149
+ noteUserScroll() {
150
+ this.#scrolling.set(true);
151
+ if (this.#scrollTimer !== null)
152
+ clearTimeout(this.#scrollTimer);
153
+ this.#scrollTimer = setTimeout(() => {
154
+ this.#scrollTimer = null;
155
+ this.#scrolling.set(false);
156
+ }, Math.max(0, this.scrollHideDelay()));
157
+ }
158
+ onPointerEnter() {
159
+ this.#hovering.set(true);
160
+ }
161
+ onPointerLeave() {
162
+ this.#hovering.set(false);
163
+ }
164
+ constructor() {
165
+ inject(DestroyRef).onDestroy(() => {
166
+ if (this.#scrollTimer !== null)
167
+ clearTimeout(this.#scrollTimer);
168
+ });
169
+ }
170
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollArea, deps: [], target: i0.ɵɵFactoryTarget.Directive });
171
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForScrollArea, isStandalone: true, selector: "[forScrollArea]", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, scrollHideDelay: { classPropertyName: "scrollHideDelay", publicName: "scrollHideDelay", isSignal: true, isRequired: false, transformFunction: null }, _dirInput: { classPropertyName: "_dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "pointerenter": "onPointerEnter()", "pointerleave": "onPointerLeave()" }, properties: { "attr.data-type": "type()", "attr.dir": "dir()" } }, providers: [{ provide: FOR_SCROLL_AREA_CONTEXT, useExisting: ForScrollArea }], exportAs: ["forScrollArea"], ngImport: i0 });
172
+ }
173
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollArea, decorators: [{
174
+ type: Directive,
175
+ args: [{
176
+ selector: '[forScrollArea]',
177
+ exportAs: 'forScrollArea',
178
+ host: {
179
+ '[attr.data-type]': 'type()',
180
+ '[attr.dir]': 'dir()',
181
+ '(pointerenter)': 'onPointerEnter()',
182
+ '(pointerleave)': 'onPointerLeave()',
183
+ },
184
+ providers: [{ provide: FOR_SCROLL_AREA_CONTEXT, useExisting: ForScrollArea }],
185
+ }]
186
+ }], ctorParameters: () => [], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], scrollHideDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollHideDelay", required: false }] }], _dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }] } });
187
+
188
+ const HIDE_NATIVE_SCROLLBARS_STYLE_ID = 'for-scroll-area-hide-native';
189
+ const HIDE_NATIVE_SCROLLBARS_CSS = `
190
+ [forScrollAreaViewport] {
191
+ overflow: scroll;
192
+ -ms-overflow-style: none;
193
+ scrollbar-width: none;
194
+ }
195
+ [forScrollAreaViewport]::-webkit-scrollbar {
196
+ display: none;
197
+ width: 0;
198
+ height: 0;
199
+ }
200
+ `;
201
+ function injectHidingStylesOnce(doc) {
202
+ if (doc.getElementById(HIDE_NATIVE_SCROLLBARS_STYLE_ID))
203
+ return;
204
+ const style = doc.createElement('style');
205
+ style.id = HIDE_NATIVE_SCROLLBARS_STYLE_ID;
206
+ style.textContent = HIDE_NATIVE_SCROLLBARS_CSS;
207
+ doc.head.appendChild(style);
208
+ }
209
+ /**
210
+ * The actually-scrolling element. Hides native scrollbars (the only place
211
+ * in forty-cdk that ships CSS — see README), tracks scroll position, and
212
+ * reports geometry to the root so the synthetic scrollbar can render.
213
+ */
214
+ class ForScrollAreaViewport {
215
+ #ctx = injectScrollAreaContext('ForScrollAreaViewport');
216
+ #host = inject(ElementRef).nativeElement;
217
+ #document = inject(DOCUMENT);
218
+ #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
219
+ constructor() {
220
+ if (this.#isBrowser) {
221
+ injectHidingStylesOnce(this.#document);
222
+ }
223
+ this.#ctx.registerViewport(this.#host);
224
+ inject(DestroyRef).onDestroy(() => this.#ctx.registerViewport(null));
225
+ afterNextRender(() => {
226
+ this.#syncScroll();
227
+ this.#syncSize();
228
+ });
229
+ // Track size changes via ResizeObserver — simpler / lighter than
230
+ // polling, and consistent with the rest of the library's reactive
231
+ // patterns. Browser-only API; no-op on server.
232
+ //
233
+ // The content element is observed only when the consumer explicitly
234
+ // marks it with `[forScrollAreaContent]`. Without that marker we skip
235
+ // content observation entirely (rather than guessing `firstElementChild`,
236
+ // which silently breaks on layered / multi-sibling layouts).
237
+ if (this.#isBrowser && typeof ResizeObserver !== 'undefined') {
238
+ const ro = new ResizeObserver(() => this.#syncSize());
239
+ ro.observe(this.#host);
240
+ inject(DestroyRef).onDestroy(() => ro.disconnect());
241
+ // Re-attach the observer whenever the registered content element
242
+ // changes (registers, unregisters, or swaps). `effect` is the right
243
+ // primitive here: this is a DOM imperative side effect, not derived
244
+ // state — see CLAUDE.md "Never propagate state inside `effect()`".
245
+ let observedContent = null;
246
+ effect(() => {
247
+ const next = this.#ctx.content();
248
+ if (next === observedContent)
249
+ return;
250
+ if (observedContent)
251
+ ro.unobserve(observedContent);
252
+ if (next)
253
+ ro.observe(next);
254
+ observedContent = next;
255
+ });
256
+ }
257
+ }
258
+ onScroll() {
259
+ this.#syncScroll();
260
+ this.#ctx.noteUserScroll();
261
+ }
262
+ #syncScroll() {
263
+ this.#ctx.reportScroll(this.#host.scrollLeft, this.#host.scrollTop);
264
+ }
265
+ #syncSize() {
266
+ this.#ctx.reportSize(this.#host.clientWidth, this.#host.clientHeight, this.#host.scrollWidth, this.#host.scrollHeight);
267
+ this.#syncScroll();
268
+ }
269
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollAreaViewport, deps: [], target: i0.ɵɵFactoryTarget.Directive });
270
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: ForScrollAreaViewport, isStandalone: true, selector: "[forScrollAreaViewport]", host: { listeners: { "scroll": "onScroll()" } }, exportAs: ["forScrollAreaViewport"], ngImport: i0 });
271
+ }
272
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollAreaViewport, decorators: [{
273
+ type: Directive,
274
+ args: [{
275
+ selector: '[forScrollAreaViewport]',
276
+ exportAs: 'forScrollAreaViewport',
277
+ host: {
278
+ '(scroll)': 'onScroll()',
279
+ },
280
+ }]
281
+ }], ctorParameters: () => [] });
282
+
283
+ /**
284
+ * Marks the content element inside `[forScrollAreaViewport]`. The viewport
285
+ * observes this element with a `ResizeObserver` so `scrollWidth` /
286
+ * `scrollHeight` updates when content reflows.
287
+ *
288
+ * Required for the synthetic scrollbar to react to content resizes — without
289
+ * it, the viewport falls back to no observation and scrollbars stay sized to
290
+ * whatever the layout reported on first render.
291
+ */
292
+ class ForScrollAreaContent {
293
+ #ctx = injectScrollAreaContext('ForScrollAreaContent');
294
+ #host = inject(ElementRef).nativeElement;
295
+ constructor() {
296
+ this.#ctx.registerContent(this.#host);
297
+ inject(DestroyRef).onDestroy(() => this.#ctx.unregisterContent(this.#host));
298
+ }
299
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollAreaContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
300
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: ForScrollAreaContent, isStandalone: true, selector: "[forScrollAreaContent]", exportAs: ["forScrollAreaContent"], ngImport: i0 });
301
+ }
302
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollAreaContent, decorators: [{
303
+ type: Directive,
304
+ args: [{
305
+ selector: '[forScrollAreaContent]',
306
+ exportAs: 'forScrollAreaContent',
307
+ }]
308
+ }], ctorParameters: () => [] });
309
+
310
+ /**
311
+ * Synthetic scrollbar track. Reflects `data-orientation`, `data-state`
312
+ * (`visible` / `hidden`), and exposes its host element via the orientation
313
+ * input so the thumb can compute geometry.
314
+ *
315
+ * The element is fully removed (`hidden`) when the corresponding axis has
316
+ * no overflow *and* `type` is not `'always'` — there is no scrollbar to
317
+ * render. Under `type="always"` the track stays painted regardless of
318
+ * overflow, so the consumer's reserved gutter is never empty.
319
+ * Visibility is enforced with an inline `display: none` (which beats any
320
+ * author `display` rule a consumer applies via a class) in addition to the
321
+ * `hidden` attribute that removes it from the a11y tree.
322
+ */
323
+ class ForScrollAreaScrollbar {
324
+ orientation = input.required(/* @ts-ignore */
325
+ ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
326
+ ctx = injectScrollAreaContext('ForScrollAreaScrollbar');
327
+ host = inject(ElementRef).nativeElement;
328
+ /**
329
+ * Reactive size of the track itself, measured independently of the viewport.
330
+ * The thumb's size and travel are computed against the *track* length, which
331
+ * the consumer is free to lay out shorter than the viewport (e.g. insets, a
332
+ * reserved corner, padding), so the viewport's reported client dimensions are
333
+ * not a substitute — the track must be observed directly.
334
+ *
335
+ * The target is a constant (`this.host` never changes), so `injectElementSize`'s
336
+ * target-swap branch is dead weight here; it is reused only for its
337
+ * `ResizeObserver` plumbing and change-deduped emission.
338
+ */
339
+ #hostRef = signal(this.host, /* @ts-ignore */
340
+ ...(ngDevMode ? [{ debugName: "#hostRef" }] : /* istanbul ignore next */ []));
341
+ size = injectElementSize(this.#hostRef);
342
+ #dragging = signal(false, /* @ts-ignore */
343
+ ...(ngDevMode ? [{ debugName: "#dragging" }] : /* istanbul ignore next */ []));
344
+ /** True while the thumb is being dragged. Pins the track visible / painted. */
345
+ dragging = this.#dragging.asReadonly();
346
+ /**
347
+ * Marks the track as actively dragged so an in-flight drag is never aborted
348
+ * by the scrollbar self-hiding (`type="hover"` / `"scroll"` fading the track,
349
+ * or a consumer `display:none` on `data-state="hidden"`). Called by the thumb
350
+ * on pointer-down / drag-end.
351
+ */
352
+ setDragging(dragging) {
353
+ this.#dragging.set(dragging);
354
+ }
355
+ hasOverflow = computed(() => {
356
+ if (this.orientation() === 'horizontal') {
357
+ return this.ctx.scrollWidth() - this.ctx.clientWidth() > 1;
358
+ }
359
+ return this.ctx.scrollHeight() - this.ctx.clientHeight() > 1;
360
+ }, /* @ts-ignore */
361
+ ...(ngDevMode ? [{ debugName: "hasOverflow" }] : /* istanbul ignore next */ []));
362
+ /**
363
+ * Whether the track is rendered at all. `'always'` keeps it painted
364
+ * unconditionally (a stable, always-present track); every
365
+ * other `type` paints only the axis that actually overflows. An in-flight
366
+ * thumb drag also pins it painted so the gesture is never aborted by the
367
+ * track self-removing. Gates both the `hidden` attribute and the inline
368
+ * `display: none` self-removal.
369
+ */
370
+ painted = computed(() => this.dragging() || this.ctx.type() === 'always' || this.hasOverflow(), /* @ts-ignore */
371
+ ...(ngDevMode ? [{ debugName: "painted" }] : /* istanbul ignore next */ []));
372
+ /**
373
+ * `'visible' | 'hidden'`. An in-flight thumb drag forces `'visible'` so a
374
+ * consumer fade on `data-state="hidden"` can't hide the track mid-gesture.
375
+ * Otherwise: `'always'` resolves to `'visible'` regardless of overflow — the
376
+ * track is permanently present. `'auto'` shows whenever the axis overflows;
377
+ * `'hover'` / `'scroll'` additionally gate on the interaction signals. A
378
+ * non-overflowing axis is `'hidden'` for every mode except `'always'`.
379
+ */
380
+ state = computed(() => {
381
+ if (this.dragging())
382
+ return 'visible';
383
+ switch (this.ctx.type()) {
384
+ case 'always':
385
+ return 'visible';
386
+ case 'auto':
387
+ return this.hasOverflow() ? 'visible' : 'hidden';
388
+ case 'hover':
389
+ return this.hasOverflow() && (this.ctx.hovering() || this.ctx.scrolling())
390
+ ? 'visible'
391
+ : 'hidden';
392
+ case 'scroll':
393
+ return this.hasOverflow() && this.ctx.scrolling() ? 'visible' : 'hidden';
394
+ }
395
+ }, /* @ts-ignore */
396
+ ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
397
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollAreaScrollbar, deps: [], target: i0.ɵɵFactoryTarget.Directive });
398
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForScrollAreaScrollbar, isStandalone: true, selector: "[forScrollAreaScrollbar]", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-orientation": "orientation()", "attr.data-state": "state()", "hidden": "!painted()", "style.display": "painted() ? null : \"none\"" } }, exportAs: ["forScrollAreaScrollbar"], ngImport: i0 });
399
+ }
400
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollAreaScrollbar, decorators: [{
401
+ type: Directive,
402
+ args: [{
403
+ selector: '[forScrollAreaScrollbar]',
404
+ exportAs: 'forScrollAreaScrollbar',
405
+ host: {
406
+ '[attr.data-orientation]': 'orientation()',
407
+ '[attr.data-state]': 'state()',
408
+ '[hidden]': '!painted()',
409
+ '[style.display]': 'painted() ? null : "none"',
410
+ },
411
+ }]
412
+ }], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: true }] }] } });
413
+
414
+ const MIN_THUMB_SIZE = 8;
415
+ function injectRequiredScrollbar() {
416
+ const scrollbar = inject(ForScrollAreaScrollbar, { optional: true });
417
+ if (!scrollbar) {
418
+ throw new Error('[forty-cdk/scroll-area] ForScrollAreaThumb must be used inside a [forScrollAreaScrollbar] element.');
419
+ }
420
+ return scrollbar;
421
+ }
422
+ /**
423
+ * The draggable thumb inside a `[forScrollAreaScrollbar]`. Sizes itself
424
+ * proportionally to viewport / content and translates along the track
425
+ * based on `scrollLeft` / `scrollTop`. Pointer-drag scrolls the viewport
426
+ * proportionally.
427
+ */
428
+ class ForScrollAreaThumb {
429
+ scrollbar = injectRequiredScrollbar();
430
+ #host = inject(ElementRef).nativeElement;
431
+ #document = inject(DOCUMENT);
432
+ #dragging = signal(false, /* @ts-ignore */
433
+ ...(ngDevMode ? [{ debugName: "#dragging" }] : /* istanbul ignore next */ []));
434
+ #dragStartPointer = 0;
435
+ #dragStartScroll = 0;
436
+ constructor() {
437
+ inject(DestroyRef).onDestroy(() => this.#endDrag());
438
+ }
439
+ /** Track length in CSS pixels (reactive — derived from the scrollbar's measured size). */
440
+ #trackLength = computed(() => {
441
+ const size = this.scrollbar.size();
442
+ if (!size)
443
+ return 0;
444
+ return this.scrollbar.orientation() === 'horizontal' ? size.width : size.height;
445
+ }, /* @ts-ignore */
446
+ ...(ngDevMode ? [{ debugName: "#trackLength" }] : /* istanbul ignore next */ []));
447
+ #ratio = computed(() => {
448
+ const ctx = this.scrollbar.ctx;
449
+ if (this.scrollbar.orientation() === 'horizontal') {
450
+ const sw = ctx.scrollWidth();
451
+ if (sw <= 0)
452
+ return 0;
453
+ return Math.min(1, ctx.clientWidth() / sw);
454
+ }
455
+ const sh = ctx.scrollHeight();
456
+ if (sh <= 0)
457
+ return 0;
458
+ return Math.min(1, ctx.clientHeight() / sh);
459
+ }, /* @ts-ignore */
460
+ ...(ngDevMode ? [{ debugName: "#ratio" }] : /* istanbul ignore next */ []));
461
+ #thumbSize = computed(() => {
462
+ const tl = this.#trackLength();
463
+ const r = this.#ratio();
464
+ if (tl === 0 || r === 0)
465
+ return 0;
466
+ return Math.max(MIN_THUMB_SIZE, Math.floor(tl * r));
467
+ }, /* @ts-ignore */
468
+ ...(ngDevMode ? [{ debugName: "#thumbSize" }] : /* istanbul ignore next */ []));
469
+ #thumbOffset = computed(() => {
470
+ const ctx = this.scrollbar.ctx;
471
+ const tl = this.#trackLength();
472
+ const tsz = this.#thumbSize();
473
+ if (this.scrollbar.orientation() === 'horizontal') {
474
+ const max = ctx.scrollWidth() - ctx.clientWidth();
475
+ if (max <= 0)
476
+ return 0;
477
+ const left = this.#normalizeScrollLeft(ctx.scrollLeft(), max);
478
+ return (left / max) * (tl - tsz) || 0;
479
+ }
480
+ const max = ctx.scrollHeight() - ctx.clientHeight();
481
+ if (max <= 0)
482
+ return 0;
483
+ return (ctx.scrollTop() / max) * (tl - tsz) || 0;
484
+ }, /* @ts-ignore */
485
+ ...(ngDevMode ? [{ debugName: "#thumbOffset" }] : /* istanbul ignore next */ []));
486
+ /**
487
+ * Normalise the viewport's `scrollLeft` to a left-edge-origin value in
488
+ * `[0, max]`. In LTR `scrollLeft` is already left-origin. In RTL the browser
489
+ * reports `scrollLeft` in the negative model (`0` at rest with the content's
490
+ * right edge flush, `-max` when scrolled fully left), so a left-origin
491
+ * position is `scrollLeft + max` — `max` at rest (thumb pinned to the right)
492
+ * down to `0` when scrolled forward.
493
+ */
494
+ #normalizeScrollLeft(scrollLeft, max) {
495
+ return this.scrollbar.ctx.dir() === 'rtl' ? scrollLeft + max : scrollLeft;
496
+ }
497
+ widthPx() {
498
+ return this.scrollbar.orientation() === 'horizontal' ? this.#thumbSize() : null;
499
+ }
500
+ heightPx() {
501
+ return this.scrollbar.orientation() === 'vertical' ? this.#thumbSize() : null;
502
+ }
503
+ leftPx() {
504
+ return this.scrollbar.orientation() === 'horizontal' ? 0 : null;
505
+ }
506
+ topPx() {
507
+ return this.scrollbar.orientation() === 'vertical' ? 0 : null;
508
+ }
509
+ transformValue() {
510
+ if (this.scrollbar.orientation() === 'horizontal') {
511
+ return `translateX(${this.#thumbOffset()}px)`;
512
+ }
513
+ return `translateY(${this.#thumbOffset()}px)`;
514
+ }
515
+ onPointerDown(event) {
516
+ if (event.button !== 0)
517
+ return;
518
+ event.preventDefault();
519
+ this.#dragging.set(true);
520
+ this.scrollbar.setDragging(true);
521
+ this.#host.setPointerCapture(event.pointerId);
522
+ this.#dragStartPointer =
523
+ this.scrollbar.orientation() === 'horizontal' ? event.clientX : event.clientY;
524
+ const ctx = this.scrollbar.ctx;
525
+ this.#dragStartScroll =
526
+ this.scrollbar.orientation() === 'horizontal' ? ctx.scrollLeft() : ctx.scrollTop();
527
+ // Listen on the owner document, not the thumb element: pointer capture is
528
+ // set on the thumb (so the gesture stays bound to this pointer), but the
529
+ // captured node can be removed mid-drag when the scrollbar self-hides
530
+ // (`type="hover"` / `"scroll"`). Document-level listeners keep firing after
531
+ // that removal, so the drag is not silently aborted. `lostpointercapture`
532
+ // tears the gesture down if capture is otherwise lost.
533
+ const doc = this.#document;
534
+ doc.addEventListener('pointermove', this.#onPointerMove);
535
+ doc.addEventListener('pointerup', this.#onPointerUp);
536
+ doc.addEventListener('pointercancel', this.#onPointerUp);
537
+ }
538
+ onLostPointerCapture() {
539
+ this.#endDrag();
540
+ }
541
+ #onPointerMove = (event) => {
542
+ if (!this.#dragging())
543
+ return;
544
+ const ctx = this.scrollbar.ctx;
545
+ const viewport = ctx.viewport();
546
+ if (!viewport)
547
+ return;
548
+ const tl = this.#trackLength();
549
+ const tsz = this.#thumbSize();
550
+ if (tl - tsz <= 0)
551
+ return;
552
+ if (this.scrollbar.orientation() === 'horizontal') {
553
+ const delta = event.clientX - this.#dragStartPointer;
554
+ const scrollMax = ctx.scrollWidth() - ctx.clientWidth();
555
+ const scrollDelta = (delta / (tl - tsz)) * scrollMax;
556
+ viewport.scrollLeft = this.#dragStartScroll + scrollDelta;
557
+ }
558
+ else {
559
+ const delta = event.clientY - this.#dragStartPointer;
560
+ const scrollMax = ctx.scrollHeight() - ctx.clientHeight();
561
+ const scrollDelta = (delta / (tl - tsz)) * scrollMax;
562
+ viewport.scrollTop = this.#dragStartScroll + scrollDelta;
563
+ }
564
+ };
565
+ #onPointerUp = (event) => {
566
+ this.#endDrag();
567
+ if (this.#host.hasPointerCapture(event.pointerId)) {
568
+ this.#host.releasePointerCapture(event.pointerId);
569
+ }
570
+ };
571
+ #endDrag() {
572
+ this.#dragging.set(false);
573
+ this.scrollbar.setDragging(false);
574
+ const doc = this.#document;
575
+ doc.removeEventListener('pointermove', this.#onPointerMove);
576
+ doc.removeEventListener('pointerup', this.#onPointerUp);
577
+ doc.removeEventListener('pointercancel', this.#onPointerUp);
578
+ }
579
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollAreaThumb, deps: [], target: i0.ɵɵFactoryTarget.Directive });
580
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: ForScrollAreaThumb, isStandalone: true, selector: "[forScrollAreaThumb]", host: { listeners: { "pointerdown": "onPointerDown($event)", "lostpointercapture": "onLostPointerCapture()" }, properties: { "style.position": "\"absolute\"", "style.width.px": "widthPx()", "style.height.px": "heightPx()", "style.left.px": "leftPx()", "style.top.px": "topPx()", "style.transform": "transformValue()", "attr.data-orientation": "scrollbar.orientation()", "attr.data-state": "scrollbar.state()" } }, exportAs: ["forScrollAreaThumb"], ngImport: i0 });
581
+ }
582
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollAreaThumb, decorators: [{
583
+ type: Directive,
584
+ args: [{
585
+ selector: '[forScrollAreaThumb]',
586
+ exportAs: 'forScrollAreaThumb',
587
+ host: {
588
+ '[style.position]': '"absolute"',
589
+ '[style.width.px]': 'widthPx()',
590
+ '[style.height.px]': 'heightPx()',
591
+ '[style.left.px]': 'leftPx()',
592
+ '[style.top.px]': 'topPx()',
593
+ '[style.transform]': 'transformValue()',
594
+ '[attr.data-orientation]': 'scrollbar.orientation()',
595
+ '[attr.data-state]': 'scrollbar.state()',
596
+ '(pointerdown)': 'onPointerDown($event)',
597
+ '(lostpointercapture)': 'onLostPointerCapture()',
598
+ },
599
+ }]
600
+ }], ctorParameters: () => [] });
601
+
602
+ /**
603
+ * Filler in the corner where horizontal and vertical scrollbars meet.
604
+ * Shown when both axes overflow, or unconditionally under `type="always"`
605
+ * (both tracks are permanently present then). Visibility is enforced with an
606
+ * inline `display: none` (which beats any author `display` rule a consumer
607
+ * applies via a class) in addition to the `hidden` attribute that removes it
608
+ * from the a11y tree.
609
+ */
610
+ class ForScrollAreaCorner {
611
+ ctx = injectScrollAreaContext('ForScrollAreaCorner');
612
+ visible = computed(() => {
613
+ if (this.ctx.type() === 'always')
614
+ return true;
615
+ const hOverflow = this.ctx.scrollWidth() - this.ctx.clientWidth() > 1;
616
+ const vOverflow = this.ctx.scrollHeight() - this.ctx.clientHeight() > 1;
617
+ return hOverflow && vOverflow;
618
+ }, /* @ts-ignore */
619
+ ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
620
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollAreaCorner, deps: [], target: i0.ɵɵFactoryTarget.Directive });
621
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: ForScrollAreaCorner, isStandalone: true, selector: "[forScrollAreaCorner]", host: { properties: { "hidden": "!visible()", "style.display": "visible() ? null : \"none\"" } }, exportAs: ["forScrollAreaCorner"], ngImport: i0 });
622
+ }
623
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForScrollAreaCorner, decorators: [{
624
+ type: Directive,
625
+ args: [{
626
+ selector: '[forScrollAreaCorner]',
627
+ exportAs: 'forScrollAreaCorner',
628
+ host: {
629
+ '[hidden]': '!visible()',
630
+ '[style.display]': 'visible() ? null : "none"',
631
+ },
632
+ }]
633
+ }] });
634
+
635
+ /**
636
+ * Generated bundle index. Do not edit.
637
+ */
638
+
639
+ export { FOR_SCROLL_AREA_CONTEXT, FOR_SCROLL_AREA_DEFAULTS, ForScrollArea, ForScrollAreaContent, ForScrollAreaCorner, ForScrollAreaScrollbar, ForScrollAreaThumb, ForScrollAreaViewport, provideForScrollAreaDefaults };
640
+ //# sourceMappingURL=forty-cdk-scroll-area.mjs.map