@raintonic/formaui 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +145 -0
  3. package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs +806 -0
  4. package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs.map +1 -0
  5. package/fesm2022/raintonic-formaui-cdk-form-field.mjs +86 -0
  6. package/fesm2022/raintonic-formaui-cdk-form-field.mjs.map +1 -0
  7. package/fesm2022/raintonic-formaui-cdk-overlay.mjs +1757 -0
  8. package/fesm2022/raintonic-formaui-cdk-overlay.mjs.map +1 -0
  9. package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs +287 -0
  10. package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs.map +1 -0
  11. package/fesm2022/raintonic-formaui-components-accordion.mjs +217 -0
  12. package/fesm2022/raintonic-formaui-components-accordion.mjs.map +1 -0
  13. package/fesm2022/raintonic-formaui-components-alert.mjs +161 -0
  14. package/fesm2022/raintonic-formaui-components-alert.mjs.map +1 -0
  15. package/fesm2022/raintonic-formaui-components-autocomplete.mjs +726 -0
  16. package/fesm2022/raintonic-formaui-components-autocomplete.mjs.map +1 -0
  17. package/fesm2022/raintonic-formaui-components-avatar.mjs +92 -0
  18. package/fesm2022/raintonic-formaui-components-avatar.mjs.map +1 -0
  19. package/fesm2022/raintonic-formaui-components-badge.mjs +107 -0
  20. package/fesm2022/raintonic-formaui-components-badge.mjs.map +1 -0
  21. package/fesm2022/raintonic-formaui-components-big-menu.mjs +68 -0
  22. package/fesm2022/raintonic-formaui-components-big-menu.mjs.map +1 -0
  23. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs +55 -0
  24. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs.map +1 -0
  25. package/fesm2022/raintonic-formaui-components-button-group.mjs +103 -0
  26. package/fesm2022/raintonic-formaui-components-button-group.mjs.map +1 -0
  27. package/fesm2022/raintonic-formaui-components-button.mjs +241 -0
  28. package/fesm2022/raintonic-formaui-components-button.mjs.map +1 -0
  29. package/fesm2022/raintonic-formaui-components-card.mjs +270 -0
  30. package/fesm2022/raintonic-formaui-components-card.mjs.map +1 -0
  31. package/fesm2022/raintonic-formaui-components-checkbox.mjs +295 -0
  32. package/fesm2022/raintonic-formaui-components-checkbox.mjs.map +1 -0
  33. package/fesm2022/raintonic-formaui-components-data-table.mjs +631 -0
  34. package/fesm2022/raintonic-formaui-components-data-table.mjs.map +1 -0
  35. package/fesm2022/raintonic-formaui-components-date-picker.mjs +1331 -0
  36. package/fesm2022/raintonic-formaui-components-date-picker.mjs.map +1 -0
  37. package/fesm2022/raintonic-formaui-components-divider.mjs +41 -0
  38. package/fesm2022/raintonic-formaui-components-divider.mjs.map +1 -0
  39. package/fesm2022/raintonic-formaui-components-drawer.mjs +190 -0
  40. package/fesm2022/raintonic-formaui-components-drawer.mjs.map +1 -0
  41. package/fesm2022/raintonic-formaui-components-dynamic-form.mjs +266 -0
  42. package/fesm2022/raintonic-formaui-components-dynamic-form.mjs.map +1 -0
  43. package/fesm2022/raintonic-formaui-components-empty-state.mjs +33 -0
  44. package/fesm2022/raintonic-formaui-components-empty-state.mjs.map +1 -0
  45. package/fesm2022/raintonic-formaui-components-file-upload.mjs +246 -0
  46. package/fesm2022/raintonic-formaui-components-file-upload.mjs.map +1 -0
  47. package/fesm2022/raintonic-formaui-components-form-field.mjs +482 -0
  48. package/fesm2022/raintonic-formaui-components-form-field.mjs.map +1 -0
  49. package/fesm2022/raintonic-formaui-components-icon.mjs +117 -0
  50. package/fesm2022/raintonic-formaui-components-icon.mjs.map +1 -0
  51. package/fesm2022/raintonic-formaui-components-input.mjs +327 -0
  52. package/fesm2022/raintonic-formaui-components-input.mjs.map +1 -0
  53. package/fesm2022/raintonic-formaui-components-list.mjs +149 -0
  54. package/fesm2022/raintonic-formaui-components-list.mjs.map +1 -0
  55. package/fesm2022/raintonic-formaui-components-menu.mjs +896 -0
  56. package/fesm2022/raintonic-formaui-components-menu.mjs.map +1 -0
  57. package/fesm2022/raintonic-formaui-components-number-input.mjs +345 -0
  58. package/fesm2022/raintonic-formaui-components-number-input.mjs.map +1 -0
  59. package/fesm2022/raintonic-formaui-components-paginator.mjs +139 -0
  60. package/fesm2022/raintonic-formaui-components-paginator.mjs.map +1 -0
  61. package/fesm2022/raintonic-formaui-components-password-input.mjs +306 -0
  62. package/fesm2022/raintonic-formaui-components-password-input.mjs.map +1 -0
  63. package/fesm2022/raintonic-formaui-components-popover.mjs +451 -0
  64. package/fesm2022/raintonic-formaui-components-popover.mjs.map +1 -0
  65. package/fesm2022/raintonic-formaui-components-progressbar.mjs +148 -0
  66. package/fesm2022/raintonic-formaui-components-progressbar.mjs.map +1 -0
  67. package/fesm2022/raintonic-formaui-components-radio.mjs +260 -0
  68. package/fesm2022/raintonic-formaui-components-radio.mjs.map +1 -0
  69. package/fesm2022/raintonic-formaui-components-select.mjs +1011 -0
  70. package/fesm2022/raintonic-formaui-components-select.mjs.map +1 -0
  71. package/fesm2022/raintonic-formaui-components-side-panel.mjs +150 -0
  72. package/fesm2022/raintonic-formaui-components-side-panel.mjs.map +1 -0
  73. package/fesm2022/raintonic-formaui-components-sidebar.mjs +257 -0
  74. package/fesm2022/raintonic-formaui-components-sidebar.mjs.map +1 -0
  75. package/fesm2022/raintonic-formaui-components-skeleton.mjs +50 -0
  76. package/fesm2022/raintonic-formaui-components-skeleton.mjs.map +1 -0
  77. package/fesm2022/raintonic-formaui-components-slider.mjs +347 -0
  78. package/fesm2022/raintonic-formaui-components-slider.mjs.map +1 -0
  79. package/fesm2022/raintonic-formaui-components-spinner.mjs +63 -0
  80. package/fesm2022/raintonic-formaui-components-spinner.mjs.map +1 -0
  81. package/fesm2022/raintonic-formaui-components-stepper.mjs +317 -0
  82. package/fesm2022/raintonic-formaui-components-stepper.mjs.map +1 -0
  83. package/fesm2022/raintonic-formaui-components-tab.mjs +197 -0
  84. package/fesm2022/raintonic-formaui-components-tab.mjs.map +1 -0
  85. package/fesm2022/raintonic-formaui-components-tag.mjs +78 -0
  86. package/fesm2022/raintonic-formaui-components-tag.mjs.map +1 -0
  87. package/fesm2022/raintonic-formaui-components-time-picker.mjs +644 -0
  88. package/fesm2022/raintonic-formaui-components-time-picker.mjs.map +1 -0
  89. package/fesm2022/raintonic-formaui-components-toggle.mjs +171 -0
  90. package/fesm2022/raintonic-formaui-components-toggle.mjs.map +1 -0
  91. package/fesm2022/raintonic-formaui-components-toolbar.mjs +140 -0
  92. package/fesm2022/raintonic-formaui-components-toolbar.mjs.map +1 -0
  93. package/fesm2022/raintonic-formaui-components-tooltip.mjs +555 -0
  94. package/fesm2022/raintonic-formaui-components-tooltip.mjs.map +1 -0
  95. package/fesm2022/raintonic-formaui-components-tree-select.mjs +314 -0
  96. package/fesm2022/raintonic-formaui-components-tree-select.mjs.map +1 -0
  97. package/fesm2022/raintonic-formaui-components-tree-table.mjs +103 -0
  98. package/fesm2022/raintonic-formaui-components-tree-table.mjs.map +1 -0
  99. package/fesm2022/raintonic-formaui-components-tree.mjs +430 -0
  100. package/fesm2022/raintonic-formaui-components-tree.mjs.map +1 -0
  101. package/fesm2022/raintonic-formaui-core.mjs +62 -0
  102. package/fesm2022/raintonic-formaui-core.mjs.map +1 -0
  103. package/fesm2022/raintonic-formaui-services-dialog.mjs +798 -0
  104. package/fesm2022/raintonic-formaui-services-dialog.mjs.map +1 -0
  105. package/fesm2022/raintonic-formaui-services-notification.mjs +391 -0
  106. package/fesm2022/raintonic-formaui-services-notification.mjs.map +1 -0
  107. package/fesm2022/raintonic-formaui-services-theme.mjs +248 -0
  108. package/fesm2022/raintonic-formaui-services-theme.mjs.map +1 -0
  109. package/fesm2022/raintonic-formaui-test-utils.mjs +66 -0
  110. package/fesm2022/raintonic-formaui-test-utils.mjs.map +1 -0
  111. package/fesm2022/raintonic-formaui.mjs +15 -0
  112. package/fesm2022/raintonic-formaui.mjs.map +1 -0
  113. package/llms-full.txt +1627 -0
  114. package/llms.txt +60 -0
  115. package/package.json +251 -0
  116. package/styles/_fonts-entry.scss +3 -0
  117. package/styles/fonts/dm-mono-400-latin.woff2 +0 -0
  118. package/styles/fonts/inter-tight-latin-italic.woff2 +0 -0
  119. package/styles/fonts/inter-tight-latin.woff2 +0 -0
  120. package/styles/index.scss +127 -0
  121. package/styles/partials/_constants.scss +29 -0
  122. package/styles/partials/_fonts.scss +36 -0
  123. package/styles/partials/_grid.scss +171 -0
  124. package/styles/partials/_mixins.scss +145 -0
  125. package/styles/partials/_motion.scss +252 -0
  126. package/styles/partials/_theme.scss +275 -0
  127. package/styles/partials/_typography.scss +112 -0
  128. package/styles/partials/_utilities.scss +480 -0
  129. package/styles/partials/themes/_dark.scss +254 -0
  130. package/styles/partials/themes/_light.scss +254 -0
  131. package/types/raintonic-formaui-cdk-drag-drop.d.ts +196 -0
  132. package/types/raintonic-formaui-cdk-drag-drop.d.ts.map +1 -0
  133. package/types/raintonic-formaui-cdk-form-field.d.ts +62 -0
  134. package/types/raintonic-formaui-cdk-form-field.d.ts.map +1 -0
  135. package/types/raintonic-formaui-cdk-overlay.d.ts +843 -0
  136. package/types/raintonic-formaui-cdk-overlay.d.ts.map +1 -0
  137. package/types/raintonic-formaui-cdk-virtual-scroll.d.ts +112 -0
  138. package/types/raintonic-formaui-cdk-virtual-scroll.d.ts.map +1 -0
  139. package/types/raintonic-formaui-components-accordion.d.ts +124 -0
  140. package/types/raintonic-formaui-components-accordion.d.ts.map +1 -0
  141. package/types/raintonic-formaui-components-alert.d.ts +143 -0
  142. package/types/raintonic-formaui-components-alert.d.ts.map +1 -0
  143. package/types/raintonic-formaui-components-autocomplete.d.ts +193 -0
  144. package/types/raintonic-formaui-components-autocomplete.d.ts.map +1 -0
  145. package/types/raintonic-formaui-components-avatar.d.ts +52 -0
  146. package/types/raintonic-formaui-components-avatar.d.ts.map +1 -0
  147. package/types/raintonic-formaui-components-badge.d.ts +47 -0
  148. package/types/raintonic-formaui-components-badge.d.ts.map +1 -0
  149. package/types/raintonic-formaui-components-big-menu.d.ts +62 -0
  150. package/types/raintonic-formaui-components-big-menu.d.ts.map +1 -0
  151. package/types/raintonic-formaui-components-breadcrumb.d.ts +26 -0
  152. package/types/raintonic-formaui-components-breadcrumb.d.ts.map +1 -0
  153. package/types/raintonic-formaui-components-button-group.d.ts +61 -0
  154. package/types/raintonic-formaui-components-button-group.d.ts.map +1 -0
  155. package/types/raintonic-formaui-components-button.d.ts +116 -0
  156. package/types/raintonic-formaui-components-button.d.ts.map +1 -0
  157. package/types/raintonic-formaui-components-card.d.ts +191 -0
  158. package/types/raintonic-formaui-components-card.d.ts.map +1 -0
  159. package/types/raintonic-formaui-components-checkbox.d.ts +132 -0
  160. package/types/raintonic-formaui-components-checkbox.d.ts.map +1 -0
  161. package/types/raintonic-formaui-components-data-table.d.ts +368 -0
  162. package/types/raintonic-formaui-components-data-table.d.ts.map +1 -0
  163. package/types/raintonic-formaui-components-date-picker.d.ts +341 -0
  164. package/types/raintonic-formaui-components-date-picker.d.ts.map +1 -0
  165. package/types/raintonic-formaui-components-divider.d.ts +21 -0
  166. package/types/raintonic-formaui-components-divider.d.ts.map +1 -0
  167. package/types/raintonic-formaui-components-drawer.d.ts +48 -0
  168. package/types/raintonic-formaui-components-drawer.d.ts.map +1 -0
  169. package/types/raintonic-formaui-components-dynamic-form.d.ts +412 -0
  170. package/types/raintonic-formaui-components-dynamic-form.d.ts.map +1 -0
  171. package/types/raintonic-formaui-components-empty-state.d.ts +14 -0
  172. package/types/raintonic-formaui-components-empty-state.d.ts.map +1 -0
  173. package/types/raintonic-formaui-components-file-upload.d.ts +77 -0
  174. package/types/raintonic-formaui-components-file-upload.d.ts.map +1 -0
  175. package/types/raintonic-formaui-components-form-field.d.ts +271 -0
  176. package/types/raintonic-formaui-components-form-field.d.ts.map +1 -0
  177. package/types/raintonic-formaui-components-icon.d.ts +61 -0
  178. package/types/raintonic-formaui-components-icon.d.ts.map +1 -0
  179. package/types/raintonic-formaui-components-input.d.ts +149 -0
  180. package/types/raintonic-formaui-components-input.d.ts.map +1 -0
  181. package/types/raintonic-formaui-components-list.d.ts +48 -0
  182. package/types/raintonic-formaui-components-list.d.ts.map +1 -0
  183. package/types/raintonic-formaui-components-menu.d.ts +403 -0
  184. package/types/raintonic-formaui-components-menu.d.ts.map +1 -0
  185. package/types/raintonic-formaui-components-number-input.d.ts +127 -0
  186. package/types/raintonic-formaui-components-number-input.d.ts.map +1 -0
  187. package/types/raintonic-formaui-components-paginator.d.ts +37 -0
  188. package/types/raintonic-formaui-components-paginator.d.ts.map +1 -0
  189. package/types/raintonic-formaui-components-password-input.d.ts +111 -0
  190. package/types/raintonic-formaui-components-password-input.d.ts.map +1 -0
  191. package/types/raintonic-formaui-components-popover.d.ts +131 -0
  192. package/types/raintonic-formaui-components-popover.d.ts.map +1 -0
  193. package/types/raintonic-formaui-components-progressbar.d.ts +111 -0
  194. package/types/raintonic-formaui-components-progressbar.d.ts.map +1 -0
  195. package/types/raintonic-formaui-components-radio.d.ts +95 -0
  196. package/types/raintonic-formaui-components-radio.d.ts.map +1 -0
  197. package/types/raintonic-formaui-components-select.d.ts +307 -0
  198. package/types/raintonic-formaui-components-select.d.ts.map +1 -0
  199. package/types/raintonic-formaui-components-side-panel.d.ts +51 -0
  200. package/types/raintonic-formaui-components-side-panel.d.ts.map +1 -0
  201. package/types/raintonic-formaui-components-sidebar.d.ts +174 -0
  202. package/types/raintonic-formaui-components-sidebar.d.ts.map +1 -0
  203. package/types/raintonic-formaui-components-skeleton.d.ts +20 -0
  204. package/types/raintonic-formaui-components-skeleton.d.ts.map +1 -0
  205. package/types/raintonic-formaui-components-slider.d.ts +108 -0
  206. package/types/raintonic-formaui-components-slider.d.ts.map +1 -0
  207. package/types/raintonic-formaui-components-spinner.d.ts +42 -0
  208. package/types/raintonic-formaui-components-spinner.d.ts.map +1 -0
  209. package/types/raintonic-formaui-components-stepper.d.ts +126 -0
  210. package/types/raintonic-formaui-components-stepper.d.ts.map +1 -0
  211. package/types/raintonic-formaui-components-tab.d.ts +96 -0
  212. package/types/raintonic-formaui-components-tab.d.ts.map +1 -0
  213. package/types/raintonic-formaui-components-tag.d.ts +34 -0
  214. package/types/raintonic-formaui-components-tag.d.ts.map +1 -0
  215. package/types/raintonic-formaui-components-time-picker.d.ts +172 -0
  216. package/types/raintonic-formaui-components-time-picker.d.ts.map +1 -0
  217. package/types/raintonic-formaui-components-toggle.d.ts +70 -0
  218. package/types/raintonic-formaui-components-toggle.d.ts.map +1 -0
  219. package/types/raintonic-formaui-components-toolbar.d.ts +128 -0
  220. package/types/raintonic-formaui-components-toolbar.d.ts.map +1 -0
  221. package/types/raintonic-formaui-components-tooltip.d.ts +268 -0
  222. package/types/raintonic-formaui-components-tooltip.d.ts.map +1 -0
  223. package/types/raintonic-formaui-components-tree-select.d.ts +80 -0
  224. package/types/raintonic-formaui-components-tree-select.d.ts.map +1 -0
  225. package/types/raintonic-formaui-components-tree-table.d.ts +90 -0
  226. package/types/raintonic-formaui-components-tree-table.d.ts.map +1 -0
  227. package/types/raintonic-formaui-components-tree.d.ts +104 -0
  228. package/types/raintonic-formaui-components-tree.d.ts.map +1 -0
  229. package/types/raintonic-formaui-core.d.ts +115 -0
  230. package/types/raintonic-formaui-core.d.ts.map +1 -0
  231. package/types/raintonic-formaui-services-dialog.d.ts +451 -0
  232. package/types/raintonic-formaui-services-dialog.d.ts.map +1 -0
  233. package/types/raintonic-formaui-services-notification.d.ts +221 -0
  234. package/types/raintonic-formaui-services-notification.d.ts.map +1 -0
  235. package/types/raintonic-formaui-services-theme.d.ts +126 -0
  236. package/types/raintonic-formaui-services-theme.d.ts.map +1 -0
  237. package/types/raintonic-formaui-test-utils.d.ts +24 -0
  238. package/types/raintonic-formaui-test-utils.d.ts.map +1 -0
  239. package/types/raintonic-formaui.d.ts +4 -0
  240. package/types/raintonic-formaui.d.ts.map +1 -0
@@ -0,0 +1,806 @@
1
+ import * as i0 from '@angular/core';
2
+ import { signal, Injectable, input, output, inject, ElementRef, Renderer2, NgZone, Directive, effect, contentChildren } from '@angular/core';
3
+ import { DOCUMENT } from '@angular/common';
4
+
5
+ class FuiDragRegistryService {
6
+ activeDrag = signal(null, ...(ngDevMode ? [{ debugName: "activeDrag" }] : /* istanbul ignore next */ []));
7
+ _dropZones = new Set();
8
+ _sortables = new Set();
9
+ registerDropZone(zone) {
10
+ this._dropZones.add(zone);
11
+ }
12
+ unregisterDropZone(zone) {
13
+ this._dropZones.delete(zone);
14
+ }
15
+ registerSortable(sortable) {
16
+ this._sortables.add(sortable);
17
+ }
18
+ unregisterSortable(sortable) {
19
+ this._sortables.delete(sortable);
20
+ }
21
+ startDrag(drag) {
22
+ this.activeDrag.set(drag);
23
+ }
24
+ updateDrag(position, _event) {
25
+ const active = this.activeDrag();
26
+ if (active) {
27
+ active.currentPosition = position;
28
+ this.activeDrag.set({ ...active });
29
+ }
30
+ }
31
+ endDrag(_event) {
32
+ this.activeDrag.set(null);
33
+ }
34
+ cancelDrag() {
35
+ this.activeDrag.set(null);
36
+ }
37
+ getDropZoneAtPoint(point) {
38
+ const preview = this.activeDrag()?.previewElement;
39
+ if (preview) {
40
+ preview.style.pointerEvents = 'none';
41
+ }
42
+ const elementAtPoint = typeof document.elementFromPoint === 'function' ? document.elementFromPoint(point.x, point.y) : null;
43
+ if (preview) {
44
+ preview.style.pointerEvents = '';
45
+ }
46
+ if (!elementAtPoint) {
47
+ return null;
48
+ }
49
+ for (const zone of this._dropZones) {
50
+ if (zone.element.nativeElement.contains(elementAtPoint)) {
51
+ return zone;
52
+ }
53
+ }
54
+ return null;
55
+ }
56
+ getSortableAtPoint(point) {
57
+ const preview = this.activeDrag()?.previewElement;
58
+ if (preview) {
59
+ preview.style.pointerEvents = 'none';
60
+ }
61
+ const elementAtPoint = typeof document.elementFromPoint === 'function' ? document.elementFromPoint(point.x, point.y) : null;
62
+ if (preview) {
63
+ preview.style.pointerEvents = '';
64
+ }
65
+ if (!elementAtPoint) {
66
+ return null;
67
+ }
68
+ for (const sortable of this._sortables) {
69
+ if (sortable.element.nativeElement.contains(elementAtPoint)) {
70
+ return sortable;
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDragRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
76
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDragRegistryService, providedIn: 'root' });
77
+ }
78
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDragRegistryService, decorators: [{
79
+ type: Injectable,
80
+ args: [{ providedIn: 'root' }]
81
+ }] });
82
+
83
+ class FuiAutoScroller {
84
+ _rafId = null;
85
+ _scrollNode = null;
86
+ SCROLL_PROXIMITY_THRESHOLD = 30;
87
+ MAX_SCROLL_SPEED = 15;
88
+ checkAutoScroll(pointerPosition) {
89
+ const scrollNode = this._getScrollableAtPoint(pointerPosition);
90
+ if (!scrollNode) {
91
+ this._stopAutoScroll();
92
+ return;
93
+ }
94
+ this._scrollNode = scrollNode;
95
+ const rect = scrollNode.getBoundingClientRect();
96
+ let speedX = 0;
97
+ let speedY = 0;
98
+ if (pointerPosition.y - rect.top < this.SCROLL_PROXIMITY_THRESHOLD) {
99
+ speedY = -this._calculateSpeed(pointerPosition.y - rect.top);
100
+ }
101
+ if (rect.bottom - pointerPosition.y < this.SCROLL_PROXIMITY_THRESHOLD) {
102
+ speedY = this._calculateSpeed(rect.bottom - pointerPosition.y);
103
+ }
104
+ if (pointerPosition.x - rect.left < this.SCROLL_PROXIMITY_THRESHOLD) {
105
+ speedX = -this._calculateSpeed(pointerPosition.x - rect.left);
106
+ }
107
+ if (rect.right - pointerPosition.x < this.SCROLL_PROXIMITY_THRESHOLD) {
108
+ speedX = this._calculateSpeed(rect.right - pointerPosition.x);
109
+ }
110
+ if (speedX !== 0 || speedY !== 0) {
111
+ this._startAutoScroll(speedX, speedY);
112
+ }
113
+ else {
114
+ this._stopAutoScroll();
115
+ }
116
+ }
117
+ stop() {
118
+ this._stopAutoScroll();
119
+ }
120
+ destroy() {
121
+ this._stopAutoScroll();
122
+ }
123
+ _calculateSpeed(distanceFromEdge) {
124
+ const ratio = 1 - distanceFromEdge / this.SCROLL_PROXIMITY_THRESHOLD;
125
+ return Math.ceil(ratio * this.MAX_SCROLL_SPEED);
126
+ }
127
+ _startAutoScroll(speedX, speedY) {
128
+ if (this._rafId !== null) {
129
+ cancelAnimationFrame(this._rafId);
130
+ }
131
+ const scroll = () => {
132
+ if (this._scrollNode) {
133
+ this._scrollNode.scrollTop += speedY;
134
+ this._scrollNode.scrollLeft += speedX;
135
+ }
136
+ this._rafId = requestAnimationFrame(scroll);
137
+ };
138
+ this._rafId = requestAnimationFrame(scroll);
139
+ }
140
+ _stopAutoScroll() {
141
+ if (this._rafId !== null) {
142
+ cancelAnimationFrame(this._rafId);
143
+ this._rafId = null;
144
+ }
145
+ }
146
+ _getScrollableAtPoint(point) {
147
+ if (typeof document.elementFromPoint !== 'function') {
148
+ return null;
149
+ }
150
+ let element = document.elementFromPoint(point.x, point.y);
151
+ while (element) {
152
+ const style = window.getComputedStyle(element);
153
+ if ((style.overflowY === 'auto' || style.overflowY === 'scroll') && element.scrollHeight > element.clientHeight) {
154
+ return element;
155
+ }
156
+ if ((style.overflowX === 'auto' || style.overflowX === 'scroll') && element.scrollWidth > element.clientWidth) {
157
+ return element;
158
+ }
159
+ element = element.parentElement;
160
+ }
161
+ return null;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Internal helper that tracks positional state for a single drag operation.
167
+ * Used by FuiDragDirective to keep the directive itself cleaner.
168
+ */
169
+ class FuiDragRef {
170
+ startPosition = { x: 0, y: 0 };
171
+ currentPosition = { x: 0, y: 0 };
172
+ _active = false;
173
+ get active() {
174
+ return this._active;
175
+ }
176
+ start(x, y) {
177
+ this.startPosition = { x, y };
178
+ this.currentPosition = { x, y };
179
+ this._active = true;
180
+ }
181
+ move(x, y) {
182
+ this.currentPosition = { x, y };
183
+ }
184
+ get distance() {
185
+ return {
186
+ x: this.currentPosition.x - this.startPosition.x,
187
+ y: this.currentPosition.y - this.startPosition.y,
188
+ };
189
+ }
190
+ reset() {
191
+ this.startPosition = { x: 0, y: 0 };
192
+ this.currentPosition = { x: 0, y: 0 };
193
+ this._active = false;
194
+ }
195
+ }
196
+
197
+ class FuiDragDirective {
198
+ fuiDragData = input(null, ...(ngDevMode ? [{ debugName: "fuiDragData" }] : /* istanbul ignore next */ []));
199
+ fuiDragDisabled = input(false, ...(ngDevMode ? [{ debugName: "fuiDragDisabled" }] : /* istanbul ignore next */ []));
200
+ fuiDragLockAxis = input('free', ...(ngDevMode ? [{ debugName: "fuiDragLockAxis" }] : /* istanbul ignore next */ []));
201
+ fuiDragPreviewTemplate = input(null, ...(ngDevMode ? [{ debugName: "fuiDragPreviewTemplate" }] : /* istanbul ignore next */ []));
202
+ fuiDragPlaceholderTemplate = input(null, ...(ngDevMode ? [{ debugName: "fuiDragPlaceholderTemplate" }] : /* istanbul ignore next */ []));
203
+ fuiDragBoundary = input(null, ...(ngDevMode ? [{ debugName: "fuiDragBoundary" }] : /* istanbul ignore next */ []));
204
+ fuiDragStarted = output();
205
+ fuiDragMoved = output();
206
+ fuiDragEnded = output();
207
+ fuiDragDropped = output();
208
+ element = inject((ElementRef));
209
+ _isDragging = signal(false, ...(ngDevMode ? [{ debugName: "_isDragging" }] : /* istanbul ignore next */ []));
210
+ _registry = inject(FuiDragRegistryService);
211
+ _renderer = inject(Renderer2);
212
+ _document = inject(DOCUMENT);
213
+ _ngZone = inject(NgZone);
214
+ _autoScroller = new FuiAutoScroller();
215
+ _dragRef = new FuiDragRef();
216
+ _previewElement = null;
217
+ _placeholderElement = null;
218
+ _pointerMoveHandler = null;
219
+ _pointerUpHandler = null;
220
+ _boundaryRect = null;
221
+ // Keyboard drag state
222
+ _keyboardDragging = false;
223
+ _keyboardPosition = { x: 0, y: 0 };
224
+ KEYBOARD_STEP = 10;
225
+ _onPointerDown(event) {
226
+ if (this.fuiDragDisabled() || event.button !== 0) {
227
+ return;
228
+ }
229
+ event.preventDefault();
230
+ const startPosition = { x: event.clientX, y: event.clientY };
231
+ this._dragRef.start(startPosition.x, startPosition.y);
232
+ this._resolveBoundary();
233
+ this._previewElement = this._createPreview();
234
+ this._updatePreviewPosition(startPosition);
235
+ this._document.body.appendChild(this._previewElement);
236
+ // Create placeholder at source location
237
+ this._placeholderElement = this._createPlaceholder();
238
+ this.element.nativeElement.parentNode?.insertBefore(this._placeholderElement, this.element.nativeElement.nextSibling);
239
+ this._isDragging.set(true);
240
+ this._registry.startDrag({
241
+ source: this,
242
+ previewElement: this._previewElement,
243
+ placeholderElement: this._placeholderElement,
244
+ startPosition,
245
+ currentPosition: { ...startPosition },
246
+ data: this.fuiDragData(),
247
+ });
248
+ this.fuiDragStarted.emit({
249
+ source: this,
250
+ data: this.fuiDragData(),
251
+ pointerPosition: startPosition,
252
+ distance: { x: 0, y: 0 },
253
+ event,
254
+ });
255
+ this._ngZone.runOutsideAngular(() => {
256
+ this._pointerMoveHandler = (e) => {
257
+ this._onPointerMove(e);
258
+ };
259
+ this._pointerUpHandler = (e) => {
260
+ this._onPointerUp(e);
261
+ };
262
+ this._document.addEventListener('pointermove', this._pointerMoveHandler);
263
+ this._document.addEventListener('pointerup', this._pointerUpHandler);
264
+ });
265
+ }
266
+ _onPointerMove(event) {
267
+ const position = this._applyConstraints({ x: event.clientX, y: event.clientY });
268
+ this._dragRef.move(position.x, position.y);
269
+ if (this._previewElement) {
270
+ this._updatePreviewPosition(position);
271
+ }
272
+ this._autoScroller.checkAutoScroll(position);
273
+ this._registry.updateDrag(position, event);
274
+ this._ngZone.run(() => {
275
+ this.fuiDragMoved.emit({
276
+ source: this,
277
+ data: this.fuiDragData(),
278
+ pointerPosition: position,
279
+ distance: this._dragRef.distance,
280
+ event,
281
+ });
282
+ });
283
+ }
284
+ _onPointerUp(event) {
285
+ this._removeListeners();
286
+ this._autoScroller.stop();
287
+ const position = { x: event.clientX, y: event.clientY };
288
+ const dropZone = this._registry.getDropZoneAtPoint(position);
289
+ if (dropZone && !dropZone.fuiDropZoneDisabled()) {
290
+ const predicate = dropZone.fuiDropZonePredicate();
291
+ const accepted = !predicate || predicate(this);
292
+ if (accepted) {
293
+ this._ngZone.run(() => {
294
+ const dropEvent = {
295
+ source: this,
296
+ dragData: this.fuiDragData(),
297
+ dropZoneData: dropZone.fuiDropZoneData(),
298
+ dropZone,
299
+ isPointerOverContainer: true,
300
+ };
301
+ this.fuiDragDropped.emit(dropEvent);
302
+ dropZone.fuiDropped.emit(dropEvent);
303
+ });
304
+ }
305
+ }
306
+ this._cleanupDrag();
307
+ this._ngZone.run(() => {
308
+ this._registry.endDrag(event);
309
+ this.fuiDragEnded.emit({
310
+ source: this,
311
+ data: this.fuiDragData(),
312
+ pointerPosition: position,
313
+ distance: this._dragRef.distance,
314
+ event,
315
+ });
316
+ this._isDragging.set(false);
317
+ });
318
+ this._dragRef.reset();
319
+ }
320
+ _onKeydown(event) {
321
+ if (this.fuiDragDisabled()) {
322
+ return;
323
+ }
324
+ if (!this._keyboardDragging) {
325
+ if (event.key === ' ' || event.key === 'Enter') {
326
+ event.preventDefault();
327
+ this._startKeyboardDrag();
328
+ }
329
+ return;
330
+ }
331
+ switch (event.key) {
332
+ case 'ArrowUp':
333
+ event.preventDefault();
334
+ this._moveKeyboard(0, -this.KEYBOARD_STEP);
335
+ break;
336
+ case 'ArrowDown':
337
+ event.preventDefault();
338
+ this._moveKeyboard(0, this.KEYBOARD_STEP);
339
+ break;
340
+ case 'ArrowLeft':
341
+ event.preventDefault();
342
+ this._moveKeyboard(-this.KEYBOARD_STEP, 0);
343
+ break;
344
+ case 'ArrowRight':
345
+ event.preventDefault();
346
+ this._moveKeyboard(this.KEYBOARD_STEP, 0);
347
+ break;
348
+ case 'Escape':
349
+ event.preventDefault();
350
+ this._cancelKeyboardDrag();
351
+ break;
352
+ case ' ':
353
+ case 'Enter':
354
+ event.preventDefault();
355
+ this._endKeyboardDrag();
356
+ break;
357
+ }
358
+ }
359
+ _startKeyboardDrag() {
360
+ const rect = this.element.nativeElement.getBoundingClientRect();
361
+ const startPosition = {
362
+ x: rect.left + rect.width / 2,
363
+ y: rect.top + rect.height / 2,
364
+ };
365
+ this._keyboardDragging = true;
366
+ this._keyboardPosition = { ...startPosition };
367
+ this._dragRef.start(startPosition.x, startPosition.y);
368
+ this._previewElement = this._createPreview();
369
+ this._updatePreviewPosition(startPosition);
370
+ this._document.body.appendChild(this._previewElement);
371
+ this._isDragging.set(true);
372
+ this._registry.startDrag({
373
+ source: this,
374
+ previewElement: this._previewElement,
375
+ startPosition,
376
+ currentPosition: { ...startPosition },
377
+ data: this.fuiDragData(),
378
+ });
379
+ }
380
+ _moveKeyboard(dx, dy) {
381
+ const axis = this.fuiDragLockAxis();
382
+ if (axis === 'x') {
383
+ dy = 0;
384
+ }
385
+ if (axis === 'y') {
386
+ dx = 0;
387
+ }
388
+ this._keyboardPosition.x += dx;
389
+ this._keyboardPosition.y += dy;
390
+ this._dragRef.move(this._keyboardPosition.x, this._keyboardPosition.y);
391
+ if (this._previewElement) {
392
+ this._updatePreviewPosition(this._keyboardPosition);
393
+ }
394
+ }
395
+ _endKeyboardDrag() {
396
+ const position = this._keyboardPosition;
397
+ const dropZone = this._registry.getDropZoneAtPoint(position);
398
+ if (dropZone && !dropZone.fuiDropZoneDisabled()) {
399
+ const predicate = dropZone.fuiDropZonePredicate();
400
+ const accepted = !predicate || predicate(this);
401
+ if (accepted) {
402
+ const dropEvent = {
403
+ source: this,
404
+ dragData: this.fuiDragData(),
405
+ dropZoneData: dropZone.fuiDropZoneData(),
406
+ dropZone,
407
+ isPointerOverContainer: true,
408
+ };
409
+ this.fuiDragDropped.emit(dropEvent);
410
+ dropZone.fuiDropped.emit(dropEvent);
411
+ }
412
+ }
413
+ this._cleanupDrag();
414
+ this._registry.cancelDrag();
415
+ this._isDragging.set(false);
416
+ this._keyboardDragging = false;
417
+ this._dragRef.reset();
418
+ }
419
+ _cancelKeyboardDrag() {
420
+ this._cleanupDrag();
421
+ this._registry.cancelDrag();
422
+ this._isDragging.set(false);
423
+ this._keyboardDragging = false;
424
+ this._dragRef.reset();
425
+ }
426
+ _createPreview() {
427
+ const sourceEl = this.element.nativeElement;
428
+ const rect = sourceEl.getBoundingClientRect();
429
+ const preview = sourceEl.cloneNode(true);
430
+ preview.classList.add('fui-drag-preview');
431
+ preview.style.position = 'fixed';
432
+ preview.style.width = `${rect.width}px`;
433
+ preview.style.height = `${rect.height}px`;
434
+ preview.style.zIndex = '10000';
435
+ preview.style.pointerEvents = 'none';
436
+ preview.style.margin = '0';
437
+ return preview;
438
+ }
439
+ _createPlaceholder() {
440
+ const sourceEl = this.element.nativeElement;
441
+ const rect = sourceEl.getBoundingClientRect();
442
+ const placeholder = this._document.createElement('div');
443
+ placeholder.classList.add('fui-drag-placeholder');
444
+ placeholder.style.width = `${rect.width}px`;
445
+ placeholder.style.height = `${rect.height}px`;
446
+ placeholder.style.boxSizing = 'border-box';
447
+ return placeholder;
448
+ }
449
+ _updatePreviewPosition(position) {
450
+ if (!this._previewElement) {
451
+ return;
452
+ }
453
+ const sourceRect = this.element.nativeElement.getBoundingClientRect();
454
+ const offsetX = sourceRect.width / 2;
455
+ const offsetY = sourceRect.height / 2;
456
+ this._previewElement.style.left = `${position.x - offsetX}px`;
457
+ this._previewElement.style.top = `${position.y - offsetY}px`;
458
+ }
459
+ _applyConstraints(position) {
460
+ const axis = this.fuiDragLockAxis();
461
+ const start = this._dragRef.startPosition;
462
+ let { x, y } = position;
463
+ if (axis === 'x') {
464
+ y = start.y;
465
+ }
466
+ else if (axis === 'y') {
467
+ x = start.x;
468
+ }
469
+ if (this._boundaryRect) {
470
+ const rect = this._boundaryRect;
471
+ x = Math.max(rect.left, Math.min(x, rect.right));
472
+ y = Math.max(rect.top, Math.min(y, rect.bottom));
473
+ }
474
+ return { x, y };
475
+ }
476
+ /** Pattern allowing simple CSS selectors (tag, class, id, attribute selectors) */
477
+ static _SAFE_SELECTOR_PATTERN = /^[a-zA-Z0-9\-_.#\[\]=~|^$*:" >,+()]+$/;
478
+ _resolveBoundary() {
479
+ const boundary = this.fuiDragBoundary();
480
+ if (!boundary) {
481
+ this._boundaryRect = null;
482
+ return;
483
+ }
484
+ let boundaryElement = null;
485
+ if (typeof boundary === 'string') {
486
+ // Validate selector to prevent injection of malicious strings
487
+ if (!FuiDragDirective._SAFE_SELECTOR_PATTERN.test(boundary)) {
488
+ console.warn(`[FormaUI] Invalid drag boundary selector: "${boundary}"`);
489
+ this._boundaryRect = null;
490
+ return;
491
+ }
492
+ boundaryElement = this._document.querySelector(boundary);
493
+ }
494
+ else {
495
+ boundaryElement = boundary.nativeElement;
496
+ }
497
+ this._boundaryRect = boundaryElement ? boundaryElement.getBoundingClientRect() : null;
498
+ }
499
+ _cleanupDrag() {
500
+ if (this._previewElement?.parentNode) {
501
+ this._previewElement.parentNode.removeChild(this._previewElement);
502
+ }
503
+ this._previewElement = null;
504
+ if (this._placeholderElement?.parentNode) {
505
+ this._placeholderElement.parentNode.removeChild(this._placeholderElement);
506
+ }
507
+ this._placeholderElement = null;
508
+ }
509
+ _removeListeners() {
510
+ if (this._pointerMoveHandler) {
511
+ this._document.removeEventListener('pointermove', this._pointerMoveHandler);
512
+ this._pointerMoveHandler = null;
513
+ }
514
+ if (this._pointerUpHandler) {
515
+ this._document.removeEventListener('pointerup', this._pointerUpHandler);
516
+ this._pointerUpHandler = null;
517
+ }
518
+ }
519
+ ngOnDestroy() {
520
+ this._removeListeners();
521
+ this._cleanupDrag();
522
+ this._autoScroller.destroy();
523
+ this._dragRef.reset();
524
+ }
525
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDragDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
526
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.6", type: FuiDragDirective, isStandalone: true, selector: "[fuiDrag]", inputs: { fuiDragData: { classPropertyName: "fuiDragData", publicName: "fuiDragData", isSignal: true, isRequired: false, transformFunction: null }, fuiDragDisabled: { classPropertyName: "fuiDragDisabled", publicName: "fuiDragDisabled", isSignal: true, isRequired: false, transformFunction: null }, fuiDragLockAxis: { classPropertyName: "fuiDragLockAxis", publicName: "fuiDragLockAxis", isSignal: true, isRequired: false, transformFunction: null }, fuiDragPreviewTemplate: { classPropertyName: "fuiDragPreviewTemplate", publicName: "fuiDragPreviewTemplate", isSignal: true, isRequired: false, transformFunction: null }, fuiDragPlaceholderTemplate: { classPropertyName: "fuiDragPlaceholderTemplate", publicName: "fuiDragPlaceholderTemplate", isSignal: true, isRequired: false, transformFunction: null }, fuiDragBoundary: { classPropertyName: "fuiDragBoundary", publicName: "fuiDragBoundary", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fuiDragStarted: "fuiDragStarted", fuiDragMoved: "fuiDragMoved", fuiDragEnded: "fuiDragEnded", fuiDragDropped: "fuiDragDropped" }, host: { attributes: { "tabindex": "0" }, listeners: { "pointerdown": "_onPointerDown($event)", "keydown": "_onKeydown($event)" }, properties: { "class.fui-drag--dragging": "_isDragging()", "attr.aria-grabbed": "_isDragging()", "attr.aria-roledescription": "\"draggable item\"" }, classAttribute: "fui-drag" }, ngImport: i0 });
527
+ }
528
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDragDirective, decorators: [{
529
+ type: Directive,
530
+ args: [{
531
+ selector: '[fuiDrag]',
532
+ standalone: true,
533
+ host: {
534
+ class: 'fui-drag',
535
+ '[class.fui-drag--dragging]': '_isDragging()',
536
+ '[attr.aria-grabbed]': '_isDragging()',
537
+ '[attr.aria-roledescription]': '"draggable item"',
538
+ tabindex: '0',
539
+ '(pointerdown)': '_onPointerDown($event)',
540
+ '(keydown)': '_onKeydown($event)',
541
+ },
542
+ }]
543
+ }], propDecorators: { fuiDragData: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiDragData", required: false }] }], fuiDragDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiDragDisabled", required: false }] }], fuiDragLockAxis: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiDragLockAxis", required: false }] }], fuiDragPreviewTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiDragPreviewTemplate", required: false }] }], fuiDragPlaceholderTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiDragPlaceholderTemplate", required: false }] }], fuiDragBoundary: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiDragBoundary", required: false }] }], fuiDragStarted: [{ type: i0.Output, args: ["fuiDragStarted"] }], fuiDragMoved: [{ type: i0.Output, args: ["fuiDragMoved"] }], fuiDragEnded: [{ type: i0.Output, args: ["fuiDragEnded"] }], fuiDragDropped: [{ type: i0.Output, args: ["fuiDragDropped"] }] } });
544
+
545
+ class FuiDropZoneDirective {
546
+ fuiDropZoneData = input(null, ...(ngDevMode ? [{ debugName: "fuiDropZoneData" }] : /* istanbul ignore next */ []));
547
+ fuiDropZoneDisabled = input(false, ...(ngDevMode ? [{ debugName: "fuiDropZoneDisabled" }] : /* istanbul ignore next */ []));
548
+ fuiDropZonePredicate = input(null, ...(ngDevMode ? [{ debugName: "fuiDropZonePredicate" }] : /* istanbul ignore next */ []));
549
+ fuiDropZoneEntered = output();
550
+ fuiDropZoneExited = output();
551
+ fuiDropped = output();
552
+ element = inject((ElementRef));
553
+ _isActive = signal(false, ...(ngDevMode ? [{ debugName: "_isActive" }] : /* istanbul ignore next */ []));
554
+ _isOver = signal(false, ...(ngDevMode ? [{ debugName: "_isOver" }] : /* istanbul ignore next */ []));
555
+ _registry = inject(FuiDragRegistryService);
556
+ _wasOver = false;
557
+ constructor() {
558
+ effect(() => {
559
+ const activeDrag = this._registry.activeDrag();
560
+ if (this.fuiDropZoneDisabled()) {
561
+ this._isActive.set(false);
562
+ this._isOver.set(false);
563
+ return;
564
+ }
565
+ if (activeDrag) {
566
+ this._isActive.set(true);
567
+ // Check if pointer is over this drop zone
568
+ const rect = this.element.nativeElement.getBoundingClientRect();
569
+ const pos = activeDrag.currentPosition;
570
+ const isOver = pos.x >= rect.left && pos.x <= rect.right && pos.y >= rect.top && pos.y <= rect.bottom;
571
+ this._isOver.set(isOver);
572
+ if (isOver && !this._wasOver) {
573
+ this.fuiDropZoneEntered.emit({
574
+ source: activeDrag.source,
575
+ data: activeDrag.data,
576
+ pointerPosition: activeDrag.currentPosition,
577
+ distance: {
578
+ x: activeDrag.currentPosition.x - activeDrag.startPosition.x,
579
+ y: activeDrag.currentPosition.y - activeDrag.startPosition.y,
580
+ },
581
+ dropZone: this,
582
+ event: null,
583
+ });
584
+ }
585
+ else if (!isOver && this._wasOver) {
586
+ this.fuiDropZoneExited.emit({
587
+ source: activeDrag.source,
588
+ data: activeDrag.data,
589
+ pointerPosition: activeDrag.currentPosition,
590
+ distance: {
591
+ x: activeDrag.currentPosition.x - activeDrag.startPosition.x,
592
+ y: activeDrag.currentPosition.y - activeDrag.startPosition.y,
593
+ },
594
+ dropZone: this,
595
+ event: null,
596
+ });
597
+ }
598
+ this._wasOver = isOver;
599
+ }
600
+ else {
601
+ this._isActive.set(false);
602
+ this._isOver.set(false);
603
+ this._wasOver = false;
604
+ }
605
+ });
606
+ }
607
+ ngOnInit() {
608
+ this._registry.registerDropZone(this);
609
+ }
610
+ ngOnDestroy() {
611
+ this._registry.unregisterDropZone(this);
612
+ }
613
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDropZoneDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
614
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.6", type: FuiDropZoneDirective, isStandalone: true, selector: "[fuiDropZone]", inputs: { fuiDropZoneData: { classPropertyName: "fuiDropZoneData", publicName: "fuiDropZoneData", isSignal: true, isRequired: false, transformFunction: null }, fuiDropZoneDisabled: { classPropertyName: "fuiDropZoneDisabled", publicName: "fuiDropZoneDisabled", isSignal: true, isRequired: false, transformFunction: null }, fuiDropZonePredicate: { classPropertyName: "fuiDropZonePredicate", publicName: "fuiDropZonePredicate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fuiDropZoneEntered: "fuiDropZoneEntered", fuiDropZoneExited: "fuiDropZoneExited", fuiDropped: "fuiDropped" }, host: { properties: { "class.fui-drop-zone--active": "_isActive()", "class.fui-drop-zone--over": "_isOver()", "attr.aria-dropeffect": "\"move\"" }, classAttribute: "fui-drop-zone" }, ngImport: i0 });
615
+ }
616
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDropZoneDirective, decorators: [{
617
+ type: Directive,
618
+ args: [{
619
+ selector: '[fuiDropZone]',
620
+ standalone: true,
621
+ host: {
622
+ class: 'fui-drop-zone',
623
+ '[class.fui-drop-zone--active]': '_isActive()',
624
+ '[class.fui-drop-zone--over]': '_isOver()',
625
+ '[attr.aria-dropeffect]': '"move"',
626
+ },
627
+ }]
628
+ }], ctorParameters: () => [], propDecorators: { fuiDropZoneData: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiDropZoneData", required: false }] }], fuiDropZoneDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiDropZoneDisabled", required: false }] }], fuiDropZonePredicate: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiDropZonePredicate", required: false }] }], fuiDropZoneEntered: [{ type: i0.Output, args: ["fuiDropZoneEntered"] }], fuiDropZoneExited: [{ type: i0.Output, args: ["fuiDropZoneExited"] }], fuiDropped: [{ type: i0.Output, args: ["fuiDropped"] }] } });
629
+
630
+ class FuiSortableDirective {
631
+ fuiSortableData = input.required(...(ngDevMode ? [{ debugName: "fuiSortableData" }] : /* istanbul ignore next */ []));
632
+ fuiSortableDisabled = input(false, ...(ngDevMode ? [{ debugName: "fuiSortableDisabled" }] : /* istanbul ignore next */ []));
633
+ fuiSortableOrientation = input('vertical', ...(ngDevMode ? [{ debugName: "fuiSortableOrientation" }] : /* istanbul ignore next */ []));
634
+ fuiSortableConnectedTo = input([], ...(ngDevMode ? [{ debugName: "fuiSortableConnectedTo" }] : /* istanbul ignore next */ []));
635
+ fuiSortableSorted = output();
636
+ fuiSortableTransferred = output();
637
+ element = inject((ElementRef));
638
+ _hasDragging = signal(false, ...(ngDevMode ? [{ debugName: "_hasDragging" }] : /* istanbul ignore next */ []));
639
+ _dragItems = contentChildren(FuiDragDirective, ...(ngDevMode ? [{ debugName: "_dragItems" }] : /* istanbul ignore next */ []));
640
+ _registry = inject(FuiDragRegistryService);
641
+ _activeDragStartIndex = -1;
642
+ _currentHoverIndex = -1;
643
+ _siblingRects = [];
644
+ constructor() {
645
+ effect(() => {
646
+ const activeDrag = this._registry.activeDrag();
647
+ if (this.fuiSortableDisabled()) {
648
+ this._hasDragging.set(false);
649
+ return;
650
+ }
651
+ if (activeDrag) {
652
+ const dragItems = this._dragItems();
653
+ const sourceIndex = dragItems.indexOf(activeDrag.source);
654
+ if (sourceIndex >= 0) {
655
+ // Drag originated from this container
656
+ this._hasDragging.set(true);
657
+ if (this._activeDragStartIndex === -1) {
658
+ this._activeDragStartIndex = sourceIndex;
659
+ this._captureRects();
660
+ }
661
+ const insertIndex = this._getInsertionIndex(activeDrag.currentPosition);
662
+ if (insertIndex !== this._currentHoverIndex) {
663
+ this._currentHoverIndex = insertIndex;
664
+ this._applyTransforms(sourceIndex, insertIndex);
665
+ }
666
+ }
667
+ else {
668
+ // Check if drag is over this container (cross-container)
669
+ const rect = this.element.nativeElement.getBoundingClientRect();
670
+ const pos = activeDrag.currentPosition;
671
+ const isOver = pos.x >= rect.left && pos.x <= rect.right && pos.y >= rect.top && pos.y <= rect.bottom;
672
+ if (isOver) {
673
+ this._hasDragging.set(true);
674
+ }
675
+ else {
676
+ this._hasDragging.set(false);
677
+ }
678
+ }
679
+ }
680
+ else {
681
+ // Drag ended - check if we need to emit sort/transfer events
682
+ if (this._hasDragging() && this._activeDragStartIndex >= 0) {
683
+ this._finalizeDrop();
684
+ }
685
+ this._hasDragging.set(false);
686
+ this._activeDragStartIndex = -1;
687
+ this._currentHoverIndex = -1;
688
+ this._clearTransforms();
689
+ }
690
+ });
691
+ }
692
+ ngOnInit() {
693
+ this._registry.registerSortable(this);
694
+ }
695
+ ngOnDestroy() {
696
+ this._registry.unregisterSortable(this);
697
+ }
698
+ _captureRects() {
699
+ const items = this._dragItems();
700
+ this._siblingRects = items.map((item) => item.element.nativeElement.getBoundingClientRect());
701
+ }
702
+ _getInsertionIndex(position) {
703
+ const orientation = this.fuiSortableOrientation();
704
+ for (let i = 0; i < this._siblingRects.length; i++) {
705
+ const rect = this._siblingRects[i];
706
+ if (orientation === 'vertical') {
707
+ const midY = rect.top + rect.height / 2;
708
+ if (position.y < midY) {
709
+ return i;
710
+ }
711
+ }
712
+ else {
713
+ const midX = rect.left + rect.width / 2;
714
+ if (position.x < midX) {
715
+ return i;
716
+ }
717
+ }
718
+ }
719
+ return this._siblingRects.length;
720
+ }
721
+ _applyTransforms(sourceIndex, insertIndex) {
722
+ const items = this._dragItems();
723
+ const orientation = this.fuiSortableOrientation();
724
+ items.forEach((item, i) => {
725
+ if (i === sourceIndex) {
726
+ return; // Skip the dragged item
727
+ }
728
+ const el = item.element.nativeElement;
729
+ let offset = 0;
730
+ if (sourceIndex < insertIndex) {
731
+ // Dragging down/right: shift items between source+1..insert up/left
732
+ if (i > sourceIndex && i < insertIndex) {
733
+ const rect = this._siblingRects[sourceIndex];
734
+ offset = orientation === 'vertical' ? -rect.height : -rect.width;
735
+ }
736
+ }
737
+ else if (sourceIndex > insertIndex) {
738
+ // Dragging up/left: shift items between insert..source-1 down/right
739
+ if (i >= insertIndex && i < sourceIndex) {
740
+ const rect = this._siblingRects[sourceIndex];
741
+ offset = orientation === 'vertical' ? rect.height : rect.width;
742
+ }
743
+ }
744
+ if (orientation === 'vertical') {
745
+ el.style.transform = offset ? `translateY(${offset}px)` : '';
746
+ }
747
+ else {
748
+ el.style.transform = offset ? `translateX(${offset}px)` : '';
749
+ }
750
+ el.style.transition = 'transform 150ms ease';
751
+ });
752
+ }
753
+ _clearTransforms() {
754
+ const items = this._dragItems();
755
+ items.forEach((item) => {
756
+ const el = item.element.nativeElement;
757
+ el.style.transform = '';
758
+ el.style.transition = '';
759
+ });
760
+ }
761
+ _finalizeDrop() {
762
+ if (this._currentHoverIndex >= 0 && this._currentHoverIndex !== this._activeDragStartIndex) {
763
+ const data = [...this.fuiSortableData()];
764
+ const [moved] = data.splice(this._activeDragStartIndex, 1);
765
+ const adjustedIndex = this._currentHoverIndex > this._activeDragStartIndex ? this._currentHoverIndex - 1 : this._currentHoverIndex;
766
+ data.splice(adjustedIndex, 0, moved);
767
+ this.fuiSortableSorted.emit({
768
+ data,
769
+ previousIndex: this._activeDragStartIndex,
770
+ currentIndex: adjustedIndex,
771
+ container: this,
772
+ });
773
+ }
774
+ this._clearTransforms();
775
+ }
776
+ /** Called by external sortables for cross-container transfers. */
777
+ emitTransfer(item, previousContainer, previousIndex, currentIndex) {
778
+ this.fuiSortableTransferred.emit({
779
+ item,
780
+ previousContainer,
781
+ container: this,
782
+ previousIndex,
783
+ currentIndex,
784
+ });
785
+ }
786
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiSortableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
787
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.2.6", type: FuiSortableDirective, isStandalone: true, selector: "[fuiSortable]", inputs: { fuiSortableData: { classPropertyName: "fuiSortableData", publicName: "fuiSortableData", isSignal: true, isRequired: true, transformFunction: null }, fuiSortableDisabled: { classPropertyName: "fuiSortableDisabled", publicName: "fuiSortableDisabled", isSignal: true, isRequired: false, transformFunction: null }, fuiSortableOrientation: { classPropertyName: "fuiSortableOrientation", publicName: "fuiSortableOrientation", isSignal: true, isRequired: false, transformFunction: null }, fuiSortableConnectedTo: { classPropertyName: "fuiSortableConnectedTo", publicName: "fuiSortableConnectedTo", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fuiSortableSorted: "fuiSortableSorted", fuiSortableTransferred: "fuiSortableTransferred" }, host: { properties: { "class.fui-sortable--dragging": "_hasDragging()" }, classAttribute: "fui-sortable" }, queries: [{ propertyName: "_dragItems", predicate: FuiDragDirective, isSignal: true }], ngImport: i0 });
788
+ }
789
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiSortableDirective, decorators: [{
790
+ type: Directive,
791
+ args: [{
792
+ selector: '[fuiSortable]',
793
+ standalone: true,
794
+ host: {
795
+ class: 'fui-sortable',
796
+ '[class.fui-sortable--dragging]': '_hasDragging()',
797
+ },
798
+ }]
799
+ }], ctorParameters: () => [], propDecorators: { fuiSortableData: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiSortableData", required: true }] }], fuiSortableDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiSortableDisabled", required: false }] }], fuiSortableOrientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiSortableOrientation", required: false }] }], fuiSortableConnectedTo: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuiSortableConnectedTo", required: false }] }], fuiSortableSorted: [{ type: i0.Output, args: ["fuiSortableSorted"] }], fuiSortableTransferred: [{ type: i0.Output, args: ["fuiSortableTransferred"] }], _dragItems: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FuiDragDirective), { isSignal: true }] }] } });
800
+
801
+ /**
802
+ * Generated bundle index. Do not edit.
803
+ */
804
+
805
+ export { FuiDragDirective, FuiDragRegistryService, FuiDropZoneDirective, FuiSortableDirective };
806
+ //# sourceMappingURL=raintonic-formaui-cdk-drag-drop.mjs.map