photon-grid-core 0.0.1

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 (555) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +0 -0
  3. package/cell-selection/active-grid-registry.d.ts +37 -0
  4. package/cell-selection/active-grid-registry.d.ts.map +1 -0
  5. package/cell-selection/active-grid-registry.js +25 -0
  6. package/cell-selection/active-grid-registry.js.map +1 -0
  7. package/cell-selection/cell-selection-engine.d.ts +336 -0
  8. package/cell-selection/cell-selection-engine.d.ts.map +1 -0
  9. package/cell-selection/cell-selection-engine.js +1534 -0
  10. package/cell-selection/cell-selection-engine.js.map +1 -0
  11. package/cell-selection/selection-range.d.ts +16 -0
  12. package/cell-selection/selection-range.d.ts.map +1 -0
  13. package/cell-selection/selection-range.js +48 -0
  14. package/cell-selection/selection-range.js.map +1 -0
  15. package/cell-selection/selection-renderer.d.ts +24 -0
  16. package/cell-selection/selection-renderer.d.ts.map +1 -0
  17. package/cell-selection/selection-renderer.js +107 -0
  18. package/cell-selection/selection-renderer.js.map +1 -0
  19. package/chart/chart-analyzer/aggregation-analyzer.d.ts +18 -0
  20. package/chart/chart-analyzer/aggregation-analyzer.d.ts.map +1 -0
  21. package/chart/chart-analyzer/aggregation-analyzer.js +63 -0
  22. package/chart/chart-analyzer/aggregation-analyzer.js.map +1 -0
  23. package/chart/chart-analyzer/bar-analyzer.d.ts +19 -0
  24. package/chart/chart-analyzer/bar-analyzer.d.ts.map +1 -0
  25. package/chart/chart-analyzer/bar-analyzer.js +56 -0
  26. package/chart/chart-analyzer/bar-analyzer.js.map +1 -0
  27. package/chart/chart-analyzer/bubble-analyzer.d.ts +16 -0
  28. package/chart/chart-analyzer/bubble-analyzer.d.ts.map +1 -0
  29. package/chart/chart-analyzer/bubble-analyzer.js +61 -0
  30. package/chart/chart-analyzer/bubble-analyzer.js.map +1 -0
  31. package/chart/chart-analyzer/cardinality-analyzer.d.ts +13 -0
  32. package/chart/chart-analyzer/cardinality-analyzer.d.ts.map +1 -0
  33. package/chart/chart-analyzer/cardinality-analyzer.js +28 -0
  34. package/chart/chart-analyzer/cardinality-analyzer.js.map +1 -0
  35. package/chart/chart-analyzer/dimension-analyzer.d.ts +12 -0
  36. package/chart/chart-analyzer/dimension-analyzer.d.ts.map +1 -0
  37. package/chart/chart-analyzer/dimension-analyzer.js +33 -0
  38. package/chart/chart-analyzer/dimension-analyzer.js.map +1 -0
  39. package/chart/chart-analyzer/histogram-analyzer.d.ts +11 -0
  40. package/chart/chart-analyzer/histogram-analyzer.d.ts.map +1 -0
  41. package/chart/chart-analyzer/histogram-analyzer.js +43 -0
  42. package/chart/chart-analyzer/histogram-analyzer.js.map +1 -0
  43. package/chart/chart-analyzer/index.d.ts +58 -0
  44. package/chart/chart-analyzer/index.d.ts.map +1 -0
  45. package/chart/chart-analyzer/index.js +130 -0
  46. package/chart/chart-analyzer/index.js.map +1 -0
  47. package/chart/chart-analyzer/line-analyzer.d.ts +23 -0
  48. package/chart/chart-analyzer/line-analyzer.d.ts.map +1 -0
  49. package/chart/chart-analyzer/line-analyzer.js +61 -0
  50. package/chart/chart-analyzer/line-analyzer.js.map +1 -0
  51. package/chart/chart-analyzer/measure-analyzer.d.ts +11 -0
  52. package/chart/chart-analyzer/measure-analyzer.d.ts.map +1 -0
  53. package/chart/chart-analyzer/measure-analyzer.js +44 -0
  54. package/chart/chart-analyzer/measure-analyzer.js.map +1 -0
  55. package/chart/chart-analyzer/pie-analyzer.d.ts +19 -0
  56. package/chart/chart-analyzer/pie-analyzer.d.ts.map +1 -0
  57. package/chart/chart-analyzer/pie-analyzer.js +64 -0
  58. package/chart/chart-analyzer/pie-analyzer.js.map +1 -0
  59. package/chart/chart-analyzer/recommendation-engine.d.ts +18 -0
  60. package/chart/chart-analyzer/recommendation-engine.d.ts.map +1 -0
  61. package/chart/chart-analyzer/recommendation-engine.js +82 -0
  62. package/chart/chart-analyzer/recommendation-engine.js.map +1 -0
  63. package/chart/chart-analyzer/scatter-analyzer.d.ts +16 -0
  64. package/chart/chart-analyzer/scatter-analyzer.d.ts.map +1 -0
  65. package/chart/chart-analyzer/scatter-analyzer.js +70 -0
  66. package/chart/chart-analyzer/scatter-analyzer.js.map +1 -0
  67. package/chart/chart-analyzer/types.d.ts +52 -0
  68. package/chart/chart-analyzer/types.d.ts.map +1 -0
  69. package/chart/chart-analyzer/types.js +10 -0
  70. package/chart/chart-analyzer/types.js.map +1 -0
  71. package/chart/chart-analyzer.d.ts +12 -0
  72. package/chart/chart-analyzer.d.ts.map +1 -0
  73. package/chart/chart-analyzer.js +77 -0
  74. package/chart/chart-analyzer.js.map +1 -0
  75. package/chart/chart-data-transformer.d.ts +26 -0
  76. package/chart/chart-data-transformer.d.ts.map +1 -0
  77. package/chart/chart-data-transformer.js +93 -0
  78. package/chart/chart-data-transformer.js.map +1 -0
  79. package/chart/chart-engine.d.ts +38 -0
  80. package/chart/chart-engine.d.ts.map +1 -0
  81. package/chart/chart-engine.js +96 -0
  82. package/chart/chart-engine.js.map +1 -0
  83. package/chart/chart-panel.d.ts +54 -0
  84. package/chart/chart-panel.d.ts.map +1 -0
  85. package/chart/chart-panel.js +350 -0
  86. package/chart/chart-panel.js.map +1 -0
  87. package/chart/chart-renderer.d.ts +93 -0
  88. package/chart/chart-renderer.d.ts.map +1 -0
  89. package/chart/chart-renderer.js +1330 -0
  90. package/chart/chart-renderer.js.map +1 -0
  91. package/chart/sparkline/sparkline-renderer.d.ts +269 -0
  92. package/chart/sparkline/sparkline-renderer.d.ts.map +1 -0
  93. package/chart/sparkline/sparkline-renderer.js +875 -0
  94. package/chart/sparkline/sparkline-renderer.js.map +1 -0
  95. package/chart/sparkline/sparkline.types.d.ts +214 -0
  96. package/chart/sparkline/sparkline.types.d.ts.map +1 -0
  97. package/chart/sparkline/sparkline.types.js +8 -0
  98. package/chart/sparkline/sparkline.types.js.map +1 -0
  99. package/column-groups/column-group-drag-handler.d.ts +169 -0
  100. package/column-groups/column-group-drag-handler.d.ts.map +1 -0
  101. package/column-groups/column-group-drag-handler.js +517 -0
  102. package/column-groups/column-group-drag-handler.js.map +1 -0
  103. package/column-groups/column-group-header-builder.d.ts +106 -0
  104. package/column-groups/column-group-header-builder.d.ts.map +1 -0
  105. package/column-groups/column-group-header-builder.js +311 -0
  106. package/column-groups/column-group-header-builder.js.map +1 -0
  107. package/column-groups/column-group-model.d.ts +248 -0
  108. package/column-groups/column-group-model.d.ts.map +1 -0
  109. package/column-groups/column-group-model.js +668 -0
  110. package/column-groups/column-group-model.js.map +1 -0
  111. package/column-groups/column-group-state-manager.d.ts +110 -0
  112. package/column-groups/column-group-state-manager.d.ts.map +1 -0
  113. package/column-groups/column-group-state-manager.js +153 -0
  114. package/column-groups/column-group-state-manager.js.map +1 -0
  115. package/column-groups/column-group.types.d.ts +250 -0
  116. package/column-groups/column-group.types.d.ts.map +1 -0
  117. package/column-groups/column-group.types.js +20 -0
  118. package/column-groups/column-group.types.js.map +1 -0
  119. package/column-groups/display-group-builder.d.ts +91 -0
  120. package/column-groups/display-group-builder.d.ts.map +1 -0
  121. package/column-groups/display-group-builder.js +225 -0
  122. package/column-groups/display-group-builder.js.map +1 -0
  123. package/column-groups/display-group-drag-handler.d.ts +205 -0
  124. package/column-groups/display-group-drag-handler.d.ts.map +1 -0
  125. package/column-groups/display-group-drag-handler.js +536 -0
  126. package/column-groups/display-group-drag-handler.js.map +1 -0
  127. package/column-groups/display-group-engine.d.ts +310 -0
  128. package/column-groups/display-group-engine.d.ts.map +1 -0
  129. package/column-groups/display-group-engine.js +549 -0
  130. package/column-groups/display-group-engine.js.map +1 -0
  131. package/column-groups/display-group-header-builder.d.ts +94 -0
  132. package/column-groups/display-group-header-builder.d.ts.map +1 -0
  133. package/column-groups/display-group-header-builder.js +224 -0
  134. package/column-groups/display-group-header-builder.js.map +1 -0
  135. package/column-groups/display-group.types.d.ts +140 -0
  136. package/column-groups/display-group.types.d.ts.map +1 -0
  137. package/column-groups/display-group.types.js +2 -0
  138. package/column-groups/display-group.types.js.map +1 -0
  139. package/column-groups/index.d.ts +25 -0
  140. package/column-groups/index.d.ts.map +1 -0
  141. package/column-groups/index.js +26 -0
  142. package/column-groups/index.js.map +1 -0
  143. package/column-groups/logical-group-registry.d.ts +77 -0
  144. package/column-groups/logical-group-registry.d.ts.map +1 -0
  145. package/column-groups/logical-group-registry.js +118 -0
  146. package/column-groups/logical-group-registry.js.map +1 -0
  147. package/core/column-model.d.ts +30 -0
  148. package/core/column-model.d.ts.map +1 -0
  149. package/core/column-model.js +203 -0
  150. package/core/column-model.js.map +1 -0
  151. package/core/grid-api.d.ts +187 -0
  152. package/core/grid-api.d.ts.map +1 -0
  153. package/core/grid-api.js +569 -0
  154. package/core/grid-api.js.map +1 -0
  155. package/core/grid-context.d.ts +61 -0
  156. package/core/grid-context.d.ts.map +1 -0
  157. package/core/grid-context.js +2 -0
  158. package/core/grid-context.js.map +1 -0
  159. package/core/grid-core.d.ts +49 -0
  160. package/core/grid-core.d.ts.map +1 -0
  161. package/core/grid-core.js +675 -0
  162. package/core/grid-core.js.map +1 -0
  163. package/core/grid-store.d.ts +62 -0
  164. package/core/grid-store.d.ts.map +1 -0
  165. package/core/grid-store.js +104 -0
  166. package/core/grid-store.js.map +1 -0
  167. package/core/row-model.d.ts +32 -0
  168. package/core/row-model.d.ts.map +1 -0
  169. package/core/row-model.js +150 -0
  170. package/core/row-model.js.map +1 -0
  171. package/drag-drop/drag-autoscroll.d.ts +14 -0
  172. package/drag-drop/drag-autoscroll.d.ts.map +1 -0
  173. package/drag-drop/drag-autoscroll.js +66 -0
  174. package/drag-drop/drag-autoscroll.js.map +1 -0
  175. package/drag-drop/drag-drop-engine.d.ts +55 -0
  176. package/drag-drop/drag-drop-engine.d.ts.map +1 -0
  177. package/drag-drop/drag-drop-engine.js +179 -0
  178. package/drag-drop/drag-drop-engine.js.map +1 -0
  179. package/drag-drop/drag-preview.d.ts +32 -0
  180. package/drag-drop/drag-preview.d.ts.map +1 -0
  181. package/drag-drop/drag-preview.js +74 -0
  182. package/drag-drop/drag-preview.js.map +1 -0
  183. package/engines/aggregation/aggregation-engine.d.ts +66 -0
  184. package/engines/aggregation/aggregation-engine.d.ts.map +1 -0
  185. package/engines/aggregation/aggregation-engine.js +149 -0
  186. package/engines/aggregation/aggregation-engine.js.map +1 -0
  187. package/engines/clipboard/clipboard-engine.d.ts +89 -0
  188. package/engines/clipboard/clipboard-engine.d.ts.map +1 -0
  189. package/engines/clipboard/clipboard-engine.js +323 -0
  190. package/engines/clipboard/clipboard-engine.js.map +1 -0
  191. package/engines/editing/cell-editor-engine.d.ts +62 -0
  192. package/engines/editing/cell-editor-engine.d.ts.map +1 -0
  193. package/engines/editing/cell-editor-engine.js +359 -0
  194. package/engines/editing/cell-editor-engine.js.map +1 -0
  195. package/engines/editing/custom-dropdown-editor.d.ts +99 -0
  196. package/engines/editing/custom-dropdown-editor.d.ts.map +1 -0
  197. package/engines/editing/custom-dropdown-editor.js +355 -0
  198. package/engines/editing/custom-dropdown-editor.js.map +1 -0
  199. package/engines/editing/value-parser.d.ts +12 -0
  200. package/engines/editing/value-parser.d.ts.map +1 -0
  201. package/engines/editing/value-parser.js +125 -0
  202. package/engines/editing/value-parser.js.map +1 -0
  203. package/engines/export/export-engine.d.ts +16 -0
  204. package/engines/export/export-engine.d.ts.map +1 -0
  205. package/engines/export/export-engine.js +99 -0
  206. package/engines/export/export-engine.js.map +1 -0
  207. package/engines/filter/filter-condition.d.ts +7 -0
  208. package/engines/filter/filter-condition.d.ts.map +1 -0
  209. package/engines/filter/filter-condition.js +126 -0
  210. package/engines/filter/filter-condition.js.map +1 -0
  211. package/engines/filter/filter-engine.d.ts +35 -0
  212. package/engines/filter/filter-engine.d.ts.map +1 -0
  213. package/engines/filter/filter-engine.js +150 -0
  214. package/engines/filter/filter-engine.js.map +1 -0
  215. package/engines/filter/filter-panel.d.ts +103 -0
  216. package/engines/filter/filter-panel.d.ts.map +1 -0
  217. package/engines/filter/filter-panel.js +645 -0
  218. package/engines/filter/filter-panel.js.map +1 -0
  219. package/engines/grouping/group-node.d.ts +21 -0
  220. package/engines/grouping/group-node.d.ts.map +1 -0
  221. package/engines/grouping/group-node.js +96 -0
  222. package/engines/grouping/group-node.js.map +1 -0
  223. package/engines/grouping/grouping-engine.d.ts +33 -0
  224. package/engines/grouping/grouping-engine.d.ts.map +1 -0
  225. package/engines/grouping/grouping-engine.js +118 -0
  226. package/engines/grouping/grouping-engine.js.map +1 -0
  227. package/engines/master-detail/master-detail-engine.d.ts +77 -0
  228. package/engines/master-detail/master-detail-engine.d.ts.map +1 -0
  229. package/engines/master-detail/master-detail-engine.js +199 -0
  230. package/engines/master-detail/master-detail-engine.js.map +1 -0
  231. package/engines/pagination/pagination-engine.d.ts +33 -0
  232. package/engines/pagination/pagination-engine.d.ts.map +1 -0
  233. package/engines/pagination/pagination-engine.js +110 -0
  234. package/engines/pagination/pagination-engine.js.map +1 -0
  235. package/engines/selection/row-selection-engine.d.ts +26 -0
  236. package/engines/selection/row-selection-engine.d.ts.map +1 -0
  237. package/engines/selection/row-selection-engine.js +145 -0
  238. package/engines/selection/row-selection-engine.js.map +1 -0
  239. package/engines/sort/sort-comparator.d.ts +43 -0
  240. package/engines/sort/sort-comparator.d.ts.map +1 -0
  241. package/engines/sort/sort-comparator.js +113 -0
  242. package/engines/sort/sort-comparator.js.map +1 -0
  243. package/engines/sort/sort-engine.d.ts +67 -0
  244. package/engines/sort/sort-engine.d.ts.map +1 -0
  245. package/engines/sort/sort-engine.js +178 -0
  246. package/engines/sort/sort-engine.js.map +1 -0
  247. package/engines/summary/summary-engine.d.ts +17 -0
  248. package/engines/summary/summary-engine.d.ts.map +1 -0
  249. package/engines/summary/summary-engine.js +72 -0
  250. package/engines/summary/summary-engine.js.map +1 -0
  251. package/engines/tree/tree-data-service.d.ts +117 -0
  252. package/engines/tree/tree-data-service.d.ts.map +1 -0
  253. package/engines/tree/tree-data-service.js +296 -0
  254. package/engines/tree/tree-data-service.js.map +1 -0
  255. package/engines/tree/tree-expansion-service.d.ts +35 -0
  256. package/engines/tree/tree-expansion-service.d.ts.map +1 -0
  257. package/engines/tree/tree-expansion-service.js +84 -0
  258. package/engines/tree/tree-expansion-service.js.map +1 -0
  259. package/engines/tree/tree-node.d.ts +40 -0
  260. package/engines/tree/tree-node.d.ts.map +1 -0
  261. package/engines/tree/tree-node.js +199 -0
  262. package/engines/tree/tree-node.js.map +1 -0
  263. package/engines/tree/tree-selection-service.d.ts +35 -0
  264. package/engines/tree/tree-selection-service.d.ts.map +1 -0
  265. package/engines/tree/tree-selection-service.js +72 -0
  266. package/engines/tree/tree-selection-service.js.map +1 -0
  267. package/engines/undo-redo/undo-redo-engine.d.ts +114 -0
  268. package/engines/undo-redo/undo-redo-engine.d.ts.map +1 -0
  269. package/engines/undo-redo/undo-redo-engine.js +165 -0
  270. package/engines/undo-redo/undo-redo-engine.js.map +1 -0
  271. package/event-bus/event-bus.d.ts +21 -0
  272. package/event-bus/event-bus.d.ts.map +1 -0
  273. package/event-bus/event-bus.js +106 -0
  274. package/event-bus/event-bus.js.map +1 -0
  275. package/icons/icon-registry.d.ts +19 -0
  276. package/icons/icon-registry.d.ts.map +1 -0
  277. package/icons/icon-registry.js +37 -0
  278. package/icons/icon-registry.js.map +1 -0
  279. package/icons/icon-renderer.d.ts +18 -0
  280. package/icons/icon-renderer.d.ts.map +1 -0
  281. package/icons/icon-renderer.js +75 -0
  282. package/icons/icon-renderer.js.map +1 -0
  283. package/icons/icon-sets/core-icons.d.ts +2 -0
  284. package/icons/icon-sets/core-icons.d.ts.map +1 -0
  285. package/icons/icon-sets/core-icons.js +48 -0
  286. package/icons/icon-sets/core-icons.js.map +1 -0
  287. package/index.d.ts +72 -0
  288. package/index.d.ts.map +1 -0
  289. package/index.js +54 -0
  290. package/index.js.map +1 -0
  291. package/package.json +64 -0
  292. package/photon-ai/builtins/filter.commands.d.ts +4 -0
  293. package/photon-ai/builtins/filter.commands.d.ts.map +1 -0
  294. package/photon-ai/builtins/filter.commands.js +189 -0
  295. package/photon-ai/builtins/filter.commands.js.map +1 -0
  296. package/photon-ai/builtins/grouping.commands.d.ts +4 -0
  297. package/photon-ai/builtins/grouping.commands.d.ts.map +1 -0
  298. package/photon-ai/builtins/grouping.commands.js +115 -0
  299. package/photon-ai/builtins/grouping.commands.js.map +1 -0
  300. package/photon-ai/builtins/index.d.ts +10 -0
  301. package/photon-ai/builtins/index.d.ts.map +1 -0
  302. package/photon-ai/builtins/index.js +26 -0
  303. package/photon-ai/builtins/index.js.map +1 -0
  304. package/photon-ai/builtins/info.commands.d.ts +4 -0
  305. package/photon-ai/builtins/info.commands.d.ts.map +1 -0
  306. package/photon-ai/builtins/info.commands.js +201 -0
  307. package/photon-ai/builtins/info.commands.js.map +1 -0
  308. package/photon-ai/builtins/move.commands.d.ts +4 -0
  309. package/photon-ai/builtins/move.commands.d.ts.map +1 -0
  310. package/photon-ai/builtins/move.commands.js +53 -0
  311. package/photon-ai/builtins/move.commands.js.map +1 -0
  312. package/photon-ai/builtins/pin.commands.d.ts +4 -0
  313. package/photon-ai/builtins/pin.commands.d.ts.map +1 -0
  314. package/photon-ai/builtins/pin.commands.js +106 -0
  315. package/photon-ai/builtins/pin.commands.js.map +1 -0
  316. package/photon-ai/builtins/selection.commands.d.ts +4 -0
  317. package/photon-ai/builtins/selection.commands.d.ts.map +1 -0
  318. package/photon-ai/builtins/selection.commands.js +102 -0
  319. package/photon-ai/builtins/selection.commands.js.map +1 -0
  320. package/photon-ai/builtins/sort.commands.d.ts +4 -0
  321. package/photon-ai/builtins/sort.commands.d.ts.map +1 -0
  322. package/photon-ai/builtins/sort.commands.js +67 -0
  323. package/photon-ai/builtins/sort.commands.js.map +1 -0
  324. package/photon-ai/builtins/visibility.commands.d.ts +4 -0
  325. package/photon-ai/builtins/visibility.commands.d.ts.map +1 -0
  326. package/photon-ai/builtins/visibility.commands.js +75 -0
  327. package/photon-ai/builtins/visibility.commands.js.map +1 -0
  328. package/photon-ai/command-builder.d.ts +21 -0
  329. package/photon-ai/command-builder.d.ts.map +1 -0
  330. package/photon-ai/command-builder.js +18 -0
  331. package/photon-ai/command-builder.js.map +1 -0
  332. package/photon-ai/command-executor.d.ts +15 -0
  333. package/photon-ai/command-executor.d.ts.map +1 -0
  334. package/photon-ai/command-executor.js +26 -0
  335. package/photon-ai/command-executor.js.map +1 -0
  336. package/photon-ai/entity-resolver.d.ts +121 -0
  337. package/photon-ai/entity-resolver.d.ts.map +1 -0
  338. package/photon-ai/entity-resolver.js +393 -0
  339. package/photon-ai/entity-resolver.js.map +1 -0
  340. package/photon-ai/fuzzy-match.d.ts +12 -0
  341. package/photon-ai/fuzzy-match.d.ts.map +1 -0
  342. package/photon-ai/fuzzy-match.js +37 -0
  343. package/photon-ai/fuzzy-match.js.map +1 -0
  344. package/photon-ai/index.d.ts +15 -0
  345. package/photon-ai/index.d.ts.map +1 -0
  346. package/photon-ai/index.js +13 -0
  347. package/photon-ai/index.js.map +1 -0
  348. package/photon-ai/intent-parser.d.ts +20 -0
  349. package/photon-ai/intent-parser.d.ts.map +1 -0
  350. package/photon-ai/intent-parser.js +52 -0
  351. package/photon-ai/intent-parser.js.map +1 -0
  352. package/photon-ai/photon-ai-memory.d.ts +42 -0
  353. package/photon-ai/photon-ai-memory.d.ts.map +1 -0
  354. package/photon-ai/photon-ai-memory.js +86 -0
  355. package/photon-ai/photon-ai-memory.js.map +1 -0
  356. package/photon-ai/photon-ai-panel.d.ts +54 -0
  357. package/photon-ai/photon-ai-panel.d.ts.map +1 -0
  358. package/photon-ai/photon-ai-panel.js +191 -0
  359. package/photon-ai/photon-ai-panel.js.map +1 -0
  360. package/photon-ai/photon-ai-registry.d.ts +25 -0
  361. package/photon-ai/photon-ai-registry.d.ts.map +1 -0
  362. package/photon-ai/photon-ai-registry.js +41 -0
  363. package/photon-ai/photon-ai-registry.js.map +1 -0
  364. package/photon-ai/photon-ai-service.d.ts +71 -0
  365. package/photon-ai/photon-ai-service.d.ts.map +1 -0
  366. package/photon-ai/photon-ai-service.js +165 -0
  367. package/photon-ai/photon-ai-service.js.map +1 -0
  368. package/photon-ai/photon-ai.types.d.ts +100 -0
  369. package/photon-ai/photon-ai.types.d.ts.map +1 -0
  370. package/photon-ai/photon-ai.types.js +2 -0
  371. package/photon-ai/photon-ai.types.js.map +1 -0
  372. package/photon-ai/query-splitter.d.ts +22 -0
  373. package/photon-ai/query-splitter.d.ts.map +1 -0
  374. package/photon-ai/query-splitter.js +81 -0
  375. package/photon-ai/query-splitter.js.map +1 -0
  376. package/photon-ai/text-normalizer.d.ts +33 -0
  377. package/photon-ai/text-normalizer.d.ts.map +1 -0
  378. package/photon-ai/text-normalizer.js +132 -0
  379. package/photon-ai/text-normalizer.js.map +1 -0
  380. package/renderer/auto-scroller.d.ts +78 -0
  381. package/renderer/auto-scroller.d.ts.map +1 -0
  382. package/renderer/auto-scroller.js +141 -0
  383. package/renderer/auto-scroller.js.map +1 -0
  384. package/renderer/body-renderer.d.ts +191 -0
  385. package/renderer/body-renderer.d.ts.map +1 -0
  386. package/renderer/body-renderer.js +806 -0
  387. package/renderer/body-renderer.js.map +1 -0
  388. package/renderer/cell-renderer.d.ts +26 -0
  389. package/renderer/cell-renderer.d.ts.map +1 -0
  390. package/renderer/cell-renderer.js +201 -0
  391. package/renderer/cell-renderer.js.map +1 -0
  392. package/renderer/column-menu.d.ts +285 -0
  393. package/renderer/column-menu.d.ts.map +1 -0
  394. package/renderer/column-menu.js +873 -0
  395. package/renderer/column-menu.js.map +1 -0
  396. package/renderer/column-style-manager.d.ts +38 -0
  397. package/renderer/column-style-manager.d.ts.map +1 -0
  398. package/renderer/column-style-manager.js +110 -0
  399. package/renderer/column-style-manager.js.map +1 -0
  400. package/renderer/detail-row-renderer.d.ts +153 -0
  401. package/renderer/detail-row-renderer.d.ts.map +1 -0
  402. package/renderer/detail-row-renderer.js +388 -0
  403. package/renderer/detail-row-renderer.js.map +1 -0
  404. package/renderer/dom-utils.d.ts +22 -0
  405. package/renderer/dom-utils.d.ts.map +1 -0
  406. package/renderer/dom-utils.js +132 -0
  407. package/renderer/dom-utils.js.map +1 -0
  408. package/renderer/footer-renderer.d.ts +25 -0
  409. package/renderer/footer-renderer.d.ts.map +1 -0
  410. package/renderer/footer-renderer.js +168 -0
  411. package/renderer/footer-renderer.js.map +1 -0
  412. package/renderer/grid-renderer.d.ts +295 -0
  413. package/renderer/grid-renderer.d.ts.map +1 -0
  414. package/renderer/grid-renderer.js +1456 -0
  415. package/renderer/grid-renderer.js.map +1 -0
  416. package/renderer/group-context-menu.d.ts +79 -0
  417. package/renderer/group-context-menu.d.ts.map +1 -0
  418. package/renderer/group-context-menu.js +238 -0
  419. package/renderer/group-context-menu.js.map +1 -0
  420. package/renderer/group-drop-zone.d.ts +56 -0
  421. package/renderer/group-drop-zone.d.ts.map +1 -0
  422. package/renderer/group-drop-zone.js +376 -0
  423. package/renderer/group-drop-zone.js.map +1 -0
  424. package/renderer/header-renderer.d.ts +264 -0
  425. package/renderer/header-renderer.d.ts.map +1 -0
  426. package/renderer/header-renderer.js +1321 -0
  427. package/renderer/header-renderer.js.map +1 -0
  428. package/renderer/overlay-renderer.d.ts +16 -0
  429. package/renderer/overlay-renderer.d.ts.map +1 -0
  430. package/renderer/overlay-renderer.js +64 -0
  431. package/renderer/overlay-renderer.js.map +1 -0
  432. package/renderer/renderer-resolver.d.ts +18 -0
  433. package/renderer/renderer-resolver.d.ts.map +1 -0
  434. package/renderer/renderer-resolver.js +18 -0
  435. package/renderer/renderer-resolver.js.map +1 -0
  436. package/renderer/row-animator.d.ts +72 -0
  437. package/renderer/row-animator.d.ts.map +1 -0
  438. package/renderer/row-animator.js +175 -0
  439. package/renderer/row-animator.js.map +1 -0
  440. package/renderer/row-drag-renderer.d.ts +58 -0
  441. package/renderer/row-drag-renderer.d.ts.map +1 -0
  442. package/renderer/row-drag-renderer.js +395 -0
  443. package/renderer/row-drag-renderer.js.map +1 -0
  444. package/renderer/row-offset-search.d.ts +17 -0
  445. package/renderer/row-offset-search.d.ts.map +1 -0
  446. package/renderer/row-offset-search.js +31 -0
  447. package/renderer/row-offset-search.js.map +1 -0
  448. package/renderer/row-position-sheet.d.ts +11 -0
  449. package/renderer/row-position-sheet.d.ts.map +1 -0
  450. package/renderer/row-position-sheet.js +29 -0
  451. package/renderer/row-position-sheet.js.map +1 -0
  452. package/renderer/scroll-controller.d.ts +58 -0
  453. package/renderer/scroll-controller.d.ts.map +1 -0
  454. package/renderer/scroll-controller.js +200 -0
  455. package/renderer/scroll-controller.js.map +1 -0
  456. package/renderer/sticky-row-tracker.d.ts +40 -0
  457. package/renderer/sticky-row-tracker.d.ts.map +1 -0
  458. package/renderer/sticky-row-tracker.js +63 -0
  459. package/renderer/sticky-row-tracker.js.map +1 -0
  460. package/renderer/tooltip-renderer.d.ts +36 -0
  461. package/renderer/tooltip-renderer.d.ts.map +1 -0
  462. package/renderer/tooltip-renderer.js +133 -0
  463. package/renderer/tooltip-renderer.js.map +1 -0
  464. package/renderer/tree-cell-renderer.d.ts +37 -0
  465. package/renderer/tree-cell-renderer.d.ts.map +1 -0
  466. package/renderer/tree-cell-renderer.js +75 -0
  467. package/renderer/tree-cell-renderer.js.map +1 -0
  468. package/renderer/tree-sticky-row-tracker.d.ts +62 -0
  469. package/renderer/tree-sticky-row-tracker.d.ts.map +1 -0
  470. package/renderer/tree-sticky-row-tracker.js +120 -0
  471. package/renderer/tree-sticky-row-tracker.js.map +1 -0
  472. package/renderer/virtual-scroll-renderer.d.ts +37 -0
  473. package/renderer/virtual-scroll-renderer.d.ts.map +1 -0
  474. package/renderer/virtual-scroll-renderer.js +133 -0
  475. package/renderer/virtual-scroll-renderer.js.map +1 -0
  476. package/styles/base-styles.d.ts +3 -0
  477. package/styles/base-styles.d.ts.map +1 -0
  478. package/styles/base-styles.js +3045 -0
  479. package/styles/base-styles.js.map +1 -0
  480. package/styles/themes/theme-alpine.d.ts +2 -0
  481. package/styles/themes/theme-alpine.d.ts.map +1 -0
  482. package/styles/themes/theme-alpine.js +120 -0
  483. package/styles/themes/theme-alpine.js.map +1 -0
  484. package/styles/themes/theme-balham.d.ts +2 -0
  485. package/styles/themes/theme-balham.d.ts.map +1 -0
  486. package/styles/themes/theme-balham.js +120 -0
  487. package/styles/themes/theme-balham.js.map +1 -0
  488. package/styles/themes/theme-dark.d.ts +2 -0
  489. package/styles/themes/theme-dark.d.ts.map +1 -0
  490. package/styles/themes/theme-dark.js +216 -0
  491. package/styles/themes/theme-dark.js.map +1 -0
  492. package/styles/themes/theme-material.d.ts +2 -0
  493. package/styles/themes/theme-material.d.ts.map +1 -0
  494. package/styles/themes/theme-material.js +134 -0
  495. package/styles/themes/theme-material.js.map +1 -0
  496. package/styles/themes/theme-quartz.d.ts +2 -0
  497. package/styles/themes/theme-quartz.d.ts.map +1 -0
  498. package/styles/themes/theme-quartz.js +120 -0
  499. package/styles/themes/theme-quartz.js.map +1 -0
  500. package/theme/css-var-injector.d.ts +10 -0
  501. package/theme/css-var-injector.d.ts.map +1 -0
  502. package/theme/css-var-injector.js +63 -0
  503. package/theme/css-var-injector.js.map +1 -0
  504. package/theme/theme-manager.d.ts +20 -0
  505. package/theme/theme-manager.d.ts.map +1 -0
  506. package/theme/theme-manager.js +79 -0
  507. package/theme/theme-manager.js.map +1 -0
  508. package/theme/themes/dark-theme.d.ts +3 -0
  509. package/theme/themes/dark-theme.d.ts.map +1 -0
  510. package/theme/themes/dark-theme.js +149 -0
  511. package/theme/themes/dark-theme.js.map +1 -0
  512. package/theme/themes/light-theme.d.ts +3 -0
  513. package/theme/themes/light-theme.d.ts.map +1 -0
  514. package/theme/themes/light-theme.js +149 -0
  515. package/theme/themes/light-theme.js.map +1 -0
  516. package/types/column.types.d.ts +195 -0
  517. package/types/column.types.d.ts.map +1 -0
  518. package/types/column.types.js +2 -0
  519. package/types/column.types.js.map +1 -0
  520. package/types/event.types.d.ts +213 -0
  521. package/types/event.types.d.ts.map +1 -0
  522. package/types/event.types.js +67 -0
  523. package/types/event.types.js.map +1 -0
  524. package/types/filter.types.d.ts +42 -0
  525. package/types/filter.types.d.ts.map +1 -0
  526. package/types/filter.types.js +2 -0
  527. package/types/filter.types.js.map +1 -0
  528. package/types/grid.types.d.ts +214 -0
  529. package/types/grid.types.d.ts.map +1 -0
  530. package/types/grid.types.js +2 -0
  531. package/types/grid.types.js.map +1 -0
  532. package/types/master-detail.types.d.ts +112 -0
  533. package/types/master-detail.types.d.ts.map +1 -0
  534. package/types/master-detail.types.js +2 -0
  535. package/types/master-detail.types.js.map +1 -0
  536. package/types/photon-ai.types.d.ts +19 -0
  537. package/types/photon-ai.types.d.ts.map +1 -0
  538. package/types/photon-ai.types.js +2 -0
  539. package/types/photon-ai.types.js.map +1 -0
  540. package/types/renderer.types.d.ts +156 -0
  541. package/types/renderer.types.d.ts.map +1 -0
  542. package/types/renderer.types.js +19 -0
  543. package/types/renderer.types.js.map +1 -0
  544. package/types/row.types.d.ts +127 -0
  545. package/types/row.types.d.ts.map +1 -0
  546. package/types/row.types.js +9 -0
  547. package/types/row.types.js.map +1 -0
  548. package/types/theme.types.d.ts +159 -0
  549. package/types/theme.types.d.ts.map +1 -0
  550. package/types/theme.types.js +2 -0
  551. package/types/theme.types.js.map +1 -0
  552. package/types/tree-data.types.d.ts +94 -0
  553. package/types/tree-data.types.d.ts.map +1 -0
  554. package/types/tree-data.types.js +2 -0
  555. package/types/tree-data.types.js.map +1 -0
@@ -0,0 +1,1321 @@
1
+ import { GridEventType } from '../types/event.types';
2
+ import { ColumnMenu } from './column-menu';
3
+ import { GroupContextMenu } from './group-context-menu';
4
+ import { createDiv, toggleClass } from './dom-utils';
5
+ import { resolveColumnRenderer } from './renderer-resolver';
6
+ export class HeaderRenderer {
7
+ /** Read by grid-renderer's columns-store watcher to skip header destroy during drag */
8
+ get isDraggingCol() { return this.isDragging; }
9
+ /**
10
+ * `true` between the resize-handle `mousedown` and the corresponding `mouseup`.
11
+ * Grid-renderer uses this to suppress body `renderRows` during resize — column
12
+ * widths are driven by CSS rules from `ColumnStyleManager`, so the body DOM
13
+ * never needs to be rebuilt while the user is dragging a resize handle.
14
+ */
15
+ get isResizingColumn() { return this._isResizingColumn; }
16
+ constructor(store, eventBus, iconRenderer, columnModel, sortEngine, colStyles) {
17
+ this.store = store;
18
+ this.eventBus = eventBus;
19
+ this.iconRenderer = iconRenderer;
20
+ this.columnModel = columnModel;
21
+ this.sortEngine = sortEngine;
22
+ this.colStyles = colStyles;
23
+ this.leftHeaderRowEl = null;
24
+ this.centerHeaderRowEl = null;
25
+ this.rightHeaderRowEl = null;
26
+ this.centerFilterRowEl = null;
27
+ this.headerCheckbox = null;
28
+ this.groupContextMenu = null;
29
+ this.groupDropZone = null;
30
+ // ── Column-group header support ───────────────────────────────────────────
31
+ /** Tree model for the column group hierarchy. `null` until wired via `setColumnGroupModel`. */
32
+ this.groupModel = null;
33
+ /** DOM builder for multi-row grouped header rows. `null` until wired. */
34
+ this.groupHeaderBuilder = null;
35
+ /** Group header row elements per panel — indexed 0..maxDepth-1. */
36
+ this.leftGroupRowEls = [];
37
+ this.centerGroupRowEls = [];
38
+ this.rightGroupRowEls = [];
39
+ /**
40
+ * Callback invoked when the user clicks a group collapse/expand toggle.
41
+ * Provided by `GridRenderer` so it can coordinate header + body rebuild.
42
+ */
43
+ this.onGroupToggleFn = null;
44
+ /**
45
+ * Callback invoked when the user finishes dragging a group resize handle.
46
+ * `GridRenderer` wires this to distribute the delta and trigger reflow.
47
+ */
48
+ this.onGroupResizeFn = null;
49
+ /**
50
+ * Wired by `GridRenderer` after group model setup — used in `onGlobalMouseUp`
51
+ * to create a clone group when a leaf is dropped onto a different group header.
52
+ */
53
+ this.groupDragHandler = null;
54
+ /**
55
+ * Display Group Engine — the new architecture that replaces ColumnGroupModel.
56
+ * When set, `renderInPanels` uses this engine instead of the legacy model.
57
+ */
58
+ this.displayGroupEngine = null;
59
+ /**
60
+ * Cached header row height from the last `renderInPanels` / `updateCenterVisibleCols`
61
+ * call. Used by `rebuildGroupRowsForPanel` which is called during drag when
62
+ * `HeaderRendererOptions` is not available on the call stack.
63
+ */
64
+ this.lastGroupRowHeight = 44;
65
+ // Drag state
66
+ this.draggingColId = null;
67
+ this.isDragging = false;
68
+ this.draggingPanelRowEl = null;
69
+ this.draggingIsGroupable = false;
70
+ this.isOverGroupZone = false;
71
+ this.ghostEl = null;
72
+ this.dragStyleEl = null;
73
+ this.draggingGridEl = null;
74
+ this.draggedColWidth = 0;
75
+ this.dragStartScrollX = 0;
76
+ this.dragIsHideMode = false;
77
+ this.dragSourcePanel = 'center';
78
+ this.dragTargetPanel = 'center';
79
+ this.dragTargetLocalIdx = -1;
80
+ this.panelDragData = [];
81
+ // Live cross-panel move state
82
+ this.livePanelMoveInProgress = false;
83
+ // Auto-scroll state
84
+ this.scrollByX = null;
85
+ this.canScrollX = null;
86
+ this.onResizeCb = null;
87
+ this.autoScrollRAF = 0;
88
+ this.autoScrollSpeed = 0;
89
+ this.centerPanelRect = null;
90
+ /** Last known cursor X during column drag — used to replay `onDragMove` after auto-scroll ticks. */
91
+ this.lastDragClientX = 0;
92
+ /** Callback wired by GridRenderer to open a filter panel for a column. */
93
+ this.openFilterPanelFn = null;
94
+ /** True while the user holds the resize handle and is actively moving the mouse. */
95
+ this._isResizingColumn = false;
96
+ // ─── Auto-scroll ──────────────────────────────────────────────────────────
97
+ this.tickAutoScroll = () => {
98
+ if (!this.isDragging || this.autoScrollSpeed === 0)
99
+ return;
100
+ if (this.autoScrollSpeed < 0 && !(this.canScrollX?.(-1) ?? true)) {
101
+ this.stopAutoScroll();
102
+ return;
103
+ }
104
+ if (this.autoScrollSpeed > 0 && !(this.canScrollX?.(1) ?? true)) {
105
+ this.stopAutoScroll();
106
+ return;
107
+ }
108
+ this.scrollByX?.(this.autoScrollSpeed);
109
+ // Immediately re-evaluate drag position using the updated --pg-scroll-x so
110
+ // header and body cell transforms stay in sync with the scroll on this frame.
111
+ // scrollDelta inside onDragMove reads the CSS var synchronously.
112
+ this.onDragMove(this.lastDragClientX);
113
+ this.autoScrollRAF = requestAnimationFrame(this.tickAutoScroll);
114
+ };
115
+ this.columnMenu = new ColumnMenu(columnModel, sortEngine, eventBus, iconRenderer, (action, colId) => this.onAction(action, colId));
116
+ this.columnMenu.setMenuCallbacks({
117
+ onAutoSize: (colId) => this.onAction('autosize', colId),
118
+ onAutoSizeAll: () => this.onAction('autosize-all', ''),
119
+ onFitToGrid: () => this.onAction('fit-to-grid', ''),
120
+ onResetWidth: (colId) => this.onAction('reset-width', colId),
121
+ onOpenColumnChooser: () => this.onAction('column-chooser', ''),
122
+ onOpenAdvancedFilter: (colDef, anchorEl) => {
123
+ this.openFilterPanelFn?.(colDef, anchorEl);
124
+ this.onAction('advanced-filter', colDef.colId);
125
+ },
126
+ onQuickFilter: (colId) => this.onAction('quick-filter', colId),
127
+ onCopyHeader: (colDef) => {
128
+ navigator.clipboard?.writeText(colDef.header).catch(() => { });
129
+ this.onAction('copy-header', colDef.colId);
130
+ },
131
+ onCopyColumn: (colDef) => this.onAction('copy-column', colDef.colId),
132
+ onCopyValues: (colDef) => this.onAction('copy-values', colDef.colId),
133
+ onRename: (colDef) => this.onAction('rename', colDef.colId),
134
+ onDuplicate: (colDef) => this.onAction('duplicate', colDef.colId),
135
+ onFreezePosition: (colDef) => this.onAction('freeze', colDef.colId),
136
+ onLockColumn: (colDef) => this.onAction('lock', colDef.colId),
137
+ onResetColumn: (colDef) => this.onAction('reset-column', colDef.colId),
138
+ onAggregate: (colDef, func) => this.onAction(`aggregate-${func}`, colDef.colId),
139
+ onMoveLeft: (colId) => {
140
+ const cols = columnModel.getVisibleColumns();
141
+ const idx = cols.findIndex((c) => c.colId === colId);
142
+ if (idx > 0) {
143
+ columnModel.moveColumn(idx, idx - 1);
144
+ this.onAction('move', colId);
145
+ }
146
+ },
147
+ onMoveRight: (colId) => {
148
+ const cols = columnModel.getVisibleColumns();
149
+ const idx = cols.findIndex((c) => c.colId === colId);
150
+ if (idx < cols.length - 1) {
151
+ columnModel.moveColumn(idx, idx + 1);
152
+ this.onAction('move', colId);
153
+ }
154
+ },
155
+ onMoveStart: (colId) => {
156
+ const cols = columnModel.getVisibleColumns();
157
+ const idx = cols.findIndex((c) => c.colId === colId);
158
+ if (idx > 0) {
159
+ columnModel.moveColumn(idx, 0);
160
+ this.onAction('move', colId);
161
+ }
162
+ },
163
+ onMoveEnd: (colId) => {
164
+ const cols = columnModel.getVisibleColumns();
165
+ const idx = cols.findIndex((c) => c.colId === colId);
166
+ if (idx < cols.length - 1) {
167
+ columnModel.moveColumn(idx, cols.length - 1);
168
+ this.onAction('move', colId);
169
+ }
170
+ },
171
+ });
172
+ this.boundMouseMove = this.onGlobalMouseMove.bind(this);
173
+ this.boundMouseUp = this.onGlobalMouseUp.bind(this);
174
+ }
175
+ setScrollCallback(fn, canScrollX) {
176
+ this.scrollByX = fn;
177
+ this.canScrollX = canScrollX ?? null;
178
+ }
179
+ setResizeCallback(cb) {
180
+ this.onResizeCb = cb;
181
+ }
182
+ /**
183
+ * Register the callback invoked when the user clicks the filter icon on a
184
+ * filterable column header. Wired by `GridRenderer.buildLayout()`.
185
+ *
186
+ * @param fn - Opens/positions a `FilterPanel` for the given column.
187
+ */
188
+ setOpenFilterPanelCallback(fn) {
189
+ this.openFilterPanelFn = fn;
190
+ }
191
+ /**
192
+ * Wire the column-group model and DOM builder into the header renderer.
193
+ *
194
+ * Call this before the first `renderInPanels` when the grid's column
195
+ * definitions contain groups (i.e. `ColumnDef.children` is present on any
196
+ * top-level column). Once wired, `renderInPanels` and `updateCenterVisibleCols`
197
+ * automatically insert and update the multi-row grouped header rows.
198
+ *
199
+ * @param model - The live {@link ColumnGroupModel} for the grid.
200
+ * @param builder - The {@link ColumnGroupHeaderBuilder} instance.
201
+ */
202
+ setColumnGroupModel(model, builder) {
203
+ this.groupModel = model;
204
+ this.groupHeaderBuilder = builder;
205
+ }
206
+ /**
207
+ * Wire the new Display Group Engine into the header renderer.
208
+ * When set, `renderInPanels` uses the engine's builder instead of the legacy
209
+ * `ColumnGroupModel` + `ColumnGroupHeaderBuilder`.
210
+ *
211
+ * @param engine - The fully-initialised `DisplayGroupEngine` instance.
212
+ */
213
+ setDisplayGroupEngine(engine) {
214
+ this.displayGroupEngine = engine;
215
+ this.groupContextMenu = new GroupContextMenu(engine, this.iconRenderer);
216
+ this.groupContextMenu.setCallbacks({
217
+ onOpenColumnChooser: () => this.onAction('column-chooser', ''),
218
+ onAction: (action, groupId) => this.onAction(action, groupId),
219
+ });
220
+ }
221
+ /**
222
+ * Register the callback fired when a user toggles a group's collapse state.
223
+ *
224
+ * `GridRenderer` wires this to coordinate header rebuild + leaf-column
225
+ * visibility update in `ColumnModel`.
226
+ *
227
+ * @param fn - Receives the `groupId` of the toggled group.
228
+ */
229
+ setGroupToggleCallback(fn) {
230
+ this.onGroupToggleFn = fn;
231
+ }
232
+ /**
233
+ * Register the callback fired when a user finishes dragging a group resize handle.
234
+ *
235
+ * `GridRenderer` wires this to call {@link ColumnGroupModel.distributeResizeDelta}
236
+ * and flush the updated widths to `ColumnStyleManager`.
237
+ *
238
+ * @param fn - Receives `groupId` and the new desired total group width.
239
+ */
240
+ setGroupResizeCallback(fn) {
241
+ this.onGroupResizeFn = fn;
242
+ }
243
+ /**
244
+ * Wire the group drag handler so that leaf drops on foreign group header cells
245
+ * create solo clone groups instead of doing a plain column reorder.
246
+ *
247
+ * @param handler - The active `ColumnGroupDragHandler` instance.
248
+ */
249
+ setGroupDragHandler(handler) {
250
+ this.groupDragHandler = handler;
251
+ }
252
+ /**
253
+ * Rebuild only the group-header rows for all panels without touching the leaf
254
+ * row or filter row. Call this after a group collapse/expand event has already
255
+ * been processed by the model (i.e. `group.collapsed` flag is up to date).
256
+ *
257
+ * @param options - Header renderer options (passed from last `renderInPanels` call).
258
+ */
259
+ rebuildGroupRows(options) {
260
+ if (!this.groupModel || !this.groupHeaderBuilder)
261
+ return;
262
+ if (!this.groupModel.hasGroups())
263
+ return;
264
+ const maxDepth = this.groupModel.getMaxDepth();
265
+ const rowHeight = options.headerRowHeight ?? 44;
266
+ const cellOpts = this.buildGroupCellOptions(rowHeight);
267
+ const rebuildPanel = (rowEls, panel) => {
268
+ const nodes = this.groupModel.getRootNodes(panel);
269
+ this.groupHeaderBuilder.updateGroupRows(rowEls, nodes, this.colStyles, maxDepth, cellOpts);
270
+ };
271
+ rebuildPanel(this.leftGroupRowEls, 'left');
272
+ rebuildPanel(this.centerGroupRowEls, 'center');
273
+ rebuildPanel(this.rightGroupRowEls, 'right');
274
+ }
275
+ /**
276
+ * Updates the filter-active indicator (`pg-th--filter-active` class and icon
277
+ * swap) on every rendered header cell based on the current `FilterModel`.
278
+ * Called from the renderer's `filterModel` store watcher.
279
+ *
280
+ * @param activeColIds - Set of `colId` strings that currently have an active filter.
281
+ */
282
+ updateFilterIndicators(activeColIds) {
283
+ const rows = [
284
+ this.leftHeaderRowEl,
285
+ this.centerHeaderRowEl,
286
+ this.rightHeaderRowEl,
287
+ ].filter((r) => r !== null);
288
+ for (const row of rows) {
289
+ for (const cell of Array.from(row.querySelectorAll('.pg-th[data-col-id]'))) {
290
+ const colId = cell.getAttribute('data-col-id') ?? '';
291
+ const active = activeColIds.has(colId);
292
+ cell.classList.toggle('pg-th--filter-active', active);
293
+ const btn = cell.querySelector('.pg-th__filter-btn');
294
+ if (btn) {
295
+ btn.classList.toggle('pg-th__filter-btn--active', active);
296
+ const iconName = active ? 'filterActive' : 'filter';
297
+ const iconEl = btn.querySelector('.pg-icon');
298
+ if (iconEl)
299
+ this.iconRenderer.updateIcon(iconEl, iconName);
300
+ }
301
+ }
302
+ }
303
+ }
304
+ // ── Private: group-cell option builder ───────────────────────────────────
305
+ /**
306
+ * Build the {@link GroupCellBuildOptions} object forwarded to the DOM builder.
307
+ * Wires the toggle and resize callbacks registered by `GridRenderer`.
308
+ */
309
+ buildGroupCellOptions(rowHeight) {
310
+ return {
311
+ rowHeight,
312
+ onCollapseToggle: (groupId) => {
313
+ this.onGroupToggleFn?.(groupId);
314
+ },
315
+ onGroupResize: (groupId, newWidth) => {
316
+ this.onGroupResizeFn?.(groupId, newWidth);
317
+ },
318
+ };
319
+ }
320
+ renderInPanels(leftContainer, centerInnerEl, rightContainer, allColumns, options = {}) {
321
+ const leftCols = allColumns.filter((c) => c.pinned === 'left');
322
+ const centerCols = allColumns.filter((c) => c.pinned !== 'left' && c.pinned !== 'right');
323
+ const rightCols = allColumns.filter((c) => c.pinned === 'right');
324
+ this.lastGroupRowHeight = options.headerRowHeight ?? this.lastGroupRowHeight;
325
+ // ── Group header rows (must be inserted BEFORE leaf row) ──────────────
326
+ this.leftGroupRowEls = [];
327
+ this.centerGroupRowEls = [];
328
+ this.rightGroupRowEls = [];
329
+ if (this.displayGroupEngine?.hasGroups) {
330
+ // ── New Display Group Engine path ─────────────────────────────────────
331
+ const engine = this.displayGroupEngine;
332
+ const rowHeight = options.headerRowHeight ?? 44;
333
+ const dragHandler = engine.getDragHandler();
334
+ const cellOpts = {
335
+ rowHeight,
336
+ onCollapseToggle: (id) => this.onGroupToggleFn?.(id),
337
+ onGroupResize: (id, w) => this.onGroupResizeFn?.(id, w),
338
+ onGroupHeaderMouseDown: dragHandler
339
+ ? (e, node, el) => dragHandler.onHeaderMouseDown(e, node, el)
340
+ : undefined,
341
+ didJustDragFn: dragHandler ? () => dragHandler.didJustDrag : undefined,
342
+ onGroupContextMenu: (e, node, el) => this.groupContextMenu?.show(node, el, e.clientX, e.clientY),
343
+ };
344
+ this.leftGroupRowEls = engine.headerBuilder.buildGroupRows(engine.buildTree(leftCols), cellOpts);
345
+ this.centerGroupRowEls = engine.headerBuilder.buildGroupRows(engine.buildTree(centerCols), cellOpts);
346
+ this.rightGroupRowEls = engine.headerBuilder.buildGroupRows(engine.buildTree(rightCols), cellOpts);
347
+ for (const el of this.leftGroupRowEls)
348
+ leftContainer.appendChild(el);
349
+ for (const el of this.centerGroupRowEls)
350
+ centerInnerEl.appendChild(el);
351
+ for (const el of this.rightGroupRowEls)
352
+ rightContainer.appendChild(el);
353
+ // Flat column cells use this to compute their full-height transform.
354
+ leftContainer.style.setProperty('--pg-group-rows-count', String(this.leftGroupRowEls.length));
355
+ centerInnerEl.style.setProperty('--pg-group-rows-count', String(this.centerGroupRowEls.length));
356
+ rightContainer.style.setProperty('--pg-group-rows-count', String(this.rightGroupRowEls.length));
357
+ }
358
+ else if (this.groupModel?.hasGroups() && this.groupHeaderBuilder) {
359
+ // ── Legacy ColumnGroupModel path (kept for compatibility) ─────────────
360
+ const maxDepth = this.groupModel.getMaxDepth();
361
+ const rowHeight = options.headerRowHeight ?? 44;
362
+ const cellOpts = this.buildGroupCellOptions(rowHeight);
363
+ this.leftGroupRowEls = this.groupHeaderBuilder.buildGroupRows(this.groupModel.getRootNodes('left'), this.colStyles, maxDepth, cellOpts);
364
+ this.centerGroupRowEls = this.groupHeaderBuilder.buildGroupRows(this.groupModel.getRootNodes('center'), this.colStyles, maxDepth, cellOpts);
365
+ this.rightGroupRowEls = this.groupHeaderBuilder.buildGroupRows(this.groupModel.getRootNodes('right'), this.colStyles, maxDepth, cellOpts);
366
+ for (const el of this.leftGroupRowEls)
367
+ leftContainer.appendChild(el);
368
+ for (const el of this.centerGroupRowEls)
369
+ centerInnerEl.appendChild(el);
370
+ for (const el of this.rightGroupRowEls)
371
+ rightContainer.appendChild(el);
372
+ }
373
+ // ── Leaf header rows ──────────────────────────────────────────────────
374
+ this.leftHeaderRowEl = this.buildHeaderRow(leftCols, options, true);
375
+ leftContainer.appendChild(this.leftHeaderRowEl);
376
+ if (options.showFilterRow)
377
+ leftContainer.appendChild(this.buildFilterRow(leftCols, options, true));
378
+ this.centerHeaderRowEl = this.buildHeaderRow(centerCols, options, false);
379
+ if (options.hasGroupedColumns) {
380
+ this.centerHeaderRowEl.insertBefore(this.buildAutoGroupTh(options.autoGroupColWidth ?? 200), this.centerHeaderRowEl.firstChild);
381
+ }
382
+ centerInnerEl.appendChild(this.centerHeaderRowEl);
383
+ if (options.showFilterRow) {
384
+ const filterRow = this.buildFilterRow(centerCols, options, false);
385
+ this.centerFilterRowEl = filterRow;
386
+ if (options.hasGroupedColumns)
387
+ filterRow.insertBefore(createDiv('pg-filter-cell pg-filter-cell--auto-group'), filterRow.firstChild);
388
+ centerInnerEl.appendChild(filterRow);
389
+ }
390
+ this.rightHeaderRowEl = this.buildHeaderRow(rightCols, options, false);
391
+ rightContainer.appendChild(this.rightHeaderRowEl);
392
+ if (options.showFilterRow)
393
+ rightContainer.appendChild(this.buildFilterRow(rightCols, options, false));
394
+ }
395
+ updateSortIndicator(colId, order) {
396
+ const rows = [this.leftHeaderRowEl, this.centerHeaderRowEl, this.rightHeaderRowEl].filter((r) => r !== null);
397
+ for (const row of rows) {
398
+ for (const cell of Array.from(row.querySelectorAll('.pg-th[data-col-id]'))) {
399
+ const isTarget = cell.getAttribute('data-col-id') === colId;
400
+ toggleClass(cell, 'pg-th--sort-asc', isTarget && order === 'asc');
401
+ toggleClass(cell, 'pg-th--sort-desc', isTarget && order === 'desc');
402
+ toggleClass(cell, 'pg-th--sorted', isTarget && order !== null);
403
+ if (isTarget) {
404
+ const iconEl = cell.querySelector('.pg-th__sort-icon');
405
+ if (iconEl)
406
+ this.iconRenderer.updateIcon(iconEl, order === 'asc' ? 'sortAsc' : order === 'desc' ? 'sortDesc' : 'sortNone');
407
+ }
408
+ }
409
+ }
410
+ }
411
+ updateAllChecked(isAll, isIndeterminate) {
412
+ if (!this.headerCheckbox)
413
+ return;
414
+ this.headerCheckbox.checked = isAll;
415
+ this.headerCheckbox.indeterminate = isIndeterminate && !isAll;
416
+ }
417
+ setGroupDropZone(zone) {
418
+ this.groupDropZone = zone;
419
+ this.columnMenu.setGroupCallbacks({
420
+ isGrouped: (colId) => zone.isGrouped(colId),
421
+ addGroup: (colId) => zone.dropColumn(colId),
422
+ removeGroup: (colId) => zone.removeColumn(colId),
423
+ });
424
+ }
425
+ destroy() {
426
+ document.removeEventListener('mousemove', this.boundMouseMove);
427
+ document.removeEventListener('mouseup', this.boundMouseUp);
428
+ this.columnMenu.destroy();
429
+ this.groupContextMenu?.destroy();
430
+ this.leftHeaderRowEl = null;
431
+ this.centerHeaderRowEl = null;
432
+ this.rightHeaderRowEl = null;
433
+ this.centerFilterRowEl = null;
434
+ this.headerCheckbox = null;
435
+ this.leftGroupRowEls = [];
436
+ this.centerGroupRowEls = [];
437
+ this.rightGroupRowEls = [];
438
+ }
439
+ updateCenterVisibleCols(visibleCols, leftSpacerW, rightSpacerW, options) {
440
+ if (!this.centerHeaderRowEl)
441
+ return;
442
+ this.lastGroupRowHeight = options.headerRowHeight ?? this.lastGroupRowHeight;
443
+ // ── displayGroupEngine: rebuild group rows live during drag ──────────────
444
+ // Called when store.columns changes mid-drag (cross-panel move via moveToPanelLive).
445
+ // Same-panel drag rebuilds are handled directly in onDragMove.
446
+ if (this.displayGroupEngine?.hasGroups) {
447
+ const allCols = this.store.get('columns');
448
+ const centerCols = allCols.filter((c) => c.pinned !== 'left' && c.pinned !== 'right' && c.visible !== false);
449
+ this.rebuildGroupRowsForPanel('center', centerCols);
450
+ // When dragging cross-panel, left/right group spans change too.
451
+ if (this.isDragging) {
452
+ this.rebuildGroupRowsForPanel('left', allCols.filter((c) => c.pinned === 'left' && c.visible !== false));
453
+ this.rebuildGroupRowsForPanel('right', allCols.filter((c) => c.pinned === 'right' && c.visible !== false));
454
+ }
455
+ }
456
+ // ── Legacy ColumnGroupModel: in-place update ─────────────────────────────
457
+ if (this.groupModel?.hasGroups() && this.groupHeaderBuilder && this.centerGroupRowEls.length > 0) {
458
+ const maxDepth = this.groupModel.getMaxDepth();
459
+ const rowHeight = options.headerRowHeight ?? 44;
460
+ const cellOpts = this.buildGroupCellOptions(rowHeight);
461
+ this.groupHeaderBuilder.updateGroupRows(this.centerGroupRowEls, this.groupModel.getRootNodes('center'), this.colStyles, maxDepth, cellOpts);
462
+ }
463
+ // During a column drag, detach the dragging TH before clearing innerHTML so
464
+ // the element survives the rebuild. Re-inserting the live element (rather than
465
+ // recreating it) preserves pg-th--dragging, event listeners, and drag CSS state.
466
+ const dragColId = this.isDragging ? this.draggingColId : null;
467
+ let dragThEl = null;
468
+ if (dragColId) {
469
+ dragThEl = this.centerHeaderRowEl.querySelector(`.pg-th[data-col-id="${dragColId}"]`);
470
+ dragThEl?.remove();
471
+ }
472
+ this.centerHeaderRowEl.innerHTML = '';
473
+ if (options.hasGroupedColumns)
474
+ this.centerHeaderRowEl.appendChild(this.buildAutoGroupTh(options.autoGroupColWidth ?? 200));
475
+ if (leftSpacerW > 0)
476
+ this.centerHeaderRowEl.appendChild(this.makeSpacer('pg-th pg-th--h-spacer', leftSpacerW));
477
+ for (let i = 0; i < visibleCols.length; i++) {
478
+ const col = visibleCols[i];
479
+ if (dragThEl && col.colId === dragColId) {
480
+ // Re-insert the live element — preserves class, listeners, and drag state.
481
+ this.centerHeaderRowEl.appendChild(dragThEl);
482
+ }
483
+ else {
484
+ this.centerHeaderRowEl.appendChild(this.buildHeaderCell(col, i, visibleCols, options, this.centerHeaderRowEl));
485
+ }
486
+ }
487
+ if (rightSpacerW > 0)
488
+ this.centerHeaderRowEl.appendChild(this.makeSpacer('pg-th pg-th--h-spacer', rightSpacerW));
489
+ if (!this.centerFilterRowEl)
490
+ return;
491
+ this.centerFilterRowEl.innerHTML = '';
492
+ if (options.hasGroupedColumns)
493
+ this.centerFilterRowEl.appendChild(createDiv('pg-filter-cell pg-filter-cell--auto-group'));
494
+ if (leftSpacerW > 0)
495
+ this.centerFilterRowEl.appendChild(this.makeSpacer('pg-filter-cell pg-filter-cell--h-spacer', leftSpacerW));
496
+ for (const col of visibleCols)
497
+ this.centerFilterRowEl.appendChild(this.buildFilterCell(col));
498
+ if (rightSpacerW > 0)
499
+ this.centerFilterRowEl.appendChild(this.makeSpacer('pg-filter-cell pg-filter-cell--h-spacer', rightSpacerW));
500
+ }
501
+ // ─── Private ──────────────────────────────────────────────────────────────
502
+ makeSpacer(cls, w) {
503
+ const sp = createDiv(cls);
504
+ sp.style.cssText = `width:${w}px;min-width:${w}px;flex-shrink:0;`;
505
+ return sp;
506
+ }
507
+ capturePanelDragData() {
508
+ const gatherPD = (panel, rowEl) => {
509
+ if (!rowEl)
510
+ return null;
511
+ const ths = Array.from(rowEl.querySelectorAll('.pg-th[data-col-id]'));
512
+ const headerPanel = rowEl.closest('.pg-panel__header');
513
+ const bounds = headerPanel?.getBoundingClientRect() ?? null;
514
+ if (!bounds || bounds.width === 0)
515
+ return null;
516
+ return {
517
+ panel,
518
+ rects: ths.map((t) => t.getBoundingClientRect()),
519
+ colIds: ths.map((t) => t.getAttribute('data-col-id') ?? ''),
520
+ bounds,
521
+ };
522
+ };
523
+ return [
524
+ gatherPD('left', this.leftHeaderRowEl),
525
+ gatherPD('center', this.centerHeaderRowEl),
526
+ gatherPD('right', this.rightHeaderRowEl),
527
+ ].filter((pd) => pd !== null);
528
+ }
529
+ buildHeaderRow(columns, options, isLeft) {
530
+ const row = createDiv('pg-header-row');
531
+ row.setAttribute('role', 'row');
532
+ if (isLeft) {
533
+ if (options.showCheckboxes)
534
+ row.appendChild(this.buildCheckboxHeaderCell());
535
+ if (options.showSerialNumber)
536
+ row.appendChild(this.buildSerialHeaderCell());
537
+ }
538
+ for (let i = 0; i < columns.length; i++)
539
+ row.appendChild(this.buildHeaderCell(columns[i], i, columns, options, row));
540
+ return row;
541
+ }
542
+ buildAutoGroupTh(width) {
543
+ const th = createDiv('pg-th pg-th--auto-group');
544
+ th.setAttribute('role', 'columnheader');
545
+ th.style.width = `${width}px`;
546
+ th.style.minWidth = `${width}px`;
547
+ const content = createDiv('pg-th__content');
548
+ const labelEl = createDiv('pg-th__label');
549
+ labelEl.textContent = 'Groups';
550
+ content.appendChild(labelEl);
551
+ th.appendChild(content);
552
+ return th;
553
+ }
554
+ buildCheckboxHeaderCell() {
555
+ const cell = createDiv('pg-th pg-th--checkbox');
556
+ cell.setAttribute('role', 'columnheader');
557
+ const checkbox = document.createElement('input');
558
+ checkbox.type = 'checkbox';
559
+ checkbox.className = 'pg-checkbox pg-header-checkbox';
560
+ checkbox.setAttribute('aria-label', 'Select all rows');
561
+ this.headerCheckbox = checkbox;
562
+ const isAll = this.store.get('isAllSelected');
563
+ const isInd = this.store.get('isIndeterminate');
564
+ checkbox.checked = isAll;
565
+ checkbox.indeterminate = isInd && !isAll;
566
+ checkbox.addEventListener('change', () => {
567
+ this.eventBus.emit(GridEventType.ALL_ROWS_SELECTED, { action: checkbox.checked ? 'selectAll' : 'deselectAll' });
568
+ });
569
+ cell.appendChild(checkbox);
570
+ return cell;
571
+ }
572
+ buildSerialHeaderCell() {
573
+ const cell = createDiv('pg-th pg-th--serial');
574
+ cell.setAttribute('role', 'columnheader');
575
+ const label = document.createElement('span');
576
+ label.className = 'pg-th__serial-label';
577
+ label.textContent = '#';
578
+ cell.appendChild(label);
579
+ return cell;
580
+ }
581
+ buildHeaderCell(col, index, panelColumns, options, panelRowEl) {
582
+ const th = createDiv('pg-th');
583
+ th.setAttribute('role', 'columnheader');
584
+ th.setAttribute('data-col-id', col.colId);
585
+ th.setAttribute('data-col-index', String(index));
586
+ th.setAttribute('tabindex', '0');
587
+ // When a grouped header is present, flat columns must visually span the
588
+ // full header height (group rows + leaf row). The CSS handles the actual
589
+ // translate + height expansion; this class is the hook.
590
+ if (this.displayGroupEngine?.hasGroups && this.displayGroupEngine.isFlat(col.colId)) {
591
+ th.classList.add('pg-th--no-group');
592
+ }
593
+ if (col.headerCssClass)
594
+ th.className += ` ${col.headerCssClass}`;
595
+ toggleClass(th, 'pg-th--sortable', col.sortable !== false);
596
+ toggleClass(th, 'pg-th--sorted', !!col.sortOrder);
597
+ toggleClass(th, 'pg-th--sort-asc', col.sortOrder === 'asc');
598
+ toggleClass(th, 'pg-th--sort-desc', col.sortOrder === 'desc');
599
+ const align = col.textAlign ?? (col.type === 'number' || col.type === 'currency' ? 'right' : 'left');
600
+ if (align !== 'left')
601
+ th.classList.add(`pg-th--align-${align}`);
602
+ if (align === 'right')
603
+ th.classList.add('pg-th--reverse');
604
+ const headerFn = resolveColumnRenderer(col, 'header');
605
+ if (headerFn) {
606
+ const rendered = headerFn({ colDef: col, sortOrder: col.sortOrder ?? null, filterActive: !!col.filterActive, api: null });
607
+ if (typeof rendered === 'string')
608
+ th.innerHTML = rendered;
609
+ else
610
+ th.appendChild(rendered);
611
+ }
612
+ else {
613
+ const content = createDiv('pg-th__content');
614
+ const labelEl = createDiv('pg-th__label');
615
+ labelEl.textContent = col.header;
616
+ labelEl.title = col.header;
617
+ content.appendChild(labelEl);
618
+ if (col.sortable !== false) {
619
+ content.appendChild(this.iconRenderer.render(col.sortOrder === 'asc' ? 'sortAsc' : col.sortOrder === 'desc' ? 'sortDesc' : 'sortNone', { size: 14, className: 'pg-th__sort-icon' }));
620
+ }
621
+ th.appendChild(content);
622
+ }
623
+ // Filter icon — visible on hover; always visible when a filter is active.
624
+ if (col.filterable !== false) {
625
+ const filterBtn = createDiv('pg-th__filter-btn');
626
+ const filterActive = col.filterActive === true;
627
+ if (filterActive)
628
+ filterBtn.classList.add('pg-th__filter-btn--active');
629
+ filterBtn.innerHTML = this.iconRenderer.renderToString(filterActive ? 'filterActive' : 'filter', 14);
630
+ filterBtn.title = 'Filter column';
631
+ filterBtn.setAttribute('tabindex', '0');
632
+ filterBtn.setAttribute('aria-label', `Filter ${col.header}`);
633
+ filterBtn.addEventListener('click', (e) => {
634
+ e.stopPropagation();
635
+ this.openFilterPanelFn?.(col, filterBtn);
636
+ });
637
+ th.appendChild(filterBtn);
638
+ }
639
+ if (options.showColumnMenu !== false) {
640
+ const menuBtn = createDiv('pg-th__menu-btn');
641
+ menuBtn.innerHTML = this.iconRenderer.renderToString('menuHorizontal', 14);
642
+ menuBtn.title = 'Column options';
643
+ menuBtn.setAttribute('tabindex', '0');
644
+ menuBtn.addEventListener('click', (e) => { e.stopPropagation(); this.columnMenu.show(col, menuBtn); });
645
+ th.appendChild(menuBtn);
646
+ }
647
+ // Right-click on the header cell opens the context menu at cursor position.
648
+ th.addEventListener('contextmenu', (e) => {
649
+ e.preventDefault();
650
+ e.stopPropagation();
651
+ this.columnMenu.show(col, th, e.clientX, e.clientY);
652
+ });
653
+ if (col.resizable !== false) {
654
+ const resizeHandle = createDiv('pg-th__resize-handle');
655
+ resizeHandle.innerHTML = '|';
656
+ resizeHandle.addEventListener('mousedown', (e) => { e.preventDefault(); e.stopPropagation(); this.startResize(e, col, th); });
657
+ th.appendChild(resizeHandle);
658
+ }
659
+ if (col.sortable !== false) {
660
+ th.addEventListener('click', (e) => {
661
+ if (e.target.closest('.pg-th__resize-handle, .pg-th__menu-btn, .pg-th__filter-btn'))
662
+ return;
663
+ const next = col.sortOrder === null ? 'asc' : col.sortOrder === 'asc' ? 'desc' : null;
664
+ if (next)
665
+ this.sortEngine.sort(col.colId, col.field, next);
666
+ else
667
+ this.sortEngine.clearSort();
668
+ this.columnModel.setColumnSort(col.colId, next);
669
+ this.updateSortIndicator(col.colId, next);
670
+ this.onAction('sort', col.colId);
671
+ });
672
+ }
673
+ this.attachColumnDragListeners(th, col, panelColumns, panelRowEl);
674
+ return th;
675
+ }
676
+ buildFilterCell(col) {
677
+ const cell = createDiv('pg-filter-cell');
678
+ cell.setAttribute('data-col-id', col.colId);
679
+ if (col.filterable !== false) {
680
+ const input = document.createElement('input');
681
+ input.type = 'text';
682
+ input.className = 'pg-filter-input';
683
+ input.placeholder = `${col.header}…`;
684
+ input.setAttribute('data-col-id', col.colId);
685
+ input.addEventListener('input', (e) => {
686
+ this.eventBus.emit(GridEventType.COLUMN_FILTER_CHANGED, {
687
+ colId: col.colId, field: col.field, term: e.target.value,
688
+ });
689
+ });
690
+ cell.appendChild(input);
691
+ }
692
+ return cell;
693
+ }
694
+ buildFilterRow(columns, options, isLeft) {
695
+ const row = createDiv('pg-filter-row');
696
+ row.setAttribute('role', 'row');
697
+ if (isLeft) {
698
+ if (options.showCheckboxes)
699
+ row.appendChild(createDiv('pg-filter-cell pg-filter-cell--checkbox'));
700
+ if (options.showSerialNumber)
701
+ row.appendChild(createDiv('pg-filter-cell pg-filter-cell--serial'));
702
+ }
703
+ for (const col of columns)
704
+ row.appendChild(this.buildFilterCell(col));
705
+ return row;
706
+ }
707
+ attachColumnDragListeners(th, col, _panelColumns, panelRowEl) {
708
+ th.addEventListener('mousedown', (e) => {
709
+ if (e.target.closest('.pg-th__resize-handle, .pg-th__menu-btn, .pg-th__filter-btn, .pg-checkbox'))
710
+ return;
711
+ if (col.draggable === false || e.button !== 0)
712
+ return;
713
+ const startX = e.clientX;
714
+ let moved = false;
715
+ const onMoveCheck = (ev) => {
716
+ if (!moved && Math.abs(ev.clientX - startX) > 5) {
717
+ moved = true;
718
+ this.startColumnDrag(col, panelRowEl);
719
+ document.removeEventListener('mousemove', onMoveCheck);
720
+ document.addEventListener('mousemove', this.boundMouseMove);
721
+ document.addEventListener('mouseup', this.boundMouseUp);
722
+ }
723
+ if (moved)
724
+ this.onDragMove(ev.clientX);
725
+ };
726
+ const onUpEarly = () => {
727
+ document.removeEventListener('mousemove', onMoveCheck);
728
+ document.removeEventListener('mouseup', onUpEarly);
729
+ };
730
+ document.addEventListener('mousemove', onMoveCheck);
731
+ document.addEventListener('mouseup', onUpEarly);
732
+ });
733
+ }
734
+ startColumnDrag(col, panelRowEl) {
735
+ this.draggingColId = col.colId;
736
+ this.isDragging = true;
737
+ this.draggingPanelRowEl = panelRowEl;
738
+ this.draggingIsGroupable = col.groupable === true && this.groupDropZone !== null;
739
+ this.isOverGroupZone = false;
740
+ this.dragIsHideMode = false;
741
+ this.livePanelMoveInProgress = false;
742
+ this.dragSourcePanel = panelRowEl === this.leftHeaderRowEl ? 'left'
743
+ : panelRowEl === this.rightHeaderRowEl ? 'right' : 'center';
744
+ this.dragTargetPanel = this.dragSourcePanel;
745
+ this.dragTargetLocalIdx = -1;
746
+ // Build ghost chip
747
+ const ghost = createDiv('pg-col-drag-ghost');
748
+ const mkIcon = (cls, name) => {
749
+ const s = document.createElement('span');
750
+ s.className = `pg-col-drag-ghost__icon ${cls}`;
751
+ s.innerHTML = this.iconRenderer.renderToString(name, 14);
752
+ return s;
753
+ };
754
+ ghost.appendChild(mkIcon('pg-col-drag-ghost__icon--arrow-left', 'chevronLeft'));
755
+ ghost.appendChild(mkIcon('pg-col-drag-ghost__icon--move', 'drag'));
756
+ ghost.appendChild(mkIcon('pg-col-drag-ghost__icon--ban', 'ban'));
757
+ ghost.appendChild(mkIcon('pg-col-drag-ghost__icon--hide', 'eyeOff'));
758
+ const ghostLabel = document.createElement('span');
759
+ ghostLabel.className = 'pg-col-drag-ghost__label';
760
+ ghostLabel.textContent = col.header;
761
+ ghost.appendChild(ghostLabel);
762
+ ghost.appendChild(mkIcon('pg-col-drag-ghost__icon--arrow-right', 'chevronRight'));
763
+ document.body.appendChild(ghost);
764
+ this.ghostEl = ghost;
765
+ const srcPD = this.panelDragData.find((pd) => pd.panel === this.dragSourcePanel);
766
+ const srcThEl = panelRowEl.querySelector(`[data-col-id="${col.colId}"]`);
767
+ srcThEl?.classList.add('pg-th--dragging');
768
+ const gridEl = panelRowEl.closest('.pg-grid');
769
+ this.draggingGridEl = gridEl;
770
+ // Capture all panel rects before any transforms
771
+ this.panelDragData = this.capturePanelDragData();
772
+ const freshSrcPD = this.panelDragData.find((pd) => pd.panel === this.dragSourcePanel);
773
+ const srcIdx = freshSrcPD?.colIds.indexOf(col.colId) ?? -1;
774
+ this.draggedColWidth = (srcIdx >= 0 && freshSrcPD ? freshSrcPD.rects[srcIdx].width : 0)
775
+ || srcThEl?.getBoundingClientRect().width || 0;
776
+ void srcPD;
777
+ this.dragStartScrollX = parseFloat(gridEl?.style.getPropertyValue('--pg-scroll-x') ?? '0');
778
+ const centerPD = this.panelDragData.find((pd) => pd.panel === 'center');
779
+ this.centerPanelRect = centerPD?.bounds ?? null;
780
+ const styleEl = document.createElement('style');
781
+ styleEl.setAttribute('data-pg-drag', '');
782
+ document.head.appendChild(styleEl);
783
+ this.dragStyleEl = styleEl;
784
+ gridEl?.classList.add('pg-grid--col-dragging');
785
+ // Suppress the 180 ms drag-shift transition while the virtual column range
786
+ // expands to all columns on the first performRender after drag start.
787
+ // Without this guard, newly-added body cells animate in from transform:0.
788
+ // The class is removed 2 frames later so smooth transitions resume for
789
+ // ordinary mouse movement.
790
+ gridEl?.classList.add('pg-grid--col-autoscrolling');
791
+ requestAnimationFrame(() => requestAnimationFrame(() => {
792
+ if (this.isDragging)
793
+ this.draggingGridEl?.classList.remove('pg-grid--col-autoscrolling');
794
+ }));
795
+ document.body.style.cursor = 'grabbing';
796
+ document.body.style.userSelect = 'none';
797
+ }
798
+ // ─── Live cross-panel move ─────────────────────────────────────────────────
799
+ /**
800
+ * When the cursor crosses into a new panel:
801
+ * 1. Immediately DOM-move the source TH into the target panel header row
802
+ * 2. Call moveAndPin() so body cells and panel widths update via the guarded re-render
803
+ * 3. After 2 frames (re-render complete), re-capture rects and continue drag
804
+ */
805
+ moveToPanelLive(newPanel, insertIdx) {
806
+ if (this.livePanelMoveInProgress)
807
+ return;
808
+ this.livePanelMoveInProgress = true;
809
+ const colId = this.draggingColId;
810
+ const targetPD = this.panelDragData.find((pd) => pd.panel === newPanel);
811
+ const insertBeforeColId = targetPD?.colIds[insertIdx] ?? null;
812
+ const newPin = newPanel === 'left' ? 'left' : newPanel === 'right' ? 'right' : null;
813
+ // Step 1: immediately DOM-move the TH for instant visual feedback in the header
814
+ const targetRowEl = newPanel === 'left' ? this.leftHeaderRowEl
815
+ : newPanel === 'right' ? this.rightHeaderRowEl
816
+ : this.centerHeaderRowEl;
817
+ const srcThEl = this.draggingGridEl?.querySelector(`.pg-th[data-col-id="${colId}"]`);
818
+ if (srcThEl && targetRowEl) {
819
+ const realThs = Array.from(targetRowEl.querySelectorAll('.pg-th[data-col-id]'));
820
+ const refEl = insertIdx < realThs.length ? realThs[insertIdx] : null;
821
+ if (refEl)
822
+ targetRowEl.insertBefore(srcThEl, refEl);
823
+ else {
824
+ const lastTh = realThs[realThs.length - 1];
825
+ if (lastTh?.nextSibling)
826
+ targetRowEl.insertBefore(srcThEl, lastTh.nextSibling);
827
+ else
828
+ targetRowEl.appendChild(srcThEl);
829
+ }
830
+ }
831
+ // Clear any drag transforms during the transition
832
+ if (this.dragStyleEl)
833
+ this.dragStyleEl.textContent = '';
834
+ // Update drag source state immediately
835
+ this.dragSourcePanel = newPanel;
836
+ this.dragTargetPanel = newPanel;
837
+ this.dragTargetLocalIdx = -1;
838
+ // Step 2: update column model → body cells re-render + panel width CSS var updates
839
+ // The grid-renderer columns watcher checks isDraggingCol and skips header.destroy()
840
+ this.columnModel.moveAndPin(colId, newPin, insertBeforeColId);
841
+ // Step 3: after re-render (2 frames), re-capture rects and re-apply dragging state
842
+ requestAnimationFrame(() => {
843
+ requestAnimationFrame(() => {
844
+ if (!this.isDragging || this.draggingColId !== colId) {
845
+ this.livePanelMoveInProgress = false;
846
+ return;
847
+ }
848
+ // Re-apply pg-th--dragging (the TH may have been rebuilt by updateCenterVisibleCols)
849
+ this.draggingGridEl?.querySelector(`.pg-th[data-col-id="${colId}"]`)
850
+ ?.classList.add('pg-th--dragging');
851
+ // Re-capture rects with the new panel layout
852
+ this.panelDragData = this.capturePanelDragData();
853
+ this.dragStartScrollX = parseFloat(this.draggingGridEl?.style.getPropertyValue('--pg-scroll-x') ?? '0');
854
+ const centerPD = this.panelDragData.find((pd) => pd.panel === 'center');
855
+ this.centerPanelRect = centerPD?.bounds ?? null;
856
+ this.livePanelMoveInProgress = false;
857
+ });
858
+ });
859
+ }
860
+ updateAutoScroll(clientX) {
861
+ if (!this.centerPanelRect || !this.scrollByX)
862
+ return;
863
+ const EDGE = 80;
864
+ const { left, right } = this.centerPanelRect;
865
+ let speed = 0;
866
+ if (clientX < left + EDGE) {
867
+ const raw = -Math.round(((left + EDGE - clientX) / EDGE) * 10);
868
+ speed = (this.canScrollX?.(-1) ?? true) ? raw : 0;
869
+ }
870
+ else if (clientX > right - EDGE) {
871
+ const raw = Math.round(((clientX - right + EDGE) / EDGE) * 10);
872
+ speed = (this.canScrollX?.(1) ?? true) ? raw : 0;
873
+ }
874
+ const wasScrolling = this.autoScrollSpeed !== 0;
875
+ this.autoScrollSpeed = speed;
876
+ if (speed !== 0 && !wasScrolling)
877
+ this.autoScrollRAF = requestAnimationFrame(this.tickAutoScroll);
878
+ else if (speed === 0 && wasScrolling)
879
+ this.stopAutoScroll();
880
+ this.ghostEl?.classList.toggle('pg-col-drag-ghost--scroll-left', speed < 0);
881
+ this.ghostEl?.classList.toggle('pg-col-drag-ghost--scroll-right', speed > 0);
882
+ }
883
+ stopAutoScroll() {
884
+ cancelAnimationFrame(this.autoScrollRAF);
885
+ this.autoScrollRAF = 0;
886
+ this.autoScrollSpeed = 0;
887
+ if (this.isDragging && !this.livePanelMoveInProgress && this.dragStyleEl) {
888
+ // Temporarily suppress all column transitions while resetting the drag baseline.
889
+ // Without this guard, sibling columns animate back to zero when their transforms
890
+ // are cleared, then re-animate forward — a visible snap-and-reanimate sequence.
891
+ this.draggingGridEl?.classList.add('pg-grid--col-autoscrolling');
892
+ this.refreshDragAfterScroll();
893
+ this.draggingGridEl?.classList.remove('pg-grid--col-autoscrolling');
894
+ }
895
+ this.ghostEl?.classList.remove('pg-col-drag-ghost--scroll-left', 'pg-col-drag-ghost--scroll-right');
896
+ }
897
+ /**
898
+ * Re-captures header column rects and re-applies drag transforms after each
899
+ * auto-scroll step. Runs 2 animation frames after the scroll so the grid's
900
+ * virtual column render (`updateCenterVisibleCols`) has completed and the DOM
901
+ * reflects any newly visible columns before `getBoundingClientRect` is called.
902
+ *
903
+ * This mirrors the 2-frame pattern used by `moveToPanelLive` and ensures the
904
+ * dragged-column ghost and sibling transforms stay accurate even when the
905
+ * mouse is stationary at the viewport edge while auto-scroll is running.
906
+ */
907
+ refreshDragAfterScroll() {
908
+ if (!this.isDragging || this.livePanelMoveInProgress)
909
+ return;
910
+ // CRITICAL: clear drag transforms before calling getBoundingClientRect.
911
+ // capturePanelDragData reads viewport positions via getBoundingClientRect.
912
+ // If dragStyleEl still has transforms applied, the captured rects include
913
+ // those offsets — the next onDragMove then compounds transforms on top of
914
+ // already-transformed positions, creating an oscillating feedback loop that
915
+ // causes blinking and column misalignment.
916
+ // getBoundingClientRect forces a synchronous layout flush, so clearing first
917
+ // and recapturing immediately gives clean baseline positions. The clear and
918
+ // re-apply are both in the same JS task, so the browser never paints a
919
+ // transform-less frame.
920
+ if (this.dragStyleEl)
921
+ this.dragStyleEl.textContent = '';
922
+ // Re-apply dragging class — updateCenterVisibleCols may have rebuilt the TH element.
923
+ this.draggingGridEl
924
+ ?.querySelector(`.pg-th[data-col-id="${this.draggingColId}"]`)
925
+ ?.classList.add('pg-th--dragging');
926
+ // Re-capture clean baseline rects (no transforms) for all currently rendered columns.
927
+ this.panelDragData = this.capturePanelDragData();
928
+ this.dragStartScrollX = parseFloat(this.draggingGridEl?.style.getPropertyValue('--pg-scroll-x') ?? '0');
929
+ const centerPD = this.panelDragData.find((pd) => pd.panel === 'center');
930
+ this.centerPanelRect = centerPD?.bounds ?? null;
931
+ // Re-apply correct transforms from the fresh baseline rects.
932
+ this.onDragMove(this.lastDragClientX);
933
+ }
934
+ // ─── Live group row preview (DisplayGroupEngine) ─────────────────────────
935
+ /**
936
+ * Rebuild the group header rows for one panel using a new (possibly preview)
937
+ * column order. Safe to call during drag — only the group row `<div>`s are
938
+ * replaced; the leaf row `<tr>` that carries the live drag element is untouched.
939
+ *
940
+ * @param panel - Which panel's group rows to refresh.
941
+ * @param cols - Ordered visible columns for this panel (preview or committed).
942
+ */
943
+ rebuildGroupRowsForPanel(panel, cols) {
944
+ if (!this.displayGroupEngine?.hasGroups)
945
+ return;
946
+ const leafRowEl = panel === 'left' ? this.leftHeaderRowEl
947
+ : panel === 'right' ? this.rightHeaderRowEl
948
+ : this.centerHeaderRowEl;
949
+ if (!leafRowEl)
950
+ return;
951
+ const container = leafRowEl.parentElement;
952
+ if (!container)
953
+ return;
954
+ const oldRows = panel === 'left' ? this.leftGroupRowEls
955
+ : panel === 'right' ? this.rightGroupRowEls
956
+ : this.centerGroupRowEls;
957
+ for (const el of oldRows)
958
+ el.remove();
959
+ const engine = this.displayGroupEngine;
960
+ const dragHandler = engine.getDragHandler();
961
+ const cellOpts = {
962
+ rowHeight: this.lastGroupRowHeight,
963
+ onCollapseToggle: (id) => this.onGroupToggleFn?.(id),
964
+ onGroupResize: (id, w) => this.onGroupResizeFn?.(id, w),
965
+ onGroupHeaderMouseDown: dragHandler
966
+ ? (e, node, el) => dragHandler.onHeaderMouseDown(e, node, el)
967
+ : undefined,
968
+ didJustDragFn: dragHandler ? () => dragHandler.didJustDrag : undefined,
969
+ onGroupContextMenu: (e, node, el) => this.groupContextMenu?.show(node, el, e.clientX, e.clientY),
970
+ };
971
+ const newRows = engine.headerBuilder.buildGroupRows(engine.buildTree(cols), cellOpts);
972
+ for (const el of newRows)
973
+ container.insertBefore(el, leafRowEl);
974
+ if (panel === 'left')
975
+ this.leftGroupRowEls = newRows;
976
+ else if (panel === 'right')
977
+ this.rightGroupRowEls = newRows;
978
+ else
979
+ this.centerGroupRowEls = newRows;
980
+ // Keep the flat-column height variable in sync whenever group rows change.
981
+ container.style.setProperty('--pg-group-rows-count', String(newRows.length));
982
+ }
983
+ /**
984
+ * Compute the preview column order for the drag source panel (same-panel drag)
985
+ * and rebuild its group rows.
986
+ *
987
+ * Called from `onDragMove` whenever the effective drop slot changes. Always
988
+ * derives the preview from the captured `panelDragData` colIds so the
989
+ * `LogicalGroupRegistry` sees the exact order the column would land in on drop.
990
+ *
991
+ * @param targetIdx - Effective slot index the dragged column is hovering over.
992
+ * @param sourceIdx - Original slot index of the dragged column in its panel.
993
+ * @param pd - Panel drag data for the source panel.
994
+ */
995
+ rebuildGroupRowsWithPreview(targetIdx, sourceIdx, pd) {
996
+ // Build preview colId order: move dragged column from sourceIdx to targetIdx.
997
+ const previewIds = [...pd.colIds];
998
+ const [movedId] = previewIds.splice(sourceIdx, 1);
999
+ previewIds.splice(targetIdx, 0, movedId);
1000
+ // Map to ColumnDef[] using store (live source of truth for metadata).
1001
+ const allCols = this.store.get('columns');
1002
+ const colMap = new Map(allCols.map((c) => [c.colId, c]));
1003
+ const previewCols = previewIds
1004
+ .map((id) => colMap.get(id))
1005
+ .filter((c) => c !== undefined);
1006
+ this.rebuildGroupRowsForPanel(this.dragSourcePanel, previewCols);
1007
+ }
1008
+ // ─── Drag move ────────────────────────────────────────────────────────────
1009
+ onDragMove(clientX) {
1010
+ if (!this.isDragging || !this.draggingColId || !this.panelDragData.length || !this.dragStyleEl)
1011
+ return;
1012
+ if (this.livePanelMoveInProgress) {
1013
+ this.dragStyleEl.textContent = '';
1014
+ return;
1015
+ }
1016
+ // Which panel is the cursor over?
1017
+ let targetPD = this.panelDragData.find((pd) => {
1018
+ if (!pd.bounds)
1019
+ return false;
1020
+ return clientX >= pd.bounds.left && clientX <= pd.bounds.right;
1021
+ });
1022
+ if (!targetPD)
1023
+ targetPD = this.panelDragData.find((pd) => pd.panel === this.dragSourcePanel);
1024
+ if (!targetPD)
1025
+ return;
1026
+ this.dragTargetPanel = targetPD.panel;
1027
+ const crossPanel = targetPD.panel !== this.dragSourcePanel;
1028
+ // Scroll correction for center panel
1029
+ const scrollDelta = targetPD.panel === 'center'
1030
+ ? parseFloat(this.draggingGridEl?.style.getPropertyValue('--pg-scroll-x') ?? '0') - this.dragStartScrollX
1031
+ : 0;
1032
+ const { rects: tRects, colIds: tIds } = targetPD;
1033
+ const srcPD = this.panelDragData.find((pd) => pd.panel === this.dragSourcePanel);
1034
+ const sourceIdxInPanel = srcPD.colIds.indexOf(this.draggingColId);
1035
+ if (crossPanel) {
1036
+ // Zone-entry: insert before the first column whose right edge the cursor hasn't passed
1037
+ let insertIdx = tIds.length;
1038
+ for (let i = 0; i < tRects.length; i++) {
1039
+ if (clientX < tRects[i].right + scrollDelta) {
1040
+ insertIdx = i;
1041
+ break;
1042
+ }
1043
+ }
1044
+ this.moveToPanelLive(targetPD.panel, insertIdx);
1045
+ this.dragStyleEl.textContent = '';
1046
+ return;
1047
+ }
1048
+ // Same-panel: find which non-source column zone the cursor is directly over
1049
+ let effectiveTarget = sourceIdxInPanel;
1050
+ for (let i = 0; i < tRects.length; i++) {
1051
+ if (i === sourceIdxInPanel)
1052
+ continue;
1053
+ const colLeft = tRects[i].left + scrollDelta;
1054
+ const colRight = tRects[i].right + scrollDelta;
1055
+ if (clientX >= colLeft && clientX < colRight) {
1056
+ effectiveTarget = i;
1057
+ break;
1058
+ }
1059
+ }
1060
+ // Cursor before all columns: snap to leftmost non-source column
1061
+ if (effectiveTarget === sourceIdxInPanel && tRects.length > 0 && clientX < tRects[0].left + scrollDelta) {
1062
+ effectiveTarget = sourceIdxInPanel === 0 ? 1 : 0;
1063
+ }
1064
+ // Cursor after all columns: snap to rightmost non-source column
1065
+ if (effectiveTarget === sourceIdxInPanel && tRects.length > 0 && clientX >= tRects[tRects.length - 1].right + scrollDelta) {
1066
+ const lastIdx = tRects.length - 1;
1067
+ effectiveTarget = sourceIdxInPanel === lastIdx ? lastIdx - 1 : lastIdx;
1068
+ }
1069
+ const prevSlot = this.dragTargetLocalIdx;
1070
+ this.dragTargetLocalIdx = effectiveTarget;
1071
+ // Rebuild group rows whenever the effective drop slot changes so group spans
1072
+ // reflect the pending position in real time — identical to AG Grid behaviour.
1073
+ if (this.displayGroupEngine?.hasGroups && effectiveTarget !== prevSlot) {
1074
+ this.rebuildGroupRowsWithPreview(effectiveTarget, sourceIdxInPanel, srcPD);
1075
+ }
1076
+ // Same-panel: apply CSS transforms
1077
+ const gridId = this.draggingGridEl?.getAttribute('data-photon-grid-id') ?? '';
1078
+ const scope = gridId ? `[data-photon-grid-id="${gridId}"] ` : '';
1079
+ let css = '';
1080
+ if (effectiveTarget === sourceIdxInPanel) {
1081
+ this.dragStyleEl.textContent = '';
1082
+ return;
1083
+ }
1084
+ const srcRect = srcPD.rects[sourceIdxInPanel];
1085
+ const tgtRect = tRects[effectiveTarget];
1086
+ const srcOffset = effectiveTarget > sourceIdxInPanel ? tgtRect.right - srcRect.right : tgtRect.left - srcRect.left;
1087
+ css += `${scope}[data-col-id="${tIds[sourceIdxInPanel]}"] { --pg-drag-x: ${srcOffset}px; z-index: 10; position: relative; transition: none; }\n`;
1088
+ for (let i = 0; i < tRects.length; i++) {
1089
+ if (i === sourceIdxInPanel)
1090
+ continue;
1091
+ let offset = 0;
1092
+ if (effectiveTarget > sourceIdxInPanel && i > sourceIdxInPanel && i <= effectiveTarget)
1093
+ offset = -this.draggedColWidth;
1094
+ else if (effectiveTarget < sourceIdxInPanel && i >= effectiveTarget && i < sourceIdxInPanel)
1095
+ offset = this.draggedColWidth;
1096
+ if (offset !== 0)
1097
+ css += `${scope}[data-col-id="${tIds[i]}"] { --pg-drag-x: ${offset}px; }\n`;
1098
+ }
1099
+ this.dragStyleEl.textContent = css;
1100
+ }
1101
+ onGlobalMouseMove(e) {
1102
+ if (!this.isDragging || !this.draggingPanelRowEl)
1103
+ return;
1104
+ if (this.ghostEl) {
1105
+ this.ghostEl.style.left = `${e.clientX + 14}px`;
1106
+ this.ghostEl.style.top = `${e.clientY}px`;
1107
+ }
1108
+ // Outside grid → hide-column mode
1109
+ const gridBounds = this.draggingGridEl?.getBoundingClientRect();
1110
+ const isOutside = !!gridBounds && (e.clientX < gridBounds.left || e.clientX > gridBounds.right ||
1111
+ e.clientY < gridBounds.top || e.clientY > gridBounds.bottom);
1112
+ if (isOutside) {
1113
+ this.dragIsHideMode = true;
1114
+ this.stopAutoScroll();
1115
+ this.ghostEl?.classList.add('pg-col-drag-ghost--hide');
1116
+ this.ghostEl?.classList.remove('pg-col-drag-ghost--no-drop', 'pg-col-drag-ghost--scroll-left', 'pg-col-drag-ghost--scroll-right');
1117
+ if (this.dragStyleEl)
1118
+ this.dragStyleEl.textContent = '';
1119
+ return;
1120
+ }
1121
+ this.dragIsHideMode = false;
1122
+ this.ghostEl?.classList.remove('pg-col-drag-ghost--hide');
1123
+ // Group zone
1124
+ const overGroupZone = this.groupDropZone?.isOver(e.clientX, e.clientY) ?? false;
1125
+ if (overGroupZone && !this.draggingIsGroupable) {
1126
+ this.stopAutoScroll();
1127
+ this.ghostEl?.classList.add('pg-col-drag-ghost--no-drop');
1128
+ document.body.style.cursor = 'no-drop';
1129
+ if (this.dragStyleEl)
1130
+ this.dragStyleEl.textContent = '';
1131
+ return;
1132
+ }
1133
+ this.ghostEl?.classList.remove('pg-col-drag-ghost--no-drop');
1134
+ document.body.style.cursor = 'grabbing';
1135
+ if (this.draggingIsGroupable && this.groupDropZone) {
1136
+ this.groupDropZone.highlight(overGroupZone);
1137
+ this.isOverGroupZone = overGroupZone;
1138
+ if (overGroupZone) {
1139
+ this.stopAutoScroll();
1140
+ if (this.dragStyleEl)
1141
+ this.dragStyleEl.textContent = '';
1142
+ return;
1143
+ }
1144
+ }
1145
+ this.lastDragClientX = e.clientX;
1146
+ this.updateAutoScroll(e.clientX);
1147
+ this.onDragMove(e.clientX);
1148
+ }
1149
+ onGlobalMouseUp(_e) {
1150
+ if (!this.isDragging) {
1151
+ this.cleanupDrag();
1152
+ return;
1153
+ }
1154
+ const colId = this.draggingColId;
1155
+ if (!colId) {
1156
+ this.cleanupDrag();
1157
+ return;
1158
+ }
1159
+ // Capture state before cleanup resets everything
1160
+ const sourcePanel = this.dragSourcePanel;
1161
+ const targetPanel = this.dragTargetPanel;
1162
+ const targetLocalIdx = this.dragTargetLocalIdx;
1163
+ const targetPD = this.panelDragData.find((pd) => pd.panel === targetPanel);
1164
+ const srcPD = this.panelDragData.find((pd) => pd.panel === sourcePanel);
1165
+ const srcLocalIdx = srcPD?.colIds.indexOf(colId) ?? -1;
1166
+ const isHide = this.dragIsHideMode;
1167
+ const isGroup = this.draggingIsGroupable && this.isOverGroupZone;
1168
+ // Capture the element under the cursor BEFORE cleanupDrag removes the ghost —
1169
+ // this is used below to detect drops on group header cells.
1170
+ const dropEl = document.elementFromPoint(_e.clientX, _e.clientY);
1171
+ const droppedOnGroupId = dropEl?.closest('[data-group-id]')
1172
+ ?.getAttribute('data-group-id') ?? null;
1173
+ // Cleanup first → sets isDragging = false → next model change triggers full header rebuild
1174
+ this.cleanupDrag();
1175
+ if (isHide) {
1176
+ this.columnModel.setColumnVisible(colId, false);
1177
+ return;
1178
+ }
1179
+ if (isGroup && this.groupDropZone) {
1180
+ this.groupDropZone.dropColumn(colId);
1181
+ return;
1182
+ }
1183
+ // When a grouped leaf is dropped onto a DIFFERENT group's header cell, create a
1184
+ // solo clone group rather than doing a plain column reorder. Dropping on the
1185
+ // leaf's own parent group header is treated as a no-op clone check (no action).
1186
+ if (droppedOnGroupId && this.groupModel && this.groupDragHandler) {
1187
+ const parentGroup = this.groupModel.getParent(colId);
1188
+ if (parentGroup) {
1189
+ // Dropped on its own parent → leave in place (within-group reorder already done)
1190
+ if (droppedOnGroupId !== parentGroup.groupId) {
1191
+ this.groupDragHandler.createLeafClone(colId, droppedOnGroupId);
1192
+ return;
1193
+ }
1194
+ return; // same parent — no clone needed
1195
+ }
1196
+ }
1197
+ if (sourcePanel === targetPanel) {
1198
+ // Same-panel (or live-moved, then fine-tuned within new panel)
1199
+ const visibleCols = this.columnModel.getVisibleColumns();
1200
+ const globalFrom = visibleCols.findIndex((c) => c.colId === colId);
1201
+ if (globalFrom === -1)
1202
+ return;
1203
+ const targetColId = targetLocalIdx !== -1 && targetPD ? targetPD.colIds[targetLocalIdx] : null;
1204
+ const globalTo = targetColId ? visibleCols.findIndex((c) => c.colId === targetColId) : globalFrom;
1205
+ // Always call moveColumn to trigger the full header rebuild (even if same position)
1206
+ this.columnModel.moveColumn(globalFrom, globalTo !== -1 ? globalTo : globalFrom);
1207
+ // If the leaf left its parent group's contiguous span, extract it into a
1208
+ // solo clone group so a group header appears at the new position.
1209
+ if (this.groupModel && this.groupDragHandler) {
1210
+ const parent = this.groupModel.getParent(colId);
1211
+ if (parent) {
1212
+ const updatedCols = this.store.get('columns').filter((c) => c.visible !== false);
1213
+ const newIdx = updatedCols.findIndex((c) => c.colId === colId);
1214
+ if (newIdx !== -1 && this.isLeafOutsideGroup(colId, newIdx, updatedCols)) {
1215
+ // insertBeforeId: the column that now follows the leaf in the flat list
1216
+ const insertBeforeId = updatedCols[newIdx + 1]?.colId ?? null;
1217
+ this.groupDragHandler.extractLeafToSoloGroup(colId, insertBeforeId);
1218
+ }
1219
+ }
1220
+ }
1221
+ }
1222
+ else {
1223
+ // Cursor dropped in a different panel than dragSourcePanel (fast move before live rects update)
1224
+ const targetPin = targetPanel === 'left' ? 'left' : targetPanel === 'right' ? 'right' : null;
1225
+ const insertBeforeColId = targetPD ? (targetPD.colIds[targetLocalIdx] ?? null) : null;
1226
+ this.columnModel.moveAndPin(colId, targetPin, insertBeforeColId);
1227
+ // Moving a grouped leaf cross-panel always places it outside its original
1228
+ // group — create a solo clone group in the target panel so the group
1229
+ // header follows the column.
1230
+ if (this.groupModel && this.groupDragHandler) {
1231
+ const parent = this.groupModel.getParent(colId);
1232
+ if (parent) {
1233
+ this.groupDragHandler.extractLeafToSoloGroup(colId, insertBeforeColId);
1234
+ }
1235
+ }
1236
+ }
1237
+ void srcLocalIdx;
1238
+ }
1239
+ cleanupDrag() {
1240
+ this.isDragging = false;
1241
+ this.livePanelMoveInProgress = false;
1242
+ this.draggingIsGroupable = false;
1243
+ this.isOverGroupZone = false;
1244
+ this.dragIsHideMode = false;
1245
+ this.groupDropZone?.highlight(false);
1246
+ this.draggingPanelRowEl?.querySelector('.pg-th--dragging')?.classList.remove('pg-th--dragging');
1247
+ this.ghostEl?.remove();
1248
+ this.ghostEl = null;
1249
+ this.dragStyleEl?.remove();
1250
+ this.dragStyleEl = null;
1251
+ this.draggingGridEl?.classList.remove('pg-grid--col-dragging', 'pg-grid--col-autoscrolling');
1252
+ this.draggingGridEl = null;
1253
+ this.draggedColWidth = 0;
1254
+ this.panelDragData = [];
1255
+ this.dragStartScrollX = 0;
1256
+ this.stopAutoScroll();
1257
+ this.centerPanelRect = null;
1258
+ this.draggingColId = null;
1259
+ this.dragTargetLocalIdx = -1;
1260
+ this.draggingPanelRowEl = null;
1261
+ document.body.style.cursor = '';
1262
+ document.body.style.userSelect = '';
1263
+ document.removeEventListener('mousemove', this.boundMouseMove);
1264
+ document.removeEventListener('mouseup', this.boundMouseUp);
1265
+ }
1266
+ startResize(e, col, thEl) {
1267
+ const startX = e.clientX;
1268
+ const startWidth = this.colStyles.getWidth(col.colId);
1269
+ thEl.classList.add('pg-th--resizing');
1270
+ document.body.style.cursor = 'col-resize';
1271
+ document.body.style.userSelect = 'none';
1272
+ this._isResizingColumn = true;
1273
+ const onMove = (ev) => {
1274
+ this.colStyles.setWidth(col.colId, Math.max(col.minWidth ?? 60, startWidth + (ev.clientX - startX)));
1275
+ this.onResizeCb?.();
1276
+ };
1277
+ const onUp = (ev) => {
1278
+ // Clear the flag BEFORE setColumnWidth fires an event so the final
1279
+ // post-resize render calls renderRows normally and the body is correct.
1280
+ this._isResizingColumn = false;
1281
+ const newWidth = Math.max(col.minWidth ?? 60, startWidth + (ev.clientX - startX));
1282
+ this.colStyles.setWidth(col.colId, newWidth);
1283
+ this.columnModel.setColumnWidth(col.colId, newWidth, true);
1284
+ thEl.classList.remove('pg-th--resizing');
1285
+ document.body.style.cursor = '';
1286
+ document.body.style.userSelect = '';
1287
+ document.removeEventListener('mousemove', onMove);
1288
+ document.removeEventListener('mouseup', onUp);
1289
+ };
1290
+ document.addEventListener('mousemove', onMove);
1291
+ document.addEventListener('mouseup', onUp);
1292
+ }
1293
+ /**
1294
+ * Returns `true` when `colId` (at its new position `newIdx` in the visible
1295
+ * columns array) is no longer adjacent to any sibling leaf from its parent
1296
+ * group — meaning it has been dragged outside the group's contiguous span.
1297
+ *
1298
+ * @param colId - The moved leaf column.
1299
+ * @param newIdx - Its new index in `cols`.
1300
+ * @param cols - Current flat visible-column array (after the move).
1301
+ */
1302
+ isLeafOutsideGroup(colId, newIdx, cols) {
1303
+ if (!this.groupModel)
1304
+ return false;
1305
+ const parent = this.groupModel.getParent(colId);
1306
+ if (!parent)
1307
+ return false;
1308
+ const siblings = new Set(this.groupModel.getLeavesInGroup(parent.groupId)
1309
+ .map((l) => l.colId)
1310
+ .filter((id) => id !== colId));
1311
+ const left = cols[newIdx - 1];
1312
+ const right = cols[newIdx + 1];
1313
+ return !(left && siblings.has(left.colId)) && !(right && siblings.has(right.colId));
1314
+ }
1315
+ onAction(action, colId) {
1316
+ this.eventBus.emit(GridEventType.COLUMNS_STATE_CHANGED, {
1317
+ action, colId, states: this.columnModel.getColumnStates(),
1318
+ });
1319
+ }
1320
+ }
1321
+ //# sourceMappingURL=header-renderer.js.map