@glideappsfinal/glide-data-grid 6.0.9

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 (745) hide show
  1. package/.eslintignore +4 -0
  2. package/.eslintrc +68 -0
  3. package/API.md +1466 -0
  4. package/CHANGELOG.md +895 -0
  5. package/LICENSE +21 -0
  6. package/README.md +190 -0
  7. package/build.sh +21 -0
  8. package/dist/cjs/cells/boolean-cell.js +87 -0
  9. package/dist/cjs/cells/boolean-cell.js.map +1 -0
  10. package/dist/cjs/cells/bubble-cell.js +53 -0
  11. package/dist/cjs/cells/bubble-cell.js.map +1 -0
  12. package/dist/cjs/cells/cell-types.js +2 -0
  13. package/dist/cjs/cells/cell-types.js.map +1 -0
  14. package/dist/cjs/cells/drilldown-cell.js +171 -0
  15. package/dist/cjs/cells/drilldown-cell.js.map +1 -0
  16. package/dist/cjs/cells/image-cell.js +94 -0
  17. package/dist/cjs/cells/image-cell.js.map +1 -0
  18. package/dist/cjs/cells/index.js +29 -0
  19. package/dist/cjs/cells/index.js.map +1 -0
  20. package/dist/cjs/cells/loading-cell.js +41 -0
  21. package/dist/cjs/cells/loading-cell.js.map +1 -0
  22. package/dist/cjs/cells/markdown-cell.js +30 -0
  23. package/dist/cjs/cells/markdown-cell.js.map +1 -0
  24. package/dist/cjs/cells/marker-cell.js +80 -0
  25. package/dist/cjs/cells/marker-cell.js.map +1 -0
  26. package/dist/cjs/cells/new-row-cell.js +53 -0
  27. package/dist/cjs/cells/new-row-cell.js.map +1 -0
  28. package/dist/cjs/cells/number-cell.js +44 -0
  29. package/dist/cjs/cells/number-cell.js.map +1 -0
  30. package/dist/cjs/cells/protected-cell.js +35 -0
  31. package/dist/cjs/cells/protected-cell.js.map +1 -0
  32. package/dist/cjs/cells/row-id-cell.js +23 -0
  33. package/dist/cjs/cells/row-id-cell.js.map +1 -0
  34. package/dist/cjs/cells/text-cell.js +48 -0
  35. package/dist/cjs/cells/text-cell.js.map +1 -0
  36. package/dist/cjs/cells/uri-cell.js +104 -0
  37. package/dist/cjs/cells/uri-cell.js.map +1 -0
  38. package/dist/cjs/common/browser-detect.js +20 -0
  39. package/dist/cjs/common/browser-detect.js.map +1 -0
  40. package/dist/cjs/common/image-window-loader.js +98 -0
  41. package/dist/cjs/common/image-window-loader.js.map +1 -0
  42. package/dist/cjs/common/is-hotkey.js +76 -0
  43. package/dist/cjs/common/is-hotkey.js.map +1 -0
  44. package/dist/cjs/common/math.js +297 -0
  45. package/dist/cjs/common/math.js.map +1 -0
  46. package/dist/cjs/common/render-state-provider.js +70 -0
  47. package/dist/cjs/common/render-state-provider.js.map +1 -0
  48. package/dist/cjs/common/resize-detector.js +27 -0
  49. package/dist/cjs/common/resize-detector.js.map +1 -0
  50. package/dist/cjs/common/styles.js +135 -0
  51. package/dist/cjs/common/styles.js.map +1 -0
  52. package/dist/cjs/common/support.js +60 -0
  53. package/dist/cjs/common/support.js.map +1 -0
  54. package/dist/cjs/common/utils.js +193 -0
  55. package/dist/cjs/common/utils.js.map +1 -0
  56. package/dist/cjs/data-editor/copy-paste.js +269 -0
  57. package/dist/cjs/data-editor/copy-paste.js.map +1 -0
  58. package/dist/cjs/data-editor/data-editor-fns.js +190 -0
  59. package/dist/cjs/data-editor/data-editor-fns.js.map +1 -0
  60. package/dist/cjs/data-editor/data-editor-keybindings.js +126 -0
  61. package/dist/cjs/data-editor/data-editor-keybindings.js.map +1 -0
  62. package/dist/cjs/data-editor/data-editor.js +2892 -0
  63. package/dist/cjs/data-editor/data-editor.js.map +1 -0
  64. package/dist/cjs/data-editor/group-rename.css +2 -0
  65. package/dist/cjs/data-editor/group-rename.js +49 -0
  66. package/dist/cjs/data-editor/group-rename.js.map +1 -0
  67. package/dist/cjs/data-editor/row-grouping-api.js +34 -0
  68. package/dist/cjs/data-editor/row-grouping-api.js.map +1 -0
  69. package/dist/cjs/data-editor/row-grouping.js +189 -0
  70. package/dist/cjs/data-editor/row-grouping.js.map +1 -0
  71. package/dist/cjs/data-editor/use-autoscroll.js +36 -0
  72. package/dist/cjs/data-editor/use-autoscroll.js.map +1 -0
  73. package/dist/cjs/data-editor/use-cells-for-selection.js +53 -0
  74. package/dist/cjs/data-editor/use-cells-for-selection.js.map +1 -0
  75. package/dist/cjs/data-editor/use-column-sizer.js +189 -0
  76. package/dist/cjs/data-editor/use-column-sizer.js.map +1 -0
  77. package/dist/cjs/data-editor/use-initial-scroll-offset.js +81 -0
  78. package/dist/cjs/data-editor/use-initial-scroll-offset.js.map +1 -0
  79. package/dist/cjs/data-editor/use-rem-adjuster.js +29 -0
  80. package/dist/cjs/data-editor/use-rem-adjuster.js.map +1 -0
  81. package/dist/cjs/data-editor/visible-region.js +2 -0
  82. package/dist/cjs/data-editor/visible-region.js.map +1 -0
  83. package/dist/cjs/data-editor-all.js +19 -0
  84. package/dist/cjs/data-editor-all.js.map +1 -0
  85. package/dist/cjs/index.js +36 -0
  86. package/dist/cjs/index.js.map +1 -0
  87. package/dist/cjs/internal/click-outside-container/click-outside-container.js +34 -0
  88. package/dist/cjs/internal/click-outside-container/click-outside-container.js.map +1 -0
  89. package/dist/cjs/internal/data-editor-container/data-grid-container.js +36 -0
  90. package/dist/cjs/internal/data-editor-container/data-grid-container.js.map +1 -0
  91. package/dist/cjs/internal/data-grid/animation-manager.js +95 -0
  92. package/dist/cjs/internal/data-grid/animation-manager.js.map +1 -0
  93. package/dist/cjs/internal/data-grid/cell-set.js +56 -0
  94. package/dist/cjs/internal/data-grid/cell-set.js.map +1 -0
  95. package/dist/cjs/internal/data-grid/color-parser.js +122 -0
  96. package/dist/cjs/internal/data-grid/color-parser.js.map +1 -0
  97. package/dist/cjs/internal/data-grid/data-grid-sprites.js +64 -0
  98. package/dist/cjs/internal/data-grid/data-grid-sprites.js.map +1 -0
  99. package/dist/cjs/internal/data-grid/data-grid-types.js +299 -0
  100. package/dist/cjs/internal/data-grid/data-grid-types.js.map +1 -0
  101. package/dist/cjs/internal/data-grid/data-grid.js +1208 -0
  102. package/dist/cjs/internal/data-grid/data-grid.js.map +1 -0
  103. package/dist/cjs/internal/data-grid/event-args.js +30 -0
  104. package/dist/cjs/internal/data-grid/event-args.js.map +1 -0
  105. package/dist/cjs/internal/data-grid/image-window-loader-interface.js +2 -0
  106. package/dist/cjs/internal/data-grid/image-window-loader-interface.js.map +1 -0
  107. package/dist/cjs/internal/data-grid/render/data-grid-lib.js +652 -0
  108. package/dist/cjs/internal/data-grid/render/data-grid-lib.js.map +1 -0
  109. package/dist/cjs/internal/data-grid/render/data-grid-render.blit.js +218 -0
  110. package/dist/cjs/internal/data-grid/render/data-grid-render.blit.js.map +1 -0
  111. package/dist/cjs/internal/data-grid/render/data-grid-render.cells.js +369 -0
  112. package/dist/cjs/internal/data-grid/render/data-grid-render.cells.js.map +1 -0
  113. package/dist/cjs/internal/data-grid/render/data-grid-render.header.js +440 -0
  114. package/dist/cjs/internal/data-grid/render/data-grid-render.header.js.map +1 -0
  115. package/dist/cjs/internal/data-grid/render/data-grid-render.js +316 -0
  116. package/dist/cjs/internal/data-grid/render/data-grid-render.js.map +1 -0
  117. package/dist/cjs/internal/data-grid/render/data-grid-render.lines.js +256 -0
  118. package/dist/cjs/internal/data-grid/render/data-grid-render.lines.js.map +1 -0
  119. package/dist/cjs/internal/data-grid/render/data-grid-render.walk.js +157 -0
  120. package/dist/cjs/internal/data-grid/render/data-grid-render.walk.js.map +1 -0
  121. package/dist/cjs/internal/data-grid/render/data-grid.render.rings.js +203 -0
  122. package/dist/cjs/internal/data-grid/render/data-grid.render.rings.js.map +1 -0
  123. package/dist/cjs/internal/data-grid/render/draw-checkbox.js +65 -0
  124. package/dist/cjs/internal/data-grid/render/draw-checkbox.js.map +1 -0
  125. package/dist/cjs/internal/data-grid/render/draw-edit-hover-indicator.js +38 -0
  126. package/dist/cjs/internal/data-grid/render/draw-edit-hover-indicator.js.map +1 -0
  127. package/dist/cjs/internal/data-grid/render/draw-grid-arg.js +2 -0
  128. package/dist/cjs/internal/data-grid/render/draw-grid-arg.js.map +1 -0
  129. package/dist/cjs/internal/data-grid/sprites.js +288 -0
  130. package/dist/cjs/internal/data-grid/sprites.js.map +1 -0
  131. package/dist/cjs/internal/data-grid/use-animation-queue.js +33 -0
  132. package/dist/cjs/internal/data-grid/use-animation-queue.js.map +1 -0
  133. package/dist/cjs/internal/data-grid/use-selection-behavior.js +112 -0
  134. package/dist/cjs/internal/data-grid/use-selection-behavior.js.map +1 -0
  135. package/dist/cjs/internal/data-grid-dnd/data-grid-dnd.js +239 -0
  136. package/dist/cjs/internal/data-grid-dnd/data-grid-dnd.js.map +1 -0
  137. package/dist/cjs/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.js +77 -0
  138. package/dist/cjs/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.js.map +1 -0
  139. package/dist/cjs/internal/data-grid-overlay-editor/data-grid-overlay-editor.js +124 -0
  140. package/dist/cjs/internal/data-grid-overlay-editor/data-grid-overlay-editor.js.map +1 -0
  141. package/dist/cjs/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.js +34 -0
  142. package/dist/cjs/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.js.map +1 -0
  143. package/dist/cjs/internal/data-grid-overlay-editor/private/bubbles-overlay-editor.js +10 -0
  144. package/dist/cjs/internal/data-grid-overlay-editor/private/bubbles-overlay-editor.js.map +1 -0
  145. package/dist/cjs/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.js +50 -0
  146. package/dist/cjs/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.js.map +1 -0
  147. package/dist/cjs/internal/data-grid-overlay-editor/private/image-overlay-editor-style.js +56 -0
  148. package/dist/cjs/internal/data-grid-overlay-editor/private/image-overlay-editor-style.js.map +1 -0
  149. package/dist/cjs/internal/data-grid-overlay-editor/private/image-overlay-editor.js +21 -0
  150. package/dist/cjs/internal/data-grid-overlay-editor/private/image-overlay-editor.js.map +1 -0
  151. package/dist/cjs/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.js +76 -0
  152. package/dist/cjs/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.js.map +1 -0
  153. package/dist/cjs/internal/data-grid-overlay-editor/private/markdown-overlay-editor.js +32 -0
  154. package/dist/cjs/internal/data-grid-overlay-editor/private/markdown-overlay-editor.js.map +1 -0
  155. package/dist/cjs/internal/data-grid-overlay-editor/private/number-overlay-editor-style.js +15 -0
  156. package/dist/cjs/internal/data-grid-overlay-editor/private/number-overlay-editor-style.js.map +1 -0
  157. package/dist/cjs/internal/data-grid-overlay-editor/private/number-overlay-editor.js +30 -0
  158. package/dist/cjs/internal/data-grid-overlay-editor/private/number-overlay-editor.js.map +1 -0
  159. package/dist/cjs/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.js +53 -0
  160. package/dist/cjs/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.js.map +1 -0
  161. package/dist/cjs/internal/data-grid-overlay-editor/private/uri-overlay-editor.js +21 -0
  162. package/dist/cjs/internal/data-grid-overlay-editor/private/uri-overlay-editor.js.map +1 -0
  163. package/dist/cjs/internal/data-grid-overlay-editor/use-stay-on-screen.js +47 -0
  164. package/dist/cjs/internal/data-grid-overlay-editor/use-stay-on-screen.js.map +1 -0
  165. package/dist/cjs/internal/data-grid-search/data-grid-search-style.js +96 -0
  166. package/dist/cjs/internal/data-grid-search/data-grid-search-style.js.map +1 -0
  167. package/dist/cjs/internal/data-grid-search/data-grid-search.js +297 -0
  168. package/dist/cjs/internal/data-grid-search/data-grid-search.js.map +1 -0
  169. package/dist/cjs/internal/growing-entry/growing-entry-style.js +60 -0
  170. package/dist/cjs/internal/growing-entry/growing-entry-style.js.map +1 -0
  171. package/dist/cjs/internal/growing-entry/growing-entry.js +41 -0
  172. package/dist/cjs/internal/growing-entry/growing-entry.js.map +1 -0
  173. package/dist/cjs/internal/markdown-div/markdown-div.js +41 -0
  174. package/dist/cjs/internal/markdown-div/markdown-div.js.map +1 -0
  175. package/dist/cjs/internal/markdown-div/private/markdown-container.js +19 -0
  176. package/dist/cjs/internal/markdown-div/private/markdown-container.js.map +1 -0
  177. package/dist/cjs/internal/scrolling-data-grid/infinite-scroller.js +265 -0
  178. package/dist/cjs/internal/scrolling-data-grid/infinite-scroller.js.map +1 -0
  179. package/dist/cjs/internal/scrolling-data-grid/scrolling-data-grid.js +155 -0
  180. package/dist/cjs/internal/scrolling-data-grid/scrolling-data-grid.js.map +1 -0
  181. package/dist/cjs/internal/scrolling-data-grid/use-kinetic-scroll.js +65 -0
  182. package/dist/cjs/internal/scrolling-data-grid/use-kinetic-scroll.js.map +1 -0
  183. package/dist/dts/cells/boolean-cell.d.ts +4 -0
  184. package/dist/dts/cells/boolean-cell.d.ts.map +1 -0
  185. package/dist/dts/cells/bubble-cell.d.ts +4 -0
  186. package/dist/dts/cells/bubble-cell.d.ts.map +1 -0
  187. package/dist/dts/cells/cell-types.d.ts +89 -0
  188. package/dist/dts/cells/cell-types.d.ts.map +1 -0
  189. package/dist/dts/cells/drilldown-cell.d.ts +4 -0
  190. package/dist/dts/cells/drilldown-cell.d.ts.map +1 -0
  191. package/dist/dts/cells/image-cell.d.ts +5 -0
  192. package/dist/dts/cells/image-cell.d.ts.map +1 -0
  193. package/dist/dts/cells/index.d.ts +4 -0
  194. package/dist/dts/cells/index.d.ts.map +1 -0
  195. package/dist/dts/cells/loading-cell.d.ts +4 -0
  196. package/dist/dts/cells/loading-cell.d.ts.map +1 -0
  197. package/dist/dts/cells/markdown-cell.d.ts +4 -0
  198. package/dist/dts/cells/markdown-cell.d.ts.map +1 -0
  199. package/dist/dts/cells/marker-cell.d.ts +4 -0
  200. package/dist/dts/cells/marker-cell.d.ts.map +1 -0
  201. package/dist/dts/cells/new-row-cell.d.ts +4 -0
  202. package/dist/dts/cells/new-row-cell.d.ts.map +1 -0
  203. package/dist/dts/cells/number-cell.d.ts +4 -0
  204. package/dist/dts/cells/number-cell.d.ts.map +1 -0
  205. package/dist/dts/cells/protected-cell.d.ts +4 -0
  206. package/dist/dts/cells/protected-cell.d.ts.map +1 -0
  207. package/dist/dts/cells/row-id-cell.d.ts +4 -0
  208. package/dist/dts/cells/row-id-cell.d.ts.map +1 -0
  209. package/dist/dts/cells/text-cell.d.ts +4 -0
  210. package/dist/dts/cells/text-cell.d.ts.map +1 -0
  211. package/dist/dts/cells/uri-cell.d.ts +4 -0
  212. package/dist/dts/cells/uri-cell.d.ts.map +1 -0
  213. package/dist/dts/common/browser-detect.d.ts +11 -0
  214. package/dist/dts/common/browser-detect.d.ts.map +1 -0
  215. package/dist/dts/common/image-window-loader.d.ts +15 -0
  216. package/dist/dts/common/image-window-loader.d.ts.map +1 -0
  217. package/dist/dts/common/is-hotkey.d.ts +7 -0
  218. package/dist/dts/common/is-hotkey.d.ts.map +1 -0
  219. package/dist/dts/common/math.d.ts +20 -0
  220. package/dist/dts/common/math.d.ts.map +1 -0
  221. package/dist/dts/common/render-state-provider.d.ts +20 -0
  222. package/dist/dts/common/render-state-provider.d.ts.map +1 -0
  223. package/dist/dts/common/resize-detector.d.ts +11 -0
  224. package/dist/dts/common/resize-detector.d.ts.map +1 -0
  225. package/dist/dts/common/styles.d.ts +61 -0
  226. package/dist/dts/common/styles.d.ts.map +1 -0
  227. package/dist/dts/common/support.d.ts +13 -0
  228. package/dist/dts/common/support.d.ts.map +1 -0
  229. package/dist/dts/common/utils.d.ts +38 -0
  230. package/dist/dts/common/utils.d.ts.map +1 -0
  231. package/dist/dts/data-editor/copy-paste.d.ts +22 -0
  232. package/dist/dts/data-editor/copy-paste.d.ts.map +1 -0
  233. package/dist/dts/data-editor/data-editor-fns.d.ts +16 -0
  234. package/dist/dts/data-editor/data-editor-fns.d.ts.map +1 -0
  235. package/dist/dts/data-editor/data-editor-keybindings.d.ts +62 -0
  236. package/dist/dts/data-editor/data-editor-keybindings.d.ts.map +1 -0
  237. package/dist/dts/data-editor/data-editor.d.ts +532 -0
  238. package/dist/dts/data-editor/data-editor.d.ts.map +1 -0
  239. package/dist/dts/data-editor/group-rename.d.ts +12 -0
  240. package/dist/dts/data-editor/group-rename.d.ts.map +1 -0
  241. package/dist/dts/data-editor/row-grouping-api.d.ts +21 -0
  242. package/dist/dts/data-editor/row-grouping-api.d.ts.map +1 -0
  243. package/dist/dts/data-editor/row-grouping.d.ts +82 -0
  244. package/dist/dts/data-editor/row-grouping.d.ts.map +1 -0
  245. package/dist/dts/data-editor/use-autoscroll.d.ts +4 -0
  246. package/dist/dts/data-editor/use-autoscroll.d.ts.map +1 -0
  247. package/dist/dts/data-editor/use-cells-for-selection.d.ts +7 -0
  248. package/dist/dts/data-editor/use-cells-for-selection.d.ts.map +1 -0
  249. package/dist/dts/data-editor/use-column-sizer.d.ts +11 -0
  250. package/dist/dts/data-editor/use-column-sizer.d.ts.map +1 -0
  251. package/dist/dts/data-editor/use-initial-scroll-offset.d.ts +9 -0
  252. package/dist/dts/data-editor/use-initial-scroll-offset.d.ts.map +1 -0
  253. package/dist/dts/data-editor/use-rem-adjuster.d.ts +22 -0
  254. package/dist/dts/data-editor/use-rem-adjuster.d.ts.map +1 -0
  255. package/dist/dts/data-editor/visible-region.d.ts +19 -0
  256. package/dist/dts/data-editor/visible-region.d.ts.map +1 -0
  257. package/dist/dts/data-editor-all.d.ts +8 -0
  258. package/dist/dts/data-editor-all.d.ts.map +1 -0
  259. package/dist/dts/index.d.ts +52 -0
  260. package/dist/dts/index.d.ts.map +1 -0
  261. package/dist/dts/internal/click-outside-container/click-outside-container.d.ts +15 -0
  262. package/dist/dts/internal/click-outside-container/click-outside-container.d.ts.map +1 -0
  263. package/dist/dts/internal/data-editor-container/data-grid-container.d.ts +10 -0
  264. package/dist/dts/internal/data-editor-container/data-grid-container.d.ts.map +1 -0
  265. package/dist/dts/internal/data-grid/animation-manager.d.ts +26 -0
  266. package/dist/dts/internal/data-grid/animation-manager.d.ts.map +1 -0
  267. package/dist/dts/internal/data-grid/cell-set.d.ts +17 -0
  268. package/dist/dts/internal/data-grid/cell-set.d.ts.map +1 -0
  269. package/dist/dts/internal/data-grid/color-parser.d.ts +16 -0
  270. package/dist/dts/internal/data-grid/color-parser.d.ts.map +1 -0
  271. package/dist/dts/internal/data-grid/data-grid-sprites.d.ts +35 -0
  272. package/dist/dts/internal/data-grid/data-grid-sprites.d.ts.map +1 -0
  273. package/dist/dts/internal/data-grid/data-grid-types.d.ts +443 -0
  274. package/dist/dts/internal/data-grid/data-grid-types.d.ts.map +1 -0
  275. package/dist/dts/internal/data-grid/data-grid.d.ts +244 -0
  276. package/dist/dts/internal/data-grid/data-grid.d.ts.map +1 -0
  277. package/dist/dts/internal/data-grid/event-args.d.ts +117 -0
  278. package/dist/dts/internal/data-grid/event-args.d.ts.map +1 -0
  279. package/dist/dts/internal/data-grid/image-window-loader-interface.d.ts +9 -0
  280. package/dist/dts/internal/data-grid/image-window-loader-interface.d.ts.map +1 -0
  281. package/dist/dts/internal/data-grid/render/data-grid-lib.d.ts +60 -0
  282. package/dist/dts/internal/data-grid/render/data-grid-lib.d.ts.map +1 -0
  283. package/dist/dts/internal/data-grid/render/data-grid-render.blit.d.ts +20 -0
  284. package/dist/dts/internal/data-grid/render/data-grid-render.blit.d.ts.map +1 -0
  285. package/dist/dts/internal/data-grid/render/data-grid-render.cells.d.ts +32 -0
  286. package/dist/dts/internal/data-grid/render/data-grid-render.cells.d.ts.map +1 -0
  287. package/dist/dts/internal/data-grid/render/data-grid-render.d.ts +3 -0
  288. package/dist/dts/internal/data-grid/render/data-grid-render.d.ts.map +1 -0
  289. package/dist/dts/internal/data-grid/render/data-grid-render.header.d.ts +22 -0
  290. package/dist/dts/internal/data-grid/render/data-grid-render.header.d.ts.map +1 -0
  291. package/dist/dts/internal/data-grid/render/data-grid-render.lines.d.ts +10 -0
  292. package/dist/dts/internal/data-grid/render/data-grid-render.lines.d.ts.map +1 -0
  293. package/dist/dts/internal/data-grid/render/data-grid-render.walk.d.ts +14 -0
  294. package/dist/dts/internal/data-grid/render/data-grid-render.walk.d.ts.map +1 -0
  295. package/dist/dts/internal/data-grid/render/data-grid.render.rings.d.ts +8 -0
  296. package/dist/dts/internal/data-grid/render/data-grid.render.rings.d.ts.map +1 -0
  297. package/dist/dts/internal/data-grid/render/draw-checkbox.d.ts +4 -0
  298. package/dist/dts/internal/data-grid/render/draw-checkbox.d.ts.map +1 -0
  299. package/dist/dts/internal/data-grid/render/draw-edit-hover-indicator.d.ts +4 -0
  300. package/dist/dts/internal/data-grid/render/draw-edit-hover-indicator.d.ts.map +1 -0
  301. package/dist/dts/internal/data-grid/render/draw-grid-arg.d.ts +73 -0
  302. package/dist/dts/internal/data-grid/render/draw-grid-arg.d.ts.map +1 -0
  303. package/dist/dts/internal/data-grid/sprites.d.ts +34 -0
  304. package/dist/dts/internal/data-grid/sprites.d.ts.map +1 -0
  305. package/dist/dts/internal/data-grid/use-animation-queue.d.ts +5 -0
  306. package/dist/dts/internal/data-grid/use-animation-queue.d.ts.map +1 -0
  307. package/dist/dts/internal/data-grid/use-selection-behavior.d.ts +13 -0
  308. package/dist/dts/internal/data-grid/use-selection-behavior.d.ts.map +1 -0
  309. package/dist/dts/internal/data-grid-dnd/data-grid-dnd.d.ts +63 -0
  310. package/dist/dts/internal/data-grid-dnd/data-grid-dnd.d.ts.map +1 -0
  311. package/dist/dts/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.d.ts +9 -0
  312. package/dist/dts/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.d.ts.map +1 -0
  313. package/dist/dts/internal/data-grid-overlay-editor/data-grid-overlay-editor.d.ts +32 -0
  314. package/dist/dts/internal/data-grid-overlay-editor/data-grid-overlay-editor.d.ts.map +1 -0
  315. package/dist/dts/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.d.ts +2 -0
  316. package/dist/dts/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.d.ts.map +1 -0
  317. package/dist/dts/internal/data-grid-overlay-editor/private/bubbles-overlay-editor.d.ts +7 -0
  318. package/dist/dts/internal/data-grid-overlay-editor/private/bubbles-overlay-editor.d.ts.map +1 -0
  319. package/dist/dts/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.d.ts +8 -0
  320. package/dist/dts/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.d.ts.map +1 -0
  321. package/dist/dts/internal/data-grid-overlay-editor/private/image-overlay-editor-style.d.ts +2 -0
  322. package/dist/dts/internal/data-grid-overlay-editor/private/image-overlay-editor-style.d.ts.map +1 -0
  323. package/dist/dts/internal/data-grid-overlay-editor/private/image-overlay-editor.d.ts +13 -0
  324. package/dist/dts/internal/data-grid-overlay-editor/private/image-overlay-editor.d.ts.map +1 -0
  325. package/dist/dts/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.d.ts +6 -0
  326. package/dist/dts/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.d.ts.map +1 -0
  327. package/dist/dts/internal/data-grid-overlay-editor/private/markdown-overlay-editor.d.ts +14 -0
  328. package/dist/dts/internal/data-grid-overlay-editor/private/markdown-overlay-editor.d.ts.map +1 -0
  329. package/dist/dts/internal/data-grid-overlay-editor/private/number-overlay-editor-style.d.ts +2 -0
  330. package/dist/dts/internal/data-grid-overlay-editor/private/number-overlay-editor-style.d.ts.map +1 -0
  331. package/dist/dts/internal/data-grid-overlay-editor/private/number-overlay-editor.d.ts +17 -0
  332. package/dist/dts/internal/data-grid-overlay-editor/private/number-overlay-editor.d.ts.map +1 -0
  333. package/dist/dts/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.d.ts +2 -0
  334. package/dist/dts/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.d.ts.map +1 -0
  335. package/dist/dts/internal/data-grid-overlay-editor/private/uri-overlay-editor.d.ts +13 -0
  336. package/dist/dts/internal/data-grid-overlay-editor/private/uri-overlay-editor.d.ts.map +1 -0
  337. package/dist/dts/internal/data-grid-overlay-editor/use-stay-on-screen.d.ts +8 -0
  338. package/dist/dts/internal/data-grid-overlay-editor/use-stay-on-screen.d.ts.map +1 -0
  339. package/dist/dts/internal/data-grid-search/data-grid-search-style.d.ts +2 -0
  340. package/dist/dts/internal/data-grid-search/data-grid-search-style.d.ts.map +1 -0
  341. package/dist/dts/internal/data-grid-search/data-grid-search.d.ts +41 -0
  342. package/dist/dts/internal/data-grid-search/data-grid-search.d.ts.map +1 -0
  343. package/dist/dts/internal/growing-entry/growing-entry-style.d.ts +4 -0
  344. package/dist/dts/internal/growing-entry/growing-entry-style.d.ts.map +1 -0
  345. package/dist/dts/internal/growing-entry/growing-entry.d.ts +12 -0
  346. package/dist/dts/internal/growing-entry/growing-entry.d.ts.map +1 -0
  347. package/dist/dts/internal/markdown-div/markdown-div.d.ts +14 -0
  348. package/dist/dts/internal/markdown-div/markdown-div.d.ts.map +1 -0
  349. package/dist/dts/internal/markdown-div/private/markdown-container.d.ts +2 -0
  350. package/dist/dts/internal/markdown-div/private/markdown-container.d.ts.map +1 -0
  351. package/dist/dts/internal/scrolling-data-grid/infinite-scroller.d.ts +38 -0
  352. package/dist/dts/internal/scrolling-data-grid/infinite-scroller.d.ts.map +1 -0
  353. package/dist/dts/internal/scrolling-data-grid/scrolling-data-grid.d.ts +57 -0
  354. package/dist/dts/internal/scrolling-data-grid/scrolling-data-grid.d.ts.map +1 -0
  355. package/dist/dts/internal/scrolling-data-grid/use-kinetic-scroll.d.ts +3 -0
  356. package/dist/dts/internal/scrolling-data-grid/use-kinetic-scroll.d.ts.map +1 -0
  357. package/dist/esm/cells/boolean-cell.js +87 -0
  358. package/dist/esm/cells/boolean-cell.js.map +1 -0
  359. package/dist/esm/cells/bubble-cell.js +53 -0
  360. package/dist/esm/cells/bubble-cell.js.map +1 -0
  361. package/dist/esm/cells/cell-types.js +2 -0
  362. package/dist/esm/cells/cell-types.js.map +1 -0
  363. package/dist/esm/cells/drilldown-cell.js +171 -0
  364. package/dist/esm/cells/drilldown-cell.js.map +1 -0
  365. package/dist/esm/cells/image-cell.js +94 -0
  366. package/dist/esm/cells/image-cell.js.map +1 -0
  367. package/dist/esm/cells/index.js +30 -0
  368. package/dist/esm/cells/index.js.map +1 -0
  369. package/dist/esm/cells/loading-cell.js +41 -0
  370. package/dist/esm/cells/loading-cell.js.map +1 -0
  371. package/dist/esm/cells/markdown-cell.js +30 -0
  372. package/dist/esm/cells/markdown-cell.js.map +1 -0
  373. package/dist/esm/cells/marker-cell.js +80 -0
  374. package/dist/esm/cells/marker-cell.js.map +1 -0
  375. package/dist/esm/cells/new-row-cell.js +53 -0
  376. package/dist/esm/cells/new-row-cell.js.map +1 -0
  377. package/dist/esm/cells/number-cell.js +44 -0
  378. package/dist/esm/cells/number-cell.js.map +1 -0
  379. package/dist/esm/cells/protected-cell.js +35 -0
  380. package/dist/esm/cells/protected-cell.js.map +1 -0
  381. package/dist/esm/cells/row-id-cell.js +23 -0
  382. package/dist/esm/cells/row-id-cell.js.map +1 -0
  383. package/dist/esm/cells/text-cell.js +48 -0
  384. package/dist/esm/cells/text-cell.js.map +1 -0
  385. package/dist/esm/cells/uri-cell.js +104 -0
  386. package/dist/esm/cells/uri-cell.js.map +1 -0
  387. package/dist/esm/common/browser-detect.js +20 -0
  388. package/dist/esm/common/browser-detect.js.map +1 -0
  389. package/dist/esm/common/image-window-loader.js +98 -0
  390. package/dist/esm/common/image-window-loader.js.map +1 -0
  391. package/dist/esm/common/is-hotkey.js +76 -0
  392. package/dist/esm/common/is-hotkey.js.map +1 -0
  393. package/dist/esm/common/math.js +297 -0
  394. package/dist/esm/common/math.js.map +1 -0
  395. package/dist/esm/common/render-state-provider.js +70 -0
  396. package/dist/esm/common/render-state-provider.js.map +1 -0
  397. package/dist/esm/common/resize-detector.js +27 -0
  398. package/dist/esm/common/resize-detector.js.map +1 -0
  399. package/dist/esm/common/styles.js +135 -0
  400. package/dist/esm/common/styles.js.map +1 -0
  401. package/dist/esm/common/support.js +60 -0
  402. package/dist/esm/common/support.js.map +1 -0
  403. package/dist/esm/common/utils.js +193 -0
  404. package/dist/esm/common/utils.js.map +1 -0
  405. package/dist/esm/data-editor/copy-paste.js +269 -0
  406. package/dist/esm/data-editor/copy-paste.js.map +1 -0
  407. package/dist/esm/data-editor/data-editor-fns.js +197 -0
  408. package/dist/esm/data-editor/data-editor-fns.js.map +1 -0
  409. package/dist/esm/data-editor/data-editor-keybindings.js +126 -0
  410. package/dist/esm/data-editor/data-editor-keybindings.js.map +1 -0
  411. package/dist/esm/data-editor/data-editor.js +2892 -0
  412. package/dist/esm/data-editor/data-editor.js.map +1 -0
  413. package/dist/esm/data-editor/group-rename.css +2 -0
  414. package/dist/esm/data-editor/group-rename.js +49 -0
  415. package/dist/esm/data-editor/group-rename.js.map +1 -0
  416. package/dist/esm/data-editor/row-grouping-api.js +34 -0
  417. package/dist/esm/data-editor/row-grouping-api.js.map +1 -0
  418. package/dist/esm/data-editor/row-grouping.js +189 -0
  419. package/dist/esm/data-editor/row-grouping.js.map +1 -0
  420. package/dist/esm/data-editor/use-autoscroll.js +36 -0
  421. package/dist/esm/data-editor/use-autoscroll.js.map +1 -0
  422. package/dist/esm/data-editor/use-cells-for-selection.js +53 -0
  423. package/dist/esm/data-editor/use-cells-for-selection.js.map +1 -0
  424. package/dist/esm/data-editor/use-column-sizer.js +189 -0
  425. package/dist/esm/data-editor/use-column-sizer.js.map +1 -0
  426. package/dist/esm/data-editor/use-initial-scroll-offset.js +81 -0
  427. package/dist/esm/data-editor/use-initial-scroll-offset.js.map +1 -0
  428. package/dist/esm/data-editor/use-rem-adjuster.js +29 -0
  429. package/dist/esm/data-editor/use-rem-adjuster.js.map +1 -0
  430. package/dist/esm/data-editor/visible-region.js +2 -0
  431. package/dist/esm/data-editor/visible-region.js.map +1 -0
  432. package/dist/esm/data-editor-all.js +19 -0
  433. package/dist/esm/data-editor-all.js.map +1 -0
  434. package/dist/esm/index.js +36 -0
  435. package/dist/esm/index.js.map +1 -0
  436. package/dist/esm/internal/click-outside-container/click-outside-container.js +34 -0
  437. package/dist/esm/internal/click-outside-container/click-outside-container.js.map +1 -0
  438. package/dist/esm/internal/data-editor-container/data-grid-container.js +36 -0
  439. package/dist/esm/internal/data-editor-container/data-grid-container.js.map +1 -0
  440. package/dist/esm/internal/data-grid/animation-manager.js +95 -0
  441. package/dist/esm/internal/data-grid/animation-manager.js.map +1 -0
  442. package/dist/esm/internal/data-grid/cell-set.js +56 -0
  443. package/dist/esm/internal/data-grid/cell-set.js.map +1 -0
  444. package/dist/esm/internal/data-grid/color-parser.js +122 -0
  445. package/dist/esm/internal/data-grid/color-parser.js.map +1 -0
  446. package/dist/esm/internal/data-grid/data-grid-sprites.js +65 -0
  447. package/dist/esm/internal/data-grid/data-grid-sprites.js.map +1 -0
  448. package/dist/esm/internal/data-grid/data-grid-types.js +299 -0
  449. package/dist/esm/internal/data-grid/data-grid-types.js.map +1 -0
  450. package/dist/esm/internal/data-grid/data-grid.js +1209 -0
  451. package/dist/esm/internal/data-grid/data-grid.js.map +1 -0
  452. package/dist/esm/internal/data-grid/event-args.js +30 -0
  453. package/dist/esm/internal/data-grid/event-args.js.map +1 -0
  454. package/dist/esm/internal/data-grid/image-window-loader-interface.js +2 -0
  455. package/dist/esm/internal/data-grid/image-window-loader-interface.js.map +1 -0
  456. package/dist/esm/internal/data-grid/render/data-grid-lib.js +653 -0
  457. package/dist/esm/internal/data-grid/render/data-grid-lib.js.map +1 -0
  458. package/dist/esm/internal/data-grid/render/data-grid-render.blit.js +219 -0
  459. package/dist/esm/internal/data-grid/render/data-grid-render.blit.js.map +1 -0
  460. package/dist/esm/internal/data-grid/render/data-grid-render.cells.js +370 -0
  461. package/dist/esm/internal/data-grid/render/data-grid-render.cells.js.map +1 -0
  462. package/dist/esm/internal/data-grid/render/data-grid-render.header.js +440 -0
  463. package/dist/esm/internal/data-grid/render/data-grid-render.header.js.map +1 -0
  464. package/dist/esm/internal/data-grid/render/data-grid-render.js +320 -0
  465. package/dist/esm/internal/data-grid/render/data-grid-render.js.map +1 -0
  466. package/dist/esm/internal/data-grid/render/data-grid-render.lines.js +261 -0
  467. package/dist/esm/internal/data-grid/render/data-grid-render.lines.js.map +1 -0
  468. package/dist/esm/internal/data-grid/render/data-grid-render.walk.js +158 -0
  469. package/dist/esm/internal/data-grid/render/data-grid-render.walk.js.map +1 -0
  470. package/dist/esm/internal/data-grid/render/data-grid.render.rings.js +205 -0
  471. package/dist/esm/internal/data-grid/render/data-grid.render.rings.js.map +1 -0
  472. package/dist/esm/internal/data-grid/render/draw-checkbox.js +65 -0
  473. package/dist/esm/internal/data-grid/render/draw-checkbox.js.map +1 -0
  474. package/dist/esm/internal/data-grid/render/draw-edit-hover-indicator.js +38 -0
  475. package/dist/esm/internal/data-grid/render/draw-edit-hover-indicator.js.map +1 -0
  476. package/dist/esm/internal/data-grid/render/draw-grid-arg.js +2 -0
  477. package/dist/esm/internal/data-grid/render/draw-grid-arg.js.map +1 -0
  478. package/dist/esm/internal/data-grid/sprites.js +288 -0
  479. package/dist/esm/internal/data-grid/sprites.js.map +1 -0
  480. package/dist/esm/internal/data-grid/use-animation-queue.js +34 -0
  481. package/dist/esm/internal/data-grid/use-animation-queue.js.map +1 -0
  482. package/dist/esm/internal/data-grid/use-selection-behavior.js +112 -0
  483. package/dist/esm/internal/data-grid/use-selection-behavior.js.map +1 -0
  484. package/dist/esm/internal/data-grid-dnd/data-grid-dnd.js +239 -0
  485. package/dist/esm/internal/data-grid-dnd/data-grid-dnd.js.map +1 -0
  486. package/dist/esm/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.js +77 -0
  487. package/dist/esm/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.js.map +1 -0
  488. package/dist/esm/internal/data-grid-overlay-editor/data-grid-overlay-editor.js +124 -0
  489. package/dist/esm/internal/data-grid-overlay-editor/data-grid-overlay-editor.js.map +1 -0
  490. package/dist/esm/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.js +34 -0
  491. package/dist/esm/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.js.map +1 -0
  492. package/dist/esm/internal/data-grid-overlay-editor/private/bubbles-overlay-editor.js +10 -0
  493. package/dist/esm/internal/data-grid-overlay-editor/private/bubbles-overlay-editor.js.map +1 -0
  494. package/dist/esm/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.js +50 -0
  495. package/dist/esm/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.js.map +1 -0
  496. package/dist/esm/internal/data-grid-overlay-editor/private/image-overlay-editor-style.js +56 -0
  497. package/dist/esm/internal/data-grid-overlay-editor/private/image-overlay-editor-style.js.map +1 -0
  498. package/dist/esm/internal/data-grid-overlay-editor/private/image-overlay-editor.js +21 -0
  499. package/dist/esm/internal/data-grid-overlay-editor/private/image-overlay-editor.js.map +1 -0
  500. package/dist/esm/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.js +76 -0
  501. package/dist/esm/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.js.map +1 -0
  502. package/dist/esm/internal/data-grid-overlay-editor/private/markdown-overlay-editor.js +32 -0
  503. package/dist/esm/internal/data-grid-overlay-editor/private/markdown-overlay-editor.js.map +1 -0
  504. package/dist/esm/internal/data-grid-overlay-editor/private/number-overlay-editor-style.js +15 -0
  505. package/dist/esm/internal/data-grid-overlay-editor/private/number-overlay-editor-style.js.map +1 -0
  506. package/dist/esm/internal/data-grid-overlay-editor/private/number-overlay-editor.js +30 -0
  507. package/dist/esm/internal/data-grid-overlay-editor/private/number-overlay-editor.js.map +1 -0
  508. package/dist/esm/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.js +53 -0
  509. package/dist/esm/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.js.map +1 -0
  510. package/dist/esm/internal/data-grid-overlay-editor/private/uri-overlay-editor.js +21 -0
  511. package/dist/esm/internal/data-grid-overlay-editor/private/uri-overlay-editor.js.map +1 -0
  512. package/dist/esm/internal/data-grid-overlay-editor/use-stay-on-screen.js +47 -0
  513. package/dist/esm/internal/data-grid-overlay-editor/use-stay-on-screen.js.map +1 -0
  514. package/dist/esm/internal/data-grid-search/data-grid-search-style.js +96 -0
  515. package/dist/esm/internal/data-grid-search/data-grid-search-style.js.map +1 -0
  516. package/dist/esm/internal/data-grid-search/data-grid-search.js +297 -0
  517. package/dist/esm/internal/data-grid-search/data-grid-search.js.map +1 -0
  518. package/dist/esm/internal/growing-entry/growing-entry-style.js +60 -0
  519. package/dist/esm/internal/growing-entry/growing-entry-style.js.map +1 -0
  520. package/dist/esm/internal/growing-entry/growing-entry.js +41 -0
  521. package/dist/esm/internal/growing-entry/growing-entry.js.map +1 -0
  522. package/dist/esm/internal/markdown-div/markdown-div.js +41 -0
  523. package/dist/esm/internal/markdown-div/markdown-div.js.map +1 -0
  524. package/dist/esm/internal/markdown-div/private/markdown-container.js +19 -0
  525. package/dist/esm/internal/markdown-div/private/markdown-container.js.map +1 -0
  526. package/dist/esm/internal/scrolling-data-grid/infinite-scroller.js +265 -0
  527. package/dist/esm/internal/scrolling-data-grid/infinite-scroller.js.map +1 -0
  528. package/dist/esm/internal/scrolling-data-grid/scrolling-data-grid.js +155 -0
  529. package/dist/esm/internal/scrolling-data-grid/scrolling-data-grid.js.map +1 -0
  530. package/dist/esm/internal/scrolling-data-grid/use-kinetic-scroll.js +65 -0
  531. package/dist/esm/internal/scrolling-data-grid/use-kinetic-scroll.js.map +1 -0
  532. package/dist/index.css +2 -0
  533. package/package.json +81 -0
  534. package/src/cells/boolean-cell.tsx +135 -0
  535. package/src/cells/bubble-cell.tsx +68 -0
  536. package/src/cells/cell-types.ts +124 -0
  537. package/src/cells/drilldown-cell.tsx +244 -0
  538. package/src/cells/image-cell.tsx +117 -0
  539. package/src/cells/index.ts +31 -0
  540. package/src/cells/loading-cell.tsx +56 -0
  541. package/src/cells/markdown-cell.tsx +44 -0
  542. package/src/cells/marker-cell.tsx +110 -0
  543. package/src/cells/new-row-cell.tsx +60 -0
  544. package/src/cells/number-cell.tsx +64 -0
  545. package/src/cells/protected-cell.tsx +42 -0
  546. package/src/cells/row-id-cell.tsx +35 -0
  547. package/src/cells/text-cell.tsx +63 -0
  548. package/src/cells/uri-cell.tsx +155 -0
  549. package/src/common/browser-detect.ts +25 -0
  550. package/src/common/image-window-loader.ts +114 -0
  551. package/src/common/is-hotkey.ts +86 -0
  552. package/src/common/math.ts +357 -0
  553. package/src/common/render-state-provider.ts +87 -0
  554. package/src/common/resize-detector.ts +43 -0
  555. package/src/common/styles.ts +214 -0
  556. package/src/common/support.ts +67 -0
  557. package/src/common/utils.tsx +284 -0
  558. package/src/data-editor/copy-paste.ts +320 -0
  559. package/src/data-editor/data-editor-fns.ts +227 -0
  560. package/src/data-editor/data-editor-keybindings.ts +198 -0
  561. package/src/data-editor/data-editor.tsx +4382 -0
  562. package/src/data-editor/group-rename.tsx +67 -0
  563. package/src/data-editor/row-grouping-api.ts +72 -0
  564. package/src/data-editor/row-grouping.ts +326 -0
  565. package/src/data-editor/stories/data-editor-repros.stories.tsx +107 -0
  566. package/src/data-editor/stories/data-editor.stories.tsx +796 -0
  567. package/src/data-editor/stories/utils.tsx +827 -0
  568. package/src/data-editor/use-autoscroll.ts +41 -0
  569. package/src/data-editor/use-cells-for-selection.ts +72 -0
  570. package/src/data-editor/use-column-sizer.ts +253 -0
  571. package/src/data-editor/use-initial-scroll-offset.ts +102 -0
  572. package/src/data-editor/use-rem-adjuster.ts +59 -0
  573. package/src/data-editor/visible-region.ts +20 -0
  574. package/src/data-editor-all.tsx +36 -0
  575. package/src/docs/00-faq.stories.tsx +63 -0
  576. package/src/docs/01-getting-started.stories.tsx +299 -0
  577. package/src/docs/02-editing-data.stories.tsx +365 -0
  578. package/src/docs/03-grid-column.stories.tsx +146 -0
  579. package/src/docs/04-streaming-data.stories.tsx +434 -0
  580. package/src/docs/05-copy-paste.stories.tsx.tsx +279 -0
  581. package/src/docs/06-search.stories.tsx +219 -0
  582. package/src/docs/07-column-grouping.stories.tsx +212 -0
  583. package/src/docs/08-theming.stories.tsx +409 -0
  584. package/src/docs/09-menus.stories.tsx +344 -0
  585. package/src/docs/doc-wrapper.tsx +512 -0
  586. package/src/docs/examples/add-column.stories.tsx +62 -0
  587. package/src/docs/examples/add-data-to-middle.stories.tsx +93 -0
  588. package/src/docs/examples/add-data-to-top.stories.tsx +70 -0
  589. package/src/docs/examples/add-data.stories.tsx +74 -0
  590. package/src/docs/examples/all-cell-kinds.stories.tsx +61 -0
  591. package/src/docs/examples/append-row-handle.stories.tsx +79 -0
  592. package/src/docs/examples/automatic-row-markers.stories.tsx +57 -0
  593. package/src/docs/examples/built-in-search.stories.tsx +83 -0
  594. package/src/docs/examples/cell-activated-event.stories.tsx +92 -0
  595. package/src/docs/examples/column-group-collapse.stories.tsx +105 -0
  596. package/src/docs/examples/column-groups.stories.tsx +51 -0
  597. package/src/docs/examples/content-alignment.stories.tsx +64 -0
  598. package/src/docs/examples/controlled-search.stories.tsx +93 -0
  599. package/src/docs/examples/controlled-selection.stories.tsx +98 -0
  600. package/src/docs/examples/copy-support.stories.tsx +63 -0
  601. package/src/docs/examples/custom-editors.stories.tsx +90 -0
  602. package/src/docs/examples/custom-event-target.stories.tsx +157 -0
  603. package/src/docs/examples/custom-group-header.stories.tsx +423 -0
  604. package/src/docs/examples/custom-header-icons.stories.tsx +76 -0
  605. package/src/docs/examples/custom-header.stories.tsx +67 -0
  606. package/src/docs/examples/custom-renderers.stories.tsx +72 -0
  607. package/src/docs/examples/drag-source.stories.tsx +63 -0
  608. package/src/docs/examples/drop-events.stories.tsx +155 -0
  609. package/src/docs/examples/fill-handle.stories.tsx +118 -0
  610. package/src/docs/examples/freeze-columns.stories.tsx +59 -0
  611. package/src/docs/examples/freeze-rows.stories.tsx +71 -0
  612. package/src/docs/examples/get-mouse-args.stories.tsx +61 -0
  613. package/src/docs/examples/header-menus.stories.tsx +162 -0
  614. package/src/docs/examples/highlight-cells.stories.tsx +84 -0
  615. package/src/docs/examples/imperative-scroll.stories.tsx +96 -0
  616. package/src/docs/examples/input-blending.stories.tsx +116 -0
  617. package/src/docs/examples/keybindings.stories.tsx +90 -0
  618. package/src/docs/examples/layout-integration.stories.tsx +48 -0
  619. package/src/docs/examples/multi-level-column-groups.stories.tsx +119 -0
  620. package/src/docs/examples/multi-select-columns.stories.tsx +47 -0
  621. package/src/docs/examples/new-column-button.stories.tsx +56 -0
  622. package/src/docs/examples/obscured-grid.stories.tsx +70 -0
  623. package/src/docs/examples/observe-visible-region.stories.tsx +56 -0
  624. package/src/docs/examples/one-hundred-thousand-columns.stories.tsx +31 -0
  625. package/src/docs/examples/one-million-rows.stories.tsx +37 -0
  626. package/src/docs/examples/overscroll.stories.tsx +74 -0
  627. package/src/docs/examples/padding.stories.tsx +74 -0
  628. package/src/docs/examples/paste-support.stories.tsx +73 -0
  629. package/src/docs/examples/prevent-diagonal-scroll.stories.tsx +47 -0
  630. package/src/docs/examples/rapid-updates.stories.tsx +108 -0
  631. package/src/docs/examples/rearrange-columns.stories.tsx +76 -0
  632. package/src/docs/examples/reorder-rows.stories.tsx +83 -0
  633. package/src/docs/examples/resizable-columns.stories.tsx +67 -0
  634. package/src/docs/examples/right-element.stories.tsx +87 -0
  635. package/src/docs/examples/right-to-left.stories.tsx +73 -0
  636. package/src/docs/examples/row-and-header-sizes.stories.tsx +75 -0
  637. package/src/docs/examples/row-grouping.stories.tsx +142 -0
  638. package/src/docs/examples/row-hover.stories.tsx +67 -0
  639. package/src/docs/examples/row-markers.stories.tsx +74 -0
  640. package/src/docs/examples/row-selections.stories.tsx +84 -0
  641. package/src/docs/examples/scaled-view.stories.tsx +36 -0
  642. package/src/docs/examples/scroll-offset.stories.tsx +49 -0
  643. package/src/docs/examples/scroll-shadows.stories.tsx +83 -0
  644. package/src/docs/examples/search-as-filter.stories.tsx +76 -0
  645. package/src/docs/examples/selection-serialization.stories.tsx +208 -0
  646. package/src/docs/examples/server-side-data.stories.tsx +219 -0
  647. package/src/docs/examples/shadow-dom.stories.tsx +107 -0
  648. package/src/docs/examples/silly-numbers.stories.tsx +40 -0
  649. package/src/docs/examples/small-editable-grid.stories.tsx +39 -0
  650. package/src/docs/examples/smooth-scrolling-grid.stories.tsx +56 -0
  651. package/src/docs/examples/span-cell.stories.tsx +99 -0
  652. package/src/docs/examples/stretch-column-size.stories.tsx +55 -0
  653. package/src/docs/examples/ten-million-cells.stories.tsx +34 -0
  654. package/src/docs/examples/theme-per-column.stories.tsx +88 -0
  655. package/src/docs/examples/theme-per-row.stories.tsx +73 -0
  656. package/src/docs/examples/theme-support.stories.tsx +150 -0
  657. package/src/docs/examples/tooltips.stories.tsx +119 -0
  658. package/src/docs/examples/trailing-row-options.stories.tsx +106 -0
  659. package/src/docs/examples/uneven-rows.stories.tsx +44 -0
  660. package/src/docs/examples/validate-data.stories.tsx +63 -0
  661. package/src/docs/examples/wrapping-text.stories.tsx +97 -0
  662. package/src/docs/template.tsx +69 -0
  663. package/src/index.ts +87 -0
  664. package/src/internal/click-outside-container/click-outside-container.tsx +50 -0
  665. package/src/internal/data-editor-container/data-grid-container.tsx +48 -0
  666. package/src/internal/data-grid/animation-manager.ts +119 -0
  667. package/src/internal/data-grid/cell-set.ts +65 -0
  668. package/src/internal/data-grid/color-parser.ts +141 -0
  669. package/src/internal/data-grid/data-grid-sprites.ts +107 -0
  670. package/src/internal/data-grid/data-grid-types.ts +742 -0
  671. package/src/internal/data-grid/data-grid.stories.tsx +410 -0
  672. package/src/internal/data-grid/data-grid.tsx +1978 -0
  673. package/src/internal/data-grid/event-args.ts +157 -0
  674. package/src/internal/data-grid/image-window-loader-interface.ts +9 -0
  675. package/src/internal/data-grid/render/data-grid-lib.ts +906 -0
  676. package/src/internal/data-grid/render/data-grid-render.blit.ts +291 -0
  677. package/src/internal/data-grid/render/data-grid-render.cells.ts +564 -0
  678. package/src/internal/data-grid/render/data-grid-render.header.ts +842 -0
  679. package/src/internal/data-grid/render/data-grid-render.lines.ts +379 -0
  680. package/src/internal/data-grid/render/data-grid-render.ts +825 -0
  681. package/src/internal/data-grid/render/data-grid-render.walk.ts +243 -0
  682. package/src/internal/data-grid/render/data-grid.render.rings.ts +348 -0
  683. package/src/internal/data-grid/render/draw-checkbox.ts +122 -0
  684. package/src/internal/data-grid/render/draw-edit-hover-indicator.ts +61 -0
  685. package/src/internal/data-grid/render/draw-grid-arg.ts +85 -0
  686. package/src/internal/data-grid/sprites.ts +321 -0
  687. package/src/internal/data-grid/use-animation-queue.ts +41 -0
  688. package/src/internal/data-grid/use-selection-behavior.ts +152 -0
  689. package/src/internal/data-grid-dnd/data-grid-dnd.tsx +450 -0
  690. package/src/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.tsx +83 -0
  691. package/src/internal/data-grid-overlay-editor/data-grid-overlay-editor.tsx +262 -0
  692. package/src/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.tsx +34 -0
  693. package/src/internal/data-grid-overlay-editor/private/bubbles-overlay-editor.tsx +21 -0
  694. package/src/internal/data-grid-overlay-editor/private/drilldown-overlay-editor.tsx +63 -0
  695. package/src/internal/data-grid-overlay-editor/private/image-overlay-editor-style.tsx +56 -0
  696. package/src/internal/data-grid-overlay-editor/private/image-overlay-editor.tsx +51 -0
  697. package/src/internal/data-grid-overlay-editor/private/markdown-overlay-editor-style.tsx +80 -0
  698. package/src/internal/data-grid-overlay-editor/private/markdown-overlay-editor.tsx +65 -0
  699. package/src/internal/data-grid-overlay-editor/private/number-overlay-editor-style.tsx +15 -0
  700. package/src/internal/data-grid-overlay-editor/private/number-overlay-editor.tsx +77 -0
  701. package/src/internal/data-grid-overlay-editor/private/uri-overlay-editor-style.tsx +53 -0
  702. package/src/internal/data-grid-overlay-editor/private/uri-overlay-editor.tsx +52 -0
  703. package/src/internal/data-grid-overlay-editor/use-stay-on-screen.ts +61 -0
  704. package/src/internal/data-grid-search/data-grid-search-style.tsx +96 -0
  705. package/src/internal/data-grid-search/data-grid-search.tsx +578 -0
  706. package/src/internal/growing-entry/growing-entry-style.tsx +62 -0
  707. package/src/internal/growing-entry/growing-entry.tsx +74 -0
  708. package/src/internal/markdown-div/markdown-div.tsx +55 -0
  709. package/src/internal/markdown-div/private/markdown-container.tsx +19 -0
  710. package/src/internal/scrolling-data-grid/infinite-scroller.tsx +379 -0
  711. package/src/internal/scrolling-data-grid/scrolling-data-grid.stories.tsx +164 -0
  712. package/src/internal/scrolling-data-grid/scrolling-data-grid.tsx +353 -0
  713. package/src/internal/scrolling-data-grid/use-kinetic-scroll.ts +78 -0
  714. package/src/stories/story-utils.tsx +72 -0
  715. package/test/animation-manager.test.ts +147 -0
  716. package/test/cells.test.tsx +122 -0
  717. package/test/click-outside-container.test.tsx +62 -0
  718. package/test/color-parser.test.ts +68 -0
  719. package/test/common.test.ts +74 -0
  720. package/test/compact-selection.test.ts +221 -0
  721. package/test/copy-paste.test.ts +485 -0
  722. package/test/data-editor-fns.test.ts +153 -0
  723. package/test/data-editor-input.test.tsx +683 -0
  724. package/test/data-editor-resize.test.tsx +271 -0
  725. package/test/data-editor.test.tsx +4945 -0
  726. package/test/data-grid-lib.test.ts +457 -0
  727. package/test/data-grid-overlay.test.tsx +67 -0
  728. package/test/data-grid-types.test.ts +52 -0
  729. package/test/data-grid.test.tsx +399 -0
  730. package/test/image-window-loader.test.ts +211 -0
  731. package/test/math.test.ts +201 -0
  732. package/test/render-state-provider.test.ts +86 -0
  733. package/test/row-grouping-api.test.ts +77 -0
  734. package/test/row-grouping.test.ts +586 -0
  735. package/test/test-utils.tsx +365 -0
  736. package/test/uri-cell.test.ts +124 -0
  737. package/test/use-animation-queue.test.ts +53 -0
  738. package/test/use-autoscroll.test.tsx +108 -0
  739. package/test/use-column-sizer.test.tsx +414 -0
  740. package/test/use-deep-memo.test.ts +41 -0
  741. package/test/use-kinetic-scroll.test.ts +57 -0
  742. package/test/use-rem-adjuster.test.ts +69 -0
  743. package/test/utils.test.ts +127 -0
  744. package/vitest.config.ts +40 -0
  745. package/vitest.setup.ts +13 -0
@@ -0,0 +1,2892 @@
1
+ /* eslint-disable sonarjs/no-duplicate-string */
2
+ import * as React from "react";
3
+ import { assert, assertNever, maybe } from "../common/support.js";
4
+ import clamp from "lodash/clamp.js";
5
+ import uniq from "lodash/uniq.js";
6
+ import flatten from "lodash/flatten.js";
7
+ import range from "lodash/range.js";
8
+ import debounce from "lodash/debounce.js";
9
+ import { GridCellKind, isEditableGridCell, isReadWriteCell, InnerGridCellKind, CompactSelection, isInnerOnlyCell, isObjectEditorCallbackResult, BooleanEmpty, BooleanIndeterminate, } from "../internal/data-grid/data-grid-types.js";
10
+ import DataGridSearch, {} from "../internal/data-grid-search/data-grid-search.js";
11
+ import { browserIsOSX } from "../common/browser-detect.js";
12
+ import { getDataEditorTheme, makeCSSStyle, ThemeContext, mergeAndRealizeTheme, } from "../common/styles.js";
13
+ import { getScrollBarWidth, useEventListener, whenDefined } from "../common/utils.js";
14
+ import { isGroupEqual, itemsAreEqual, itemIsInRect, gridSelectionHasItem, getFreezeTrailingHeight, } from "../internal/data-grid/render/data-grid-lib.js";
15
+ import { GroupRename } from "./group-rename.js";
16
+ import { measureColumn, useColumnSizer } from "./use-column-sizer.js";
17
+ import { isHotkey } from "../common/is-hotkey.js";
18
+ import { useSelectionBehavior } from "../internal/data-grid/use-selection-behavior.js";
19
+ import { useCellsForSelection } from "./use-cells-for-selection.js";
20
+ import { unquote, expandSelection, copyToClipboard, toggleBoolean } from "./data-editor-fns.js";
21
+ import { DataEditorContainer } from "../internal/data-editor-container/data-grid-container.js";
22
+ import { useAutoscroll } from "./use-autoscroll.js";
23
+ import { decodeHTML } from "./copy-paste.js";
24
+ import { useRemAdjuster } from "./use-rem-adjuster.js";
25
+ import { withAlpha } from "../internal/data-grid/color-parser.js";
26
+ import { combineRects, getClosestRect, pointInRect } from "../common/math.js";
27
+ import { groupHeaderKind, outOfBoundsKind, headerKind, mouseEventArgsAreEqual, } from "../internal/data-grid/event-args.js";
28
+ import { useKeybindingsWithDefaults } from "./data-editor-keybindings.js";
29
+ import { useRowGroupingInner } from "./row-grouping.js";
30
+ import { useRowGrouping } from "./row-grouping-api.js";
31
+ import { useInitialScrollOffset } from "./use-initial-scroll-offset.js";
32
+ const DataGridOverlayEditor = React.lazy(async () => await import("../internal/data-grid-overlay-editor/data-grid-overlay-editor.js"));
33
+ // There must be a better way
34
+ let idCounter = 0;
35
+ function getSpanStops(cells) {
36
+ return uniq(flatten(flatten(cells)
37
+ .filter(c => c.span !== undefined)
38
+ .map(c => range((c.span?.[0] ?? 0) + 1, (c.span?.[1] ?? 0) + 1))));
39
+ }
40
+ function shiftSelection(input, offset) {
41
+ if (input === undefined || offset === 0 || (input.columns.length === 0 && input.current === undefined))
42
+ return input;
43
+ return {
44
+ current: input.current === undefined
45
+ ? undefined
46
+ : {
47
+ cell: [input.current.cell[0] + offset, input.current.cell[1]],
48
+ range: {
49
+ ...input.current.range,
50
+ x: input.current.range.x + offset,
51
+ },
52
+ rangeStack: input.current.rangeStack.map(r => ({
53
+ ...r,
54
+ x: r.x + offset,
55
+ })),
56
+ },
57
+ rows: input.rows,
58
+ columns: input.columns.offset(offset),
59
+ };
60
+ }
61
+ const loadingCell = {
62
+ kind: GridCellKind.Loading,
63
+ allowOverlay: false,
64
+ };
65
+ export const emptyGridSelection = {
66
+ columns: CompactSelection.empty(),
67
+ rows: CompactSelection.empty(),
68
+ current: undefined,
69
+ };
70
+ const DataEditorImpl = (p, forwardedRef) => {
71
+ const [gridSelectionInner, setGridSelectionInner] = React.useState(emptyGridSelection);
72
+ const [overlay, setOverlay] = React.useState();
73
+ const searchInputRef = React.useRef(null);
74
+ const canvasRef = React.useRef(null);
75
+ const [mouseState, setMouseState] = React.useState();
76
+ const lastSent = React.useRef(undefined);
77
+ const safeWindow = typeof window === "undefined" ? null : window;
78
+ const { imageEditorOverride, getRowThemeOverride: getRowThemeOverrideIn, markdownDivCreateNode, width, height, columns: columnsIn, rows: rowsIn, getCellContent, onCellClicked, onCellActivated, onFillPattern, onFinishedEditing, coercePasteValue, drawHeader: drawHeaderIn, drawGroupHeader: drawGroupHeaderIn, drawCell: drawCellIn, editorBloom, onHeaderClicked, onColumnProposeMove, rangeSelectionColumnSpanning = true, spanRangeBehavior = "default", onGroupHeaderClicked, onCellContextMenu, className, onHeaderContextMenu, getCellsForSelection: getCellsForSelectionIn, onGroupHeaderContextMenu, onGroupHeaderRenamed, onCellEdited, onCellsEdited, onSearchResultsChanged: onSearchResultsChangedIn, searchResults, onSearchValueChange, searchValue, onKeyDown: onKeyDownIn, onKeyUp: onKeyUpIn, keybindings: keybindingsIn, editOnType = true, onRowAppended, onColumnAppended, onColumnMoved, validateCell: validateCellIn, highlightRegions: highlightRegionsIn, rangeSelect = "rect", columnSelect = "multi", rowSelect = "multi", rangeSelectionBlending = "exclusive", columnSelectionBlending = "exclusive", rowSelectionBlending = "exclusive", onDelete: onDeleteIn, onDragStart, onMouseMove, onPaste, copyHeaders = false, freezeColumns = 0, cellActivationBehavior = "second-click", rowSelectionMode = "auto", columnSelectionMode = "auto", onHeaderMenuClick, onHeaderIndicatorClick, getGroupDetails, rowGrouping, onSearchClose: onSearchCloseIn, onItemHovered, onSelectionCleared, showSearch: showSearchIn, onVisibleRegionChanged, gridSelection: gridSelectionOuter, onGridSelectionChange, minColumnWidth: minColumnWidthIn = 50, maxColumnWidth: maxColumnWidthIn = 500, maxColumnAutoWidth: maxColumnAutoWidthIn, provideEditor, trailingRowOptions, freezeTrailingRows = 0, allowedFillDirections = "orthogonal", scrollOffsetX, scrollOffsetY, verticalBorder, onDragOverCell, onDrop, onColumnResize: onColumnResizeIn, onColumnResizeEnd: onColumnResizeEndIn, onColumnResizeStart: onColumnResizeStartIn, customRenderers: additionalRenderers, fillHandle, experimental, fixedShadowX, fixedShadowY, headerIcons, imageWindowLoader, initialSize, isDraggable, onDragLeave, onRowMoved, overscrollX: overscrollXIn, overscrollY: overscrollYIn, preventDiagonalScrolling, rightElement, rightElementProps, trapFocus = false, smoothScrollX, smoothScrollY, scaleToRem = false, rowHeight: rowHeightIn = 34, headerHeight: headerHeightIn = 36, groupHeaderHeight: groupHeaderHeightIn = headerHeightIn, theme: themeIn, isOutsideClick, renderers, resizeIndicator, scrollToActiveCell = true, drawFocusRing: drawFocusRingIn = true, portalElementRef, } = p;
79
+ const drawFocusRing = drawFocusRingIn === "no-editor" ? overlay === undefined : drawFocusRingIn;
80
+ const rowMarkersObj = typeof p.rowMarkers === "string" ? undefined : p.rowMarkers;
81
+ const rowMarkers = rowMarkersObj?.kind ?? p.rowMarkers ?? "none";
82
+ const rowMarkerWidthRaw = rowMarkersObj?.width ?? p.rowMarkerWidth;
83
+ const rowMarkerStartIndex = rowMarkersObj?.startIndex ?? p.rowMarkerStartIndex ?? 1;
84
+ const rowMarkerTheme = rowMarkersObj?.theme ?? p.rowMarkerTheme;
85
+ const headerRowMarkerTheme = rowMarkersObj?.headerTheme;
86
+ const headerRowMarkerAlwaysVisible = rowMarkersObj?.headerAlwaysVisible;
87
+ const headerRowMarkerDisabled = rowSelect !== "multi" || rowMarkersObj?.headerDisabled === true;
88
+ const rowMarkerCheckboxStyle = rowMarkersObj?.checkboxStyle ?? "square";
89
+ const minColumnWidth = Math.max(minColumnWidthIn, 20);
90
+ const maxColumnWidth = Math.max(maxColumnWidthIn, minColumnWidth);
91
+ const maxColumnAutoWidth = Math.max(maxColumnAutoWidthIn ?? maxColumnWidth, minColumnWidth);
92
+ const docStyle = React.useMemo(() => {
93
+ if (typeof window === "undefined")
94
+ return { fontSize: "16px" };
95
+ return window.getComputedStyle(document.documentElement);
96
+ }, []);
97
+ const { rows, rowNumberMapper, rowHeight: rowHeightPostGrouping, getRowThemeOverride, } = useRowGroupingInner(rowGrouping, rowsIn, rowHeightIn, getRowThemeOverrideIn);
98
+ const remSize = React.useMemo(() => Number.parseFloat(docStyle.fontSize), [docStyle]);
99
+ const { rowHeight, headerHeight, groupHeaderHeight, theme, overscrollX, overscrollY } = useRemAdjuster({
100
+ groupHeaderHeight: groupHeaderHeightIn,
101
+ headerHeight: headerHeightIn,
102
+ overscrollX: overscrollXIn,
103
+ overscrollY: overscrollYIn,
104
+ remSize,
105
+ rowHeight: rowHeightPostGrouping,
106
+ scaleToRem,
107
+ theme: themeIn,
108
+ });
109
+ const keybindings = useKeybindingsWithDefaults(keybindingsIn);
110
+ const rowMarkerWidth = rowMarkerWidthRaw ?? (rowsIn > 10_000 ? 48 : rowsIn > 1000 ? 44 : rowsIn > 100 ? 36 : 32);
111
+ const hasRowMarkers = rowMarkers !== "none";
112
+ const rowMarkerOffset = hasRowMarkers ? 1 : 0;
113
+ const showTrailingBlankRow = trailingRowOptions !== undefined;
114
+ const lastRowSticky = trailingRowOptions?.sticky === true;
115
+ const [showSearchInner, setShowSearchInner] = React.useState(false);
116
+ const showSearch = showSearchIn ?? showSearchInner;
117
+ const onSearchClose = React.useCallback(() => {
118
+ if (onSearchCloseIn !== undefined) {
119
+ onSearchCloseIn();
120
+ }
121
+ else {
122
+ setShowSearchInner(false);
123
+ }
124
+ }, [onSearchCloseIn]);
125
+ const gridSelectionOuterMangled = React.useMemo(() => {
126
+ return gridSelectionOuter === undefined ? undefined : shiftSelection(gridSelectionOuter, rowMarkerOffset);
127
+ }, [gridSelectionOuter, rowMarkerOffset]);
128
+ const gridSelection = gridSelectionOuterMangled ?? gridSelectionInner;
129
+ const abortControllerRef = React.useRef(undefined);
130
+ if (abortControllerRef.current === undefined)
131
+ abortControllerRef.current = new AbortController();
132
+ React.useEffect(() => () => abortControllerRef?.current.abort(), []);
133
+ const [getCellsForSelection, getCellsForSeletionDirect] = useCellsForSelection(getCellsForSelectionIn, getCellContent, rowMarkerOffset, abortControllerRef.current, rows);
134
+ const validateCell = React.useCallback((cell, newValue, prevValue) => {
135
+ if (validateCellIn === undefined)
136
+ return true;
137
+ const item = [cell[0] - rowMarkerOffset, cell[1]];
138
+ return validateCellIn?.(item, newValue, prevValue);
139
+ }, [rowMarkerOffset, validateCellIn]);
140
+ const expectedExternalGridSelection = React.useRef(gridSelectionOuter);
141
+ const setGridSelection = React.useCallback((newVal, expand) => {
142
+ if (expand) {
143
+ newVal = expandSelection(newVal, getCellsForSelection, rowMarkerOffset, spanRangeBehavior, abortControllerRef.current);
144
+ }
145
+ if (onGridSelectionChange !== undefined) {
146
+ expectedExternalGridSelection.current = shiftSelection(newVal, -rowMarkerOffset);
147
+ onGridSelectionChange(expectedExternalGridSelection.current);
148
+ }
149
+ else {
150
+ setGridSelectionInner(newVal);
151
+ }
152
+ }, [onGridSelectionChange, getCellsForSelection, rowMarkerOffset, spanRangeBehavior]);
153
+ const onColumnResize = whenDefined(onColumnResizeIn, React.useCallback((_, w, ind, wg) => {
154
+ onColumnResizeIn?.(columnsIn[ind - rowMarkerOffset], w, ind - rowMarkerOffset, wg);
155
+ }, [onColumnResizeIn, rowMarkerOffset, columnsIn]));
156
+ const onColumnResizeEnd = whenDefined(onColumnResizeEndIn, React.useCallback((_, w, ind, wg) => {
157
+ onColumnResizeEndIn?.(columnsIn[ind - rowMarkerOffset], w, ind - rowMarkerOffset, wg);
158
+ }, [onColumnResizeEndIn, rowMarkerOffset, columnsIn]));
159
+ const onColumnResizeStart = whenDefined(onColumnResizeStartIn, React.useCallback((_, w, ind, wg) => {
160
+ onColumnResizeStartIn?.(columnsIn[ind - rowMarkerOffset], w, ind - rowMarkerOffset, wg);
161
+ }, [onColumnResizeStartIn, rowMarkerOffset, columnsIn]));
162
+ const drawHeader = whenDefined(drawHeaderIn, React.useCallback((args, draw) => {
163
+ return drawHeaderIn?.({ ...args, columnIndex: args.columnIndex - rowMarkerOffset }, draw) ?? false;
164
+ }, [drawHeaderIn, rowMarkerOffset]));
165
+ const drawCell = whenDefined(drawCellIn, React.useCallback((args, draw) => {
166
+ return drawCellIn?.({ ...args, col: args.col - rowMarkerOffset }, draw) ?? false;
167
+ }, [drawCellIn, rowMarkerOffset]));
168
+ const onDelete = React.useCallback(sel => {
169
+ if (onDeleteIn !== undefined) {
170
+ const result = onDeleteIn(shiftSelection(sel, -rowMarkerOffset));
171
+ if (typeof result === "boolean") {
172
+ return result;
173
+ }
174
+ return shiftSelection(result, rowMarkerOffset);
175
+ }
176
+ return true;
177
+ }, [onDeleteIn, rowMarkerOffset]);
178
+ const [setCurrent, setSelectedRows, setSelectedColumns] = useSelectionBehavior(gridSelection, setGridSelection, rangeSelectionBlending, columnSelectionBlending, rowSelectionBlending, rangeSelect, rangeSelectionColumnSpanning);
179
+ const mergedTheme = React.useMemo(() => {
180
+ return mergeAndRealizeTheme(getDataEditorTheme(), theme);
181
+ }, [theme]);
182
+ const [clientSize, setClientSize] = React.useState([0, 0, 0]);
183
+ const rendererMap = React.useMemo(() => {
184
+ if (renderers === undefined)
185
+ return {};
186
+ const result = {};
187
+ for (const r of renderers) {
188
+ result[r.kind] = r;
189
+ }
190
+ return result;
191
+ }, [renderers]);
192
+ const getCellRenderer = React.useCallback((cell) => {
193
+ if (cell.kind !== GridCellKind.Custom) {
194
+ return rendererMap[cell.kind];
195
+ }
196
+ return additionalRenderers?.find(x => x.isMatch(cell));
197
+ }, [additionalRenderers, rendererMap]);
198
+ // eslint-disable-next-line prefer-const
199
+ let { sizedColumns: columns, nonGrowWidth } = useColumnSizer(columnsIn, rows, getCellsForSeletionDirect, clientSize[0] - (rowMarkerOffset === 0 ? 0 : rowMarkerWidth) - clientSize[2], minColumnWidth, maxColumnAutoWidth, mergedTheme, getCellRenderer, abortControllerRef.current);
200
+ if (rowMarkers !== "none")
201
+ nonGrowWidth += rowMarkerWidth;
202
+ const enableGroups = React.useMemo(() => {
203
+ return columns.some(c => c.group !== undefined);
204
+ }, [columns]);
205
+ const groupHeights = enableGroups
206
+ ? Array.isArray(groupHeaderHeight)
207
+ ? groupHeaderHeight.reduce((sum, h) => sum + h, 0)
208
+ : groupHeaderHeight
209
+ : 0;
210
+ const totalHeaderHeight = headerHeight + groupHeights;
211
+ const numSelectedRows = gridSelection.rows.length;
212
+ const rowMarkerChecked = rowMarkers === "none" ? undefined : numSelectedRows === 0 ? false : numSelectedRows === rows ? true : undefined;
213
+ const mangledCols = React.useMemo(() => {
214
+ if (rowMarkers === "none")
215
+ return columns;
216
+ return [
217
+ {
218
+ title: "",
219
+ width: rowMarkerWidth,
220
+ icon: undefined,
221
+ hasMenu: false,
222
+ style: "normal",
223
+ themeOverride: rowMarkerTheme,
224
+ rowMarker: rowMarkerCheckboxStyle,
225
+ rowMarkerChecked,
226
+ headerRowMarkerTheme,
227
+ headerRowMarkerAlwaysVisible,
228
+ headerRowMarkerDisabled,
229
+ },
230
+ ...columns,
231
+ ];
232
+ }, [
233
+ rowMarkers,
234
+ columns,
235
+ rowMarkerWidth,
236
+ rowMarkerTheme,
237
+ rowMarkerCheckboxStyle,
238
+ rowMarkerChecked,
239
+ headerRowMarkerTheme,
240
+ headerRowMarkerAlwaysVisible,
241
+ headerRowMarkerDisabled,
242
+ ]);
243
+ const visibleRegionRef = React.useRef({
244
+ height: 1,
245
+ width: 1,
246
+ x: 0,
247
+ y: 0,
248
+ });
249
+ const hasJustScrolled = React.useRef(false);
250
+ const { setVisibleRegion, visibleRegion, scrollRef } = useInitialScrollOffset(scrollOffsetX, scrollOffsetY, rowHeight, visibleRegionRef, () => (hasJustScrolled.current = true));
251
+ visibleRegionRef.current = visibleRegion;
252
+ const cellXOffset = visibleRegion.x + rowMarkerOffset;
253
+ const cellYOffset = visibleRegion.y;
254
+ const gridRef = React.useRef(null);
255
+ const focus = React.useCallback((immediate) => {
256
+ if (immediate === true) {
257
+ gridRef.current?.focus();
258
+ }
259
+ else {
260
+ window.requestAnimationFrame(() => {
261
+ gridRef.current?.focus();
262
+ });
263
+ }
264
+ }, []);
265
+ const mangledRows = showTrailingBlankRow ? rows + 1 : rows;
266
+ const mangledOnCellsEdited = React.useCallback((items) => {
267
+ const mangledItems = rowMarkerOffset === 0
268
+ ? items
269
+ : items.map(x => ({
270
+ ...x,
271
+ location: [x.location[0] - rowMarkerOffset, x.location[1]],
272
+ }));
273
+ const r = onCellsEdited?.(mangledItems);
274
+ if (r !== true) {
275
+ for (const i of mangledItems)
276
+ onCellEdited?.(i.location, i.value);
277
+ }
278
+ return r;
279
+ }, [onCellEdited, onCellsEdited, rowMarkerOffset]);
280
+ const [fillHighlightRegion, setFillHighlightRegion] = React.useState();
281
+ // this will generally be undefined triggering the memo less often
282
+ const highlightRange = gridSelection.current !== undefined &&
283
+ gridSelection.current.range.width * gridSelection.current.range.height > 1
284
+ ? gridSelection.current.range
285
+ : undefined;
286
+ const highlightFocus = drawFocusRing ? gridSelection.current?.cell : undefined;
287
+ const highlightFocusCol = highlightFocus?.[0];
288
+ const highlightFocusRow = highlightFocus?.[1];
289
+ const highlightRegions = React.useMemo(() => {
290
+ if ((highlightRegionsIn === undefined || highlightRegionsIn.length === 0) &&
291
+ (highlightRange ?? highlightFocusCol ?? highlightFocusRow ?? fillHighlightRegion) === undefined)
292
+ return undefined;
293
+ const regions = [];
294
+ if (highlightRegionsIn !== undefined) {
295
+ for (const r of highlightRegionsIn) {
296
+ const maxWidth = mangledCols.length - r.range.x - rowMarkerOffset;
297
+ if (maxWidth > 0) {
298
+ regions.push({
299
+ color: r.color,
300
+ range: {
301
+ ...r.range,
302
+ x: r.range.x + rowMarkerOffset,
303
+ width: Math.min(maxWidth, r.range.width),
304
+ },
305
+ style: r.style,
306
+ });
307
+ }
308
+ }
309
+ }
310
+ if (fillHighlightRegion !== undefined) {
311
+ regions.push({
312
+ color: withAlpha(mergedTheme.accentColor, 0),
313
+ range: fillHighlightRegion,
314
+ style: "dashed",
315
+ });
316
+ }
317
+ if (highlightRange !== undefined) {
318
+ regions.push({
319
+ color: withAlpha(mergedTheme.accentColor, 0.5),
320
+ range: highlightRange,
321
+ style: "solid-outline",
322
+ });
323
+ }
324
+ if (highlightFocusCol !== undefined && highlightFocusRow !== undefined) {
325
+ regions.push({
326
+ color: mergedTheme.accentColor,
327
+ range: {
328
+ x: highlightFocusCol,
329
+ y: highlightFocusRow,
330
+ width: 1,
331
+ height: 1,
332
+ },
333
+ style: "solid-outline",
334
+ });
335
+ }
336
+ return regions.length > 0 ? regions : undefined;
337
+ }, [
338
+ fillHighlightRegion,
339
+ highlightRange,
340
+ highlightFocusCol,
341
+ highlightFocusRow,
342
+ highlightRegionsIn,
343
+ mangledCols.length,
344
+ mergedTheme.accentColor,
345
+ rowMarkerOffset,
346
+ ]);
347
+ const mangledColsRef = React.useRef(mangledCols);
348
+ mangledColsRef.current = mangledCols;
349
+ const getMangledCellContent = React.useCallback(([col, row], forceStrict = false) => {
350
+ const isTrailing = showTrailingBlankRow && row === mangledRows - 1;
351
+ const isRowMarkerCol = col === 0 && hasRowMarkers;
352
+ if (isRowMarkerCol) {
353
+ if (isTrailing) {
354
+ return loadingCell;
355
+ }
356
+ const mappedRow = rowNumberMapper(row);
357
+ if (mappedRow === undefined)
358
+ return loadingCell;
359
+ return {
360
+ kind: InnerGridCellKind.Marker,
361
+ allowOverlay: false,
362
+ checkboxStyle: rowMarkerCheckboxStyle,
363
+ checked: gridSelection?.rows.hasIndex(row) === true,
364
+ markerKind: rowMarkers === "clickable-number" ? "number" : rowMarkers,
365
+ row: rowMarkerStartIndex + mappedRow,
366
+ drawHandle: onRowMoved !== undefined,
367
+ cursor: rowMarkers === "clickable-number" ? "pointer" : undefined,
368
+ };
369
+ }
370
+ else if (isTrailing) {
371
+ //If the grid is empty, we will return text
372
+ const isFirst = col === rowMarkerOffset;
373
+ const maybeFirstColumnHint = isFirst ? (trailingRowOptions?.hint ?? "") : "";
374
+ const c = mangledColsRef.current[col];
375
+ if (c?.trailingRowOptions?.disabled === true) {
376
+ return loadingCell;
377
+ }
378
+ else {
379
+ const hint = c?.trailingRowOptions?.hint ?? maybeFirstColumnHint;
380
+ const icon = c?.trailingRowOptions?.addIcon ?? trailingRowOptions?.addIcon;
381
+ return {
382
+ kind: InnerGridCellKind.NewRow,
383
+ hint,
384
+ allowOverlay: false,
385
+ icon,
386
+ };
387
+ }
388
+ }
389
+ else {
390
+ const outerCol = col - rowMarkerOffset;
391
+ if (forceStrict || experimental?.strict === true) {
392
+ const vr = visibleRegionRef.current;
393
+ const isOutsideMainArea = vr.x > outerCol ||
394
+ outerCol > vr.x + vr.width ||
395
+ vr.y > row ||
396
+ row > vr.y + vr.height ||
397
+ row >= rowsRef.current;
398
+ const isSelected = outerCol === vr.extras?.selected?.[0] && row === vr.extras?.selected[1];
399
+ let isInFreezeArea = false;
400
+ if (vr.extras?.freezeRegions !== undefined) {
401
+ for (const fr of vr.extras.freezeRegions) {
402
+ if (pointInRect(fr, outerCol, row)) {
403
+ isInFreezeArea = true;
404
+ break;
405
+ }
406
+ }
407
+ }
408
+ if (isOutsideMainArea && !isSelected && !isInFreezeArea) {
409
+ return loadingCell;
410
+ }
411
+ }
412
+ let result = getCellContent([outerCol, row]);
413
+ if (rowMarkerOffset !== 0 && result.span !== undefined) {
414
+ result = {
415
+ ...result,
416
+ span: [result.span[0] + rowMarkerOffset, result.span[1] + rowMarkerOffset],
417
+ };
418
+ }
419
+ return result;
420
+ }
421
+ }, [
422
+ showTrailingBlankRow,
423
+ mangledRows,
424
+ hasRowMarkers,
425
+ rowNumberMapper,
426
+ rowMarkerCheckboxStyle,
427
+ gridSelection?.rows,
428
+ rowMarkers,
429
+ rowMarkerStartIndex,
430
+ onRowMoved,
431
+ rowMarkerOffset,
432
+ trailingRowOptions?.hint,
433
+ trailingRowOptions?.addIcon,
434
+ experimental?.strict,
435
+ getCellContent,
436
+ ]);
437
+ const mangledGetGroupDetails = React.useCallback(group => {
438
+ let result = getGroupDetails?.(group) ?? { name: group };
439
+ if (onGroupHeaderRenamed !== undefined && group !== "") {
440
+ result = {
441
+ icon: result.icon,
442
+ name: result.name,
443
+ overrideTheme: result.overrideTheme,
444
+ actions: [
445
+ ...(result.actions ?? []),
446
+ {
447
+ title: "Rename",
448
+ icon: "renameIcon",
449
+ onClick: e => setRenameGroup({
450
+ group: result.name,
451
+ bounds: e.bounds,
452
+ }),
453
+ },
454
+ ],
455
+ };
456
+ }
457
+ return result;
458
+ }, [getGroupDetails, onGroupHeaderRenamed]);
459
+ const setOverlaySimple = React.useCallback((val) => {
460
+ const [col, row] = val.cell;
461
+ const column = mangledCols[col];
462
+ const groupName = column?.group !== undefined
463
+ ? Array.isArray(column.group)
464
+ ? (column.group[0] ?? "")
465
+ : column.group
466
+ : "";
467
+ const groupTheme = groupName !== "" ? mangledGetGroupDetails(groupName)?.overrideTheme : undefined;
468
+ const colTheme = column?.themeOverride;
469
+ const rowTheme = getRowThemeOverride?.(row);
470
+ setOverlay({
471
+ ...val,
472
+ theme: mergeAndRealizeTheme(mergedTheme, groupTheme, colTheme, rowTheme, val.content.themeOverride),
473
+ });
474
+ }, [getRowThemeOverride, mangledCols, mangledGetGroupDetails, mergedTheme]);
475
+ const reselect = React.useCallback((bounds, activation, initialValue) => {
476
+ if (gridSelection.current === undefined)
477
+ return;
478
+ const [col, row] = gridSelection.current.cell;
479
+ const c = getMangledCellContent([col, row]);
480
+ if (c.kind !== GridCellKind.Boolean && c.allowOverlay) {
481
+ let content = c;
482
+ if (initialValue !== undefined) {
483
+ switch (content.kind) {
484
+ case GridCellKind.Number: {
485
+ const d = maybe(() => (initialValue === "-" ? -0 : Number.parseFloat(initialValue)), 0);
486
+ content = {
487
+ ...content,
488
+ data: Number.isNaN(d) ? 0 : d,
489
+ };
490
+ break;
491
+ }
492
+ case GridCellKind.Text:
493
+ case GridCellKind.Markdown:
494
+ case GridCellKind.Uri:
495
+ content = {
496
+ ...content,
497
+ data: initialValue,
498
+ };
499
+ break;
500
+ }
501
+ }
502
+ setOverlaySimple({
503
+ target: bounds,
504
+ content,
505
+ initialValue,
506
+ cell: [col, row],
507
+ highlight: initialValue === undefined,
508
+ forceEditMode: initialValue !== undefined,
509
+ activation,
510
+ });
511
+ }
512
+ else if (c.kind === GridCellKind.Boolean && activation.inputType === "keyboard" && c.readonly !== true) {
513
+ mangledOnCellsEdited([
514
+ {
515
+ location: gridSelection.current.cell,
516
+ value: {
517
+ ...c,
518
+ data: toggleBoolean(c.data),
519
+ },
520
+ },
521
+ ]);
522
+ gridRef.current?.damage([{ cell: gridSelection.current.cell }]);
523
+ }
524
+ }, [getMangledCellContent, gridSelection, mangledOnCellsEdited, setOverlaySimple]);
525
+ const focusOnRowFromTrailingBlankRow = React.useCallback((col, row) => {
526
+ const bounds = gridRef.current?.getBounds(col, row);
527
+ if (bounds === undefined || scrollRef.current === null) {
528
+ return;
529
+ }
530
+ const content = getMangledCellContent([col, row]);
531
+ if (!content.allowOverlay) {
532
+ return;
533
+ }
534
+ setOverlaySimple({
535
+ target: bounds,
536
+ content,
537
+ initialValue: undefined,
538
+ highlight: true,
539
+ cell: [col, row],
540
+ forceEditMode: true,
541
+ activation: { inputType: "keyboard", key: "Enter" },
542
+ });
543
+ }, [getMangledCellContent, scrollRef, setOverlaySimple]);
544
+ const scrollTo = React.useCallback((col, row, dir = "both", paddingX = 0, paddingY = 0, options = undefined) => {
545
+ if (scrollRef.current !== null) {
546
+ const grid = gridRef.current;
547
+ const canvas = canvasRef.current;
548
+ const trueCol = typeof col !== "number" ? (col.unit === "cell" ? col.amount : undefined) : col;
549
+ const trueRow = typeof row !== "number" ? (row.unit === "cell" ? row.amount : undefined) : row;
550
+ const desiredX = typeof col !== "number" && col.unit === "px" ? col.amount : undefined;
551
+ const desiredY = typeof row !== "number" && row.unit === "px" ? row.amount : undefined;
552
+ if (grid !== null && canvas !== null) {
553
+ let targetRect = {
554
+ x: 0,
555
+ y: 0,
556
+ width: 0,
557
+ height: 0,
558
+ };
559
+ let scrollX = 0;
560
+ let scrollY = 0;
561
+ if (trueCol !== undefined || trueRow !== undefined) {
562
+ targetRect = grid.getBounds((trueCol ?? 0) + rowMarkerOffset, trueRow ?? 0) ?? targetRect;
563
+ if (targetRect.width === 0 || targetRect.height === 0)
564
+ return;
565
+ }
566
+ const scrollBounds = canvas.getBoundingClientRect();
567
+ const scale = scrollBounds.width / canvas.offsetWidth;
568
+ if (desiredX !== undefined) {
569
+ targetRect = {
570
+ ...targetRect,
571
+ x: desiredX - scrollBounds.left - scrollRef.current.scrollLeft,
572
+ width: 1,
573
+ };
574
+ }
575
+ if (desiredY !== undefined) {
576
+ targetRect = {
577
+ ...targetRect,
578
+ y: desiredY + scrollBounds.top - scrollRef.current.scrollTop,
579
+ height: 1,
580
+ };
581
+ }
582
+ if (targetRect !== undefined) {
583
+ const bounds = {
584
+ x: targetRect.x - paddingX,
585
+ y: targetRect.y - paddingY,
586
+ width: targetRect.width + 2 * paddingX,
587
+ height: targetRect.height + 2 * paddingY,
588
+ };
589
+ let frozenWidth = 0;
590
+ for (let i = 0; i < freezeColumns; i++) {
591
+ frozenWidth += columns[i].width;
592
+ }
593
+ let trailingRowHeight = 0;
594
+ const freezeTrailingRowsEffective = freezeTrailingRows + (lastRowSticky ? 1 : 0);
595
+ if (freezeTrailingRowsEffective > 0) {
596
+ trailingRowHeight = getFreezeTrailingHeight(mangledRows, freezeTrailingRowsEffective, rowHeight);
597
+ }
598
+ // scrollBounds is already scaled
599
+ let sLeft = frozenWidth * scale + scrollBounds.left + rowMarkerOffset * rowMarkerWidth * scale;
600
+ let sRight = scrollBounds.right;
601
+ let sTop = scrollBounds.top + totalHeaderHeight * scale;
602
+ let sBottom = scrollBounds.bottom - trailingRowHeight * scale;
603
+ const minx = targetRect.width + paddingX * 2;
604
+ switch (options?.hAlign) {
605
+ case "start":
606
+ sRight = sLeft + minx;
607
+ break;
608
+ case "end":
609
+ sLeft = sRight - minx;
610
+ break;
611
+ case "center":
612
+ sLeft = Math.floor((sLeft + sRight) / 2) - minx / 2;
613
+ sRight = sLeft + minx;
614
+ break;
615
+ }
616
+ const miny = targetRect.height + paddingY * 2;
617
+ switch (options?.vAlign) {
618
+ case "start":
619
+ sBottom = sTop + miny;
620
+ break;
621
+ case "end":
622
+ sTop = sBottom - miny;
623
+ break;
624
+ case "center":
625
+ sTop = Math.floor((sTop + sBottom) / 2) - miny / 2;
626
+ sBottom = sTop + miny;
627
+ break;
628
+ }
629
+ if (sLeft > bounds.x) {
630
+ scrollX = bounds.x - sLeft;
631
+ }
632
+ else if (sRight < bounds.x + bounds.width) {
633
+ scrollX = bounds.x + bounds.width - sRight;
634
+ }
635
+ if (sTop > bounds.y) {
636
+ scrollY = bounds.y - sTop;
637
+ }
638
+ else if (sBottom < bounds.y + bounds.height) {
639
+ scrollY = bounds.y + bounds.height - sBottom;
640
+ }
641
+ if (dir === "vertical" || (typeof col === "number" && col < freezeColumns)) {
642
+ scrollX = 0;
643
+ }
644
+ else if (dir === "horizontal" ||
645
+ (typeof row === "number" && row >= mangledRows - freezeTrailingRowsEffective)) {
646
+ scrollY = 0;
647
+ }
648
+ if (scrollX !== 0 || scrollY !== 0) {
649
+ // Remove scaling as scrollTo method is unaffected by transform scale.
650
+ if (scale !== 1) {
651
+ scrollX /= scale;
652
+ scrollY /= scale;
653
+ }
654
+ scrollRef.current.scrollTo({
655
+ left: scrollX + scrollRef.current.scrollLeft,
656
+ top: scrollY + scrollRef.current.scrollTop,
657
+ behavior: options?.behavior ?? "auto",
658
+ });
659
+ }
660
+ }
661
+ }
662
+ }
663
+ }, [
664
+ rowMarkerOffset,
665
+ freezeTrailingRows,
666
+ rowMarkerWidth,
667
+ scrollRef,
668
+ totalHeaderHeight,
669
+ freezeColumns,
670
+ columns,
671
+ mangledRows,
672
+ lastRowSticky,
673
+ rowHeight,
674
+ ]);
675
+ const focusCallback = React.useRef(focusOnRowFromTrailingBlankRow);
676
+ const getCellContentRef = React.useRef(getCellContent);
677
+ focusCallback.current = focusOnRowFromTrailingBlankRow;
678
+ getCellContentRef.current = getCellContent;
679
+ const rowsRef = React.useRef(rows);
680
+ rowsRef.current = rows;
681
+ const colsRef = React.useRef(mangledCols.length);
682
+ colsRef.current = mangledCols.length;
683
+ const appendRow = React.useCallback(async (col, openOverlay = true, behavior) => {
684
+ const c = mangledCols[col];
685
+ if (c?.trailingRowOptions?.disabled === true) {
686
+ return;
687
+ }
688
+ const appendResult = onRowAppended?.();
689
+ let r = undefined;
690
+ let bottom = true;
691
+ if (appendResult !== undefined) {
692
+ r = await appendResult;
693
+ if (r === "top")
694
+ bottom = false;
695
+ if (typeof r === "number")
696
+ bottom = false;
697
+ }
698
+ let backoff = 0;
699
+ const doFocus = () => {
700
+ if (rowsRef.current <= rows) {
701
+ if (backoff < 500) {
702
+ window.setTimeout(doFocus, backoff);
703
+ }
704
+ backoff = 50 + backoff * 2;
705
+ return;
706
+ }
707
+ const row = typeof r === "number" ? r : bottom ? rows : 0;
708
+ scrollToRef.current(col - rowMarkerOffset, row, "both", 0, 0, behavior ? { behavior } : undefined);
709
+ setCurrent({
710
+ cell: [col, row],
711
+ range: {
712
+ x: col,
713
+ y: row,
714
+ width: 1,
715
+ height: 1,
716
+ },
717
+ }, false, false, "edit");
718
+ const cell = getCellContentRef.current([col - rowMarkerOffset, row]);
719
+ if (cell.allowOverlay && isReadWriteCell(cell) && cell.readonly !== true && openOverlay) {
720
+ // wait for scroll to have a chance to process
721
+ window.setTimeout(() => {
722
+ focusCallback.current(col, row);
723
+ }, 0);
724
+ }
725
+ };
726
+ // Queue up to allow the consumer to react to the event and let us check if they did
727
+ doFocus();
728
+ }, [mangledCols, onRowAppended, rowMarkerOffset, rows, setCurrent]);
729
+ const appendColumn = React.useCallback(async (row, openOverlay = true) => {
730
+ const appendResult = onColumnAppended?.();
731
+ let r = undefined;
732
+ let right = true;
733
+ if (appendResult !== undefined) {
734
+ r = await appendResult;
735
+ if (r === "left")
736
+ right = false;
737
+ if (typeof r === "number")
738
+ right = false;
739
+ }
740
+ let backoff = 0;
741
+ const doFocus = () => {
742
+ if (colsRef.current <= mangledCols.length) {
743
+ if (backoff < 500) {
744
+ window.setTimeout(doFocus, backoff);
745
+ }
746
+ backoff = 50 + backoff * 2;
747
+ return;
748
+ }
749
+ const col = typeof r === "number" ? r : right ? mangledCols.length : 0;
750
+ scrollTo(col - rowMarkerOffset, row);
751
+ setCurrent({
752
+ cell: [col, row],
753
+ range: {
754
+ x: col,
755
+ y: row,
756
+ width: 1,
757
+ height: 1,
758
+ },
759
+ }, false, false, "edit");
760
+ const cell = getCellContentRef.current([col - rowMarkerOffset, row]);
761
+ if (cell.allowOverlay && isReadWriteCell(cell) && cell.readonly !== true && openOverlay) {
762
+ window.setTimeout(() => {
763
+ focusCallback.current(col, row);
764
+ }, 0);
765
+ }
766
+ };
767
+ doFocus();
768
+ }, [mangledCols, onColumnAppended, rowMarkerOffset, scrollTo, setCurrent]);
769
+ const getCustomNewRowTargetColumn = React.useCallback((col) => {
770
+ const customTargetColumn = columns[col]?.trailingRowOptions?.targetColumn ?? trailingRowOptions?.targetColumn;
771
+ if (typeof customTargetColumn === "number") {
772
+ const customTargetOffset = hasRowMarkers ? 1 : 0;
773
+ return customTargetColumn + customTargetOffset;
774
+ }
775
+ if (typeof customTargetColumn === "object") {
776
+ const maybeIndex = columnsIn.indexOf(customTargetColumn);
777
+ if (maybeIndex >= 0) {
778
+ const customTargetOffset = hasRowMarkers ? 1 : 0;
779
+ return maybeIndex + customTargetOffset;
780
+ }
781
+ }
782
+ return undefined;
783
+ }, [columns, columnsIn, hasRowMarkers, trailingRowOptions?.targetColumn]);
784
+ const lastSelectedRowRef = React.useRef(undefined);
785
+ const lastSelectedColRef = React.useRef(undefined);
786
+ const themeForCell = React.useCallback((cell, pos) => {
787
+ const [col, row] = pos;
788
+ return mergeAndRealizeTheme(mergedTheme, mangledCols[col]?.themeOverride, getRowThemeOverride?.(row), cell.themeOverride);
789
+ }, [getRowThemeOverride, mangledCols, mergedTheme]);
790
+ const { mapper } = useRowGrouping(rowGrouping, rowsIn);
791
+ const rowGroupingNavBehavior = rowGrouping?.navigationBehavior;
792
+ const handleSelect = React.useCallback((args) => {
793
+ const isMultiKey = browserIsOSX.value ? args.metaKey : args.ctrlKey;
794
+ const isMultiRow = isMultiKey && rowSelect === "multi";
795
+ const [col, row] = args.location;
796
+ const selectedColumns = gridSelection.columns;
797
+ const selectedRows = gridSelection.rows;
798
+ const [cellCol, cellRow] = gridSelection.current?.cell ?? [];
799
+ // eslint-disable-next-line unicorn/prefer-switch
800
+ if (args.kind === "cell") {
801
+ lastSelectedColRef.current = undefined;
802
+ lastMouseSelectLocation.current = [col, row];
803
+ if (col === 0 && hasRowMarkers) {
804
+ if ((showTrailingBlankRow === true && row === rows) ||
805
+ rowMarkers === "number" ||
806
+ rowSelect === "none")
807
+ return;
808
+ const markerCell = getMangledCellContent(args.location);
809
+ if (markerCell.kind !== InnerGridCellKind.Marker) {
810
+ return;
811
+ }
812
+ if (onRowMoved !== undefined) {
813
+ const renderer = getCellRenderer(markerCell);
814
+ assert(renderer?.kind === InnerGridCellKind.Marker);
815
+ const postClick = renderer?.onClick?.({
816
+ ...args,
817
+ cell: markerCell,
818
+ posX: args.localEventX,
819
+ posY: args.localEventY,
820
+ bounds: args.bounds,
821
+ theme: themeForCell(markerCell, args.location),
822
+ preventDefault: () => undefined,
823
+ });
824
+ if (postClick === undefined || postClick.checked === markerCell.checked)
825
+ return;
826
+ }
827
+ setOverlay(undefined);
828
+ focus();
829
+ const isSelected = selectedRows.hasIndex(row);
830
+ const lastHighlighted = lastSelectedRowRef.current;
831
+ if (rowSelect === "multi" &&
832
+ (args.shiftKey || args.isLongTouch === true) &&
833
+ lastHighlighted !== undefined &&
834
+ selectedRows.hasIndex(lastHighlighted)) {
835
+ const newSlice = [Math.min(lastHighlighted, row), Math.max(lastHighlighted, row) + 1];
836
+ if (isMultiRow || rowSelectionMode === "multi") {
837
+ setSelectedRows(undefined, newSlice, true);
838
+ }
839
+ else {
840
+ setSelectedRows(CompactSelection.fromSingleSelection(newSlice), undefined, isMultiRow);
841
+ }
842
+ }
843
+ else if (rowSelect === "multi" && (isMultiRow || args.isTouch || rowSelectionMode === "multi")) {
844
+ if (isSelected) {
845
+ setSelectedRows(selectedRows.remove(row), undefined, true);
846
+ }
847
+ else {
848
+ setSelectedRows(undefined, row, true);
849
+ lastSelectedRowRef.current = row;
850
+ }
851
+ }
852
+ else if (isSelected && selectedRows.length === 1) {
853
+ setSelectedRows(CompactSelection.empty(), undefined, isMultiKey);
854
+ }
855
+ else {
856
+ setSelectedRows(CompactSelection.fromSingleSelection(row), undefined, isMultiKey);
857
+ lastSelectedRowRef.current = row;
858
+ }
859
+ }
860
+ else if (col >= rowMarkerOffset && showTrailingBlankRow && row === rows) {
861
+ const customTargetColumn = getCustomNewRowTargetColumn(col);
862
+ void appendRow(customTargetColumn ?? col);
863
+ }
864
+ else {
865
+ if (cellCol !== col || cellRow !== row) {
866
+ const cell = getMangledCellContent(args.location);
867
+ const renderer = getCellRenderer(cell);
868
+ if (renderer?.onSelect !== undefined) {
869
+ let prevented = false;
870
+ renderer.onSelect({
871
+ ...args,
872
+ cell,
873
+ posX: args.localEventX,
874
+ posY: args.localEventY,
875
+ bounds: args.bounds,
876
+ preventDefault: () => (prevented = true),
877
+ theme: themeForCell(cell, args.location),
878
+ });
879
+ if (prevented) {
880
+ return;
881
+ }
882
+ }
883
+ if (rowGroupingNavBehavior === "block" && mapper(row).isGroupHeader) {
884
+ return;
885
+ }
886
+ const isLastStickyRow = lastRowSticky && row === rows;
887
+ const startedFromLastSticky = lastRowSticky && gridSelection !== undefined && gridSelection.current?.cell[1] === rows;
888
+ if ((args.shiftKey || args.isLongTouch === true) &&
889
+ cellCol !== undefined &&
890
+ cellRow !== undefined &&
891
+ gridSelection.current !== undefined &&
892
+ !startedFromLastSticky) {
893
+ if (isLastStickyRow) {
894
+ // If we're making a selection and shift click in to the last sticky row,
895
+ // just drop the event. Don't kill the selection.
896
+ return;
897
+ }
898
+ const left = Math.min(col, cellCol);
899
+ const right = Math.max(col, cellCol);
900
+ const top = Math.min(row, cellRow);
901
+ const bottom = Math.max(row, cellRow);
902
+ setCurrent({
903
+ ...gridSelection.current,
904
+ range: {
905
+ x: left,
906
+ y: top,
907
+ width: right - left + 1,
908
+ height: bottom - top + 1,
909
+ },
910
+ }, true, isMultiKey, "click");
911
+ lastSelectedRowRef.current = undefined;
912
+ focus();
913
+ }
914
+ else {
915
+ setCurrent({
916
+ cell: [col, row],
917
+ range: { x: col, y: row, width: 1, height: 1 },
918
+ }, true, isMultiKey, "click");
919
+ lastSelectedRowRef.current = undefined;
920
+ setOverlay(undefined);
921
+ focus();
922
+ }
923
+ }
924
+ }
925
+ }
926
+ else if (args.kind === "header") {
927
+ lastMouseSelectLocation.current = [col, row];
928
+ setOverlay(undefined);
929
+ if (hasRowMarkers && col === 0) {
930
+ lastSelectedRowRef.current = undefined;
931
+ lastSelectedColRef.current = undefined;
932
+ if (!headerRowMarkerDisabled && rowSelect === "multi") {
933
+ if (selectedRows.length !== rows) {
934
+ setSelectedRows(CompactSelection.fromSingleSelection([0, rows]), undefined, isMultiKey);
935
+ }
936
+ else {
937
+ setSelectedRows(CompactSelection.empty(), undefined, isMultiKey);
938
+ }
939
+ focus();
940
+ }
941
+ }
942
+ else {
943
+ const lastCol = lastSelectedColRef.current;
944
+ if (columnSelect === "multi" &&
945
+ (args.shiftKey || args.isLongTouch === true) &&
946
+ lastCol !== undefined &&
947
+ selectedColumns.hasIndex(lastCol)) {
948
+ // Support for selecting a slice of columns:
949
+ const newSlice = [Math.min(lastCol, col), Math.max(lastCol, col) + 1];
950
+ if (isMultiKey || args.isTouch || columnSelectionMode === "multi") {
951
+ setSelectedColumns(undefined, newSlice, isMultiKey);
952
+ }
953
+ else {
954
+ setSelectedColumns(CompactSelection.fromSingleSelection(newSlice), undefined, isMultiKey);
955
+ }
956
+ }
957
+ else if (columnSelect === "multi" &&
958
+ (isMultiKey || args.isTouch || columnSelectionMode === "multi")) {
959
+ // Support for selecting a single columns additively:
960
+ if (selectedColumns.hasIndex(col)) {
961
+ // If the column is already selected, deselect that column:
962
+ setSelectedColumns(selectedColumns.remove(col), undefined, isMultiKey);
963
+ }
964
+ else {
965
+ setSelectedColumns(undefined, col, isMultiKey);
966
+ }
967
+ lastSelectedColRef.current = col;
968
+ }
969
+ else if (columnSelect !== "none") {
970
+ if (selectedColumns.hasIndex(col)) {
971
+ // If the column is already selected, deselect that column:
972
+ setSelectedColumns(selectedColumns.remove(col), undefined, isMultiKey);
973
+ }
974
+ else {
975
+ setSelectedColumns(CompactSelection.fromSingleSelection(col), undefined, isMultiKey);
976
+ }
977
+ lastSelectedColRef.current = col;
978
+ }
979
+ lastSelectedRowRef.current = undefined;
980
+ focus();
981
+ }
982
+ }
983
+ else if (args.kind === groupHeaderKind) {
984
+ lastMouseSelectLocation.current = [col, row];
985
+ }
986
+ else if (args.kind === outOfBoundsKind && !args.isMaybeScrollbar) {
987
+ setGridSelection(emptyGridSelection, false);
988
+ setOverlay(undefined);
989
+ focus();
990
+ onSelectionCleared?.();
991
+ lastSelectedRowRef.current = undefined;
992
+ lastSelectedColRef.current = undefined;
993
+ }
994
+ }, [
995
+ rowSelect,
996
+ columnSelect,
997
+ gridSelection,
998
+ hasRowMarkers,
999
+ rowMarkerOffset,
1000
+ showTrailingBlankRow,
1001
+ rows,
1002
+ rowMarkers,
1003
+ getMangledCellContent,
1004
+ onRowMoved,
1005
+ focus,
1006
+ rowSelectionMode,
1007
+ columnSelectionMode,
1008
+ getCellRenderer,
1009
+ themeForCell,
1010
+ setSelectedRows,
1011
+ getCustomNewRowTargetColumn,
1012
+ appendRow,
1013
+ rowGroupingNavBehavior,
1014
+ mapper,
1015
+ lastRowSticky,
1016
+ setCurrent,
1017
+ headerRowMarkerDisabled,
1018
+ setSelectedColumns,
1019
+ setGridSelection,
1020
+ onSelectionCleared,
1021
+ ]);
1022
+ const isActivelyDraggingHeader = React.useRef(false);
1023
+ const lastMouseSelectLocation = React.useRef(undefined);
1024
+ const touchDownArgs = React.useRef(visibleRegion);
1025
+ const mouseDownData = React.useRef(undefined);
1026
+ const onMouseDown = React.useCallback((args) => {
1027
+ isPrevented.current = false;
1028
+ touchDownArgs.current = visibleRegionRef.current;
1029
+ if (args.button !== 0 && args.button !== 1) {
1030
+ mouseDownData.current = undefined;
1031
+ return;
1032
+ }
1033
+ const time = performance.now();
1034
+ mouseDownData.current = {
1035
+ button: args.button,
1036
+ time,
1037
+ location: args.location,
1038
+ };
1039
+ if (args?.kind === "header") {
1040
+ isActivelyDraggingHeader.current = true;
1041
+ }
1042
+ const fh = args.kind === "cell" && args.isFillHandle;
1043
+ if (!fh && args.kind !== "cell" && args.isEdge)
1044
+ return;
1045
+ setMouseState({
1046
+ previousSelection: gridSelection,
1047
+ fillHandle: fh,
1048
+ });
1049
+ lastMouseSelectLocation.current = undefined;
1050
+ if (!args.isTouch && args.button === 0 && !fh) {
1051
+ handleSelect(args);
1052
+ }
1053
+ else if (!args.isTouch && args.button === 1) {
1054
+ lastMouseSelectLocation.current = args.location;
1055
+ }
1056
+ }, [gridSelection, handleSelect]);
1057
+ const [renameGroup, setRenameGroup] = React.useState();
1058
+ const handleGroupHeaderSelection = React.useCallback((args) => {
1059
+ if (args.kind !== groupHeaderKind || columnSelect !== "multi") {
1060
+ return;
1061
+ }
1062
+ const isMultiKey = browserIsOSX.value ? args.metaKey : args.ctrlKey;
1063
+ const [col, row] = args.location;
1064
+ const selectedColumns = gridSelection.columns;
1065
+ if (col < rowMarkerOffset)
1066
+ return;
1067
+ // Determine the level of the clicked group header
1068
+ // row is -2 for level 0, -3 for level 1, etc.
1069
+ const level = row <= -2 ? -2 - row : 0;
1070
+ const needle = mangledCols[col];
1071
+ // Find all columns that belong to the same group at this level and all levels below
1072
+ // We need to find columns that match at the clicked level AND all parent levels
1073
+ let start = col;
1074
+ let end = col;
1075
+ // Find start: go backwards and check if groups match at all levels from 0 to the clicked level
1076
+ for (let i = col - 1; i >= rowMarkerOffset; i--) {
1077
+ let matches = true;
1078
+ for (let l = 0; l <= level; l++) {
1079
+ if (!isGroupEqual(needle.group, mangledCols[i].group, l)) {
1080
+ matches = false;
1081
+ break;
1082
+ }
1083
+ }
1084
+ if (!matches)
1085
+ break;
1086
+ start--;
1087
+ }
1088
+ // Find end: go forwards and check if groups match at all levels from 0 to the clicked level
1089
+ for (let i = col + 1; i < mangledCols.length; i++) {
1090
+ let matches = true;
1091
+ for (let l = 0; l <= level; l++) {
1092
+ if (!isGroupEqual(needle.group, mangledCols[i].group, l)) {
1093
+ matches = false;
1094
+ break;
1095
+ }
1096
+ }
1097
+ if (!matches)
1098
+ break;
1099
+ end++;
1100
+ }
1101
+ focus();
1102
+ if (isMultiKey || args.isTouch || columnSelectionMode === "multi") {
1103
+ if (selectedColumns.hasAll([start, end + 1])) {
1104
+ let newVal = selectedColumns;
1105
+ for (let index = start; index <= end; index++) {
1106
+ newVal = newVal.remove(index);
1107
+ }
1108
+ setSelectedColumns(newVal, undefined, isMultiKey);
1109
+ }
1110
+ else {
1111
+ setSelectedColumns(undefined, [start, end + 1], isMultiKey);
1112
+ }
1113
+ }
1114
+ else {
1115
+ setSelectedColumns(CompactSelection.fromSingleSelection([start, end + 1]), undefined, isMultiKey);
1116
+ }
1117
+ }, [
1118
+ columnSelect,
1119
+ focus,
1120
+ gridSelection.columns,
1121
+ mangledCols,
1122
+ rowMarkerOffset,
1123
+ setSelectedColumns,
1124
+ columnSelectionMode,
1125
+ ]);
1126
+ const isPrevented = React.useRef(false);
1127
+ const normalSizeColumn = React.useCallback(async (col) => {
1128
+ if (getCellsForSelection !== undefined && onColumnResize !== undefined) {
1129
+ const start = visibleRegionRef.current.y;
1130
+ const end = visibleRegionRef.current.height;
1131
+ let cells = getCellsForSelection({
1132
+ x: col,
1133
+ y: start,
1134
+ width: 1,
1135
+ height: Math.min(end, rows - start),
1136
+ }, abortControllerRef.current.signal);
1137
+ if (typeof cells !== "object") {
1138
+ cells = await cells();
1139
+ }
1140
+ const inputCol = columns[col - rowMarkerOffset];
1141
+ const offscreen = document.createElement("canvas");
1142
+ const ctx = offscreen.getContext("2d", { alpha: false });
1143
+ if (ctx !== null) {
1144
+ ctx.font = mergedTheme.baseFontFull;
1145
+ const newCol = measureColumn(ctx, mergedTheme, inputCol, 0, cells, minColumnWidth, maxColumnWidth, false, getCellRenderer);
1146
+ onColumnResize?.(inputCol, newCol.width, col, newCol.width);
1147
+ }
1148
+ }
1149
+ }, [
1150
+ columns,
1151
+ getCellsForSelection,
1152
+ maxColumnWidth,
1153
+ mergedTheme,
1154
+ minColumnWidth,
1155
+ onColumnResize,
1156
+ rowMarkerOffset,
1157
+ rows,
1158
+ getCellRenderer,
1159
+ ]);
1160
+ const [scrollDir, setScrollDir] = React.useState();
1161
+ const fillPattern = React.useCallback(async (previousSelection, currentSelection) => {
1162
+ const patternRange = previousSelection.current?.range;
1163
+ if (patternRange === undefined ||
1164
+ getCellsForSelection === undefined ||
1165
+ currentSelection.current === undefined) {
1166
+ return;
1167
+ }
1168
+ const currentRange = currentSelection.current.range;
1169
+ if (onFillPattern !== undefined) {
1170
+ let canceled = false;
1171
+ onFillPattern({
1172
+ fillDestination: { ...currentRange, x: currentRange.x - rowMarkerOffset },
1173
+ patternSource: { ...patternRange, x: patternRange.x - rowMarkerOffset },
1174
+ preventDefault: () => (canceled = true),
1175
+ });
1176
+ if (canceled)
1177
+ return;
1178
+ }
1179
+ let cells = getCellsForSelection(patternRange, abortControllerRef.current.signal);
1180
+ if (typeof cells !== "object")
1181
+ cells = await cells();
1182
+ const pattern = cells;
1183
+ // loop through all cells in currentSelection.current.range
1184
+ const editItemList = [];
1185
+ for (let x = 0; x < currentRange.width; x++) {
1186
+ for (let y = 0; y < currentRange.height; y++) {
1187
+ const cell = [currentRange.x + x, currentRange.y + y];
1188
+ if (itemIsInRect(cell, patternRange))
1189
+ continue;
1190
+ const patternCell = pattern[y % patternRange.height][x % patternRange.width];
1191
+ if (isInnerOnlyCell(patternCell) || !isReadWriteCell(patternCell))
1192
+ continue;
1193
+ editItemList.push({
1194
+ location: cell,
1195
+ value: { ...patternCell },
1196
+ });
1197
+ }
1198
+ }
1199
+ mangledOnCellsEdited(editItemList);
1200
+ gridRef.current?.damage(editItemList.map(c => ({
1201
+ cell: c.location,
1202
+ })));
1203
+ }, [getCellsForSelection, mangledOnCellsEdited, onFillPattern, rowMarkerOffset]);
1204
+ const fillRight = React.useCallback(() => {
1205
+ if (gridSelection.current === undefined || gridSelection.current.range.width <= 1)
1206
+ return;
1207
+ const firstColSelection = {
1208
+ ...gridSelection,
1209
+ current: {
1210
+ ...gridSelection.current,
1211
+ range: {
1212
+ ...gridSelection.current.range,
1213
+ width: 1,
1214
+ },
1215
+ },
1216
+ };
1217
+ void fillPattern(firstColSelection, gridSelection);
1218
+ }, [fillPattern, gridSelection]);
1219
+ const fillDown = React.useCallback(() => {
1220
+ if (gridSelection.current === undefined || gridSelection.current.range.height <= 1)
1221
+ return;
1222
+ const firstRowSelection = {
1223
+ ...gridSelection,
1224
+ current: {
1225
+ ...gridSelection.current,
1226
+ range: {
1227
+ ...gridSelection.current.range,
1228
+ height: 1,
1229
+ },
1230
+ },
1231
+ };
1232
+ void fillPattern(firstRowSelection, gridSelection);
1233
+ }, [fillPattern, gridSelection]);
1234
+ const onMouseUp = React.useCallback((args, isOutside) => {
1235
+ const mouse = mouseState;
1236
+ setMouseState(undefined);
1237
+ setFillHighlightRegion(undefined);
1238
+ setScrollDir(undefined);
1239
+ isActivelyDraggingHeader.current = false;
1240
+ if (isOutside)
1241
+ return;
1242
+ if (mouse?.fillHandle === true &&
1243
+ gridSelection.current !== undefined &&
1244
+ mouse.previousSelection?.current !== undefined) {
1245
+ if (fillHighlightRegion === undefined)
1246
+ return;
1247
+ const newRange = {
1248
+ ...gridSelection,
1249
+ current: {
1250
+ ...gridSelection.current,
1251
+ range: combineRects(mouse.previousSelection.current.range, fillHighlightRegion),
1252
+ },
1253
+ };
1254
+ void fillPattern(mouse.previousSelection, newRange);
1255
+ setGridSelection(newRange, true);
1256
+ return;
1257
+ }
1258
+ const [col, row] = args.location;
1259
+ const [lastMouseDownCol, lastMouseDownRow] = lastMouseSelectLocation.current ?? [];
1260
+ const preventDefault = () => {
1261
+ isPrevented.current = true;
1262
+ };
1263
+ const handleMaybeClick = (a) => {
1264
+ const isValidClick = a.isTouch || (lastMouseDownCol === col && lastMouseDownRow === row);
1265
+ if (isValidClick) {
1266
+ onCellClicked?.([col - rowMarkerOffset, row], {
1267
+ ...a,
1268
+ preventDefault,
1269
+ });
1270
+ }
1271
+ if (a.button === 1)
1272
+ return !isPrevented.current;
1273
+ if (!isPrevented.current) {
1274
+ const c = getMangledCellContent(args.location);
1275
+ const r = getCellRenderer(c);
1276
+ if (r !== undefined && r.onClick !== undefined && isValidClick) {
1277
+ const newVal = r.onClick({
1278
+ ...a,
1279
+ cell: c,
1280
+ posX: a.localEventX,
1281
+ posY: a.localEventY,
1282
+ bounds: a.bounds,
1283
+ theme: themeForCell(c, args.location),
1284
+ preventDefault,
1285
+ });
1286
+ if (newVal !== undefined && !isInnerOnlyCell(newVal) && isEditableGridCell(newVal)) {
1287
+ mangledOnCellsEdited([{ location: a.location, value: newVal }]);
1288
+ gridRef.current?.damage([
1289
+ {
1290
+ cell: a.location,
1291
+ },
1292
+ ]);
1293
+ }
1294
+ }
1295
+ if (isPrevented.current || gridSelection.current === undefined)
1296
+ return false;
1297
+ let shouldActivate = false;
1298
+ switch (c.activationBehaviorOverride ?? cellActivationBehavior) {
1299
+ case "double-click":
1300
+ case "second-click": {
1301
+ if (mouse?.previousSelection?.current?.cell === undefined)
1302
+ break;
1303
+ const [selectedCol, selectedRow] = gridSelection.current.cell;
1304
+ const [prevCol, prevRow] = mouse.previousSelection.current.cell;
1305
+ const isClickOnSelected = col === selectedCol && col === prevCol && row === selectedRow && row === prevRow;
1306
+ shouldActivate =
1307
+ isClickOnSelected &&
1308
+ (a.isDoubleClick === true || cellActivationBehavior === "second-click");
1309
+ break;
1310
+ }
1311
+ case "single-click": {
1312
+ shouldActivate = true;
1313
+ break;
1314
+ }
1315
+ }
1316
+ if (shouldActivate) {
1317
+ const act = a.isDoubleClick === true
1318
+ ? "double-click"
1319
+ : (c.activationBehaviorOverride ?? cellActivationBehavior);
1320
+ const activationEvent = {
1321
+ inputType: "pointer",
1322
+ pointerActivation: act,
1323
+ pointerType: a.isTouch ? "touch" : "mouse",
1324
+ };
1325
+ onCellActivated?.([col - rowMarkerOffset, row], activationEvent);
1326
+ reselect(a.bounds, activationEvent);
1327
+ return true;
1328
+ }
1329
+ }
1330
+ return false;
1331
+ };
1332
+ const clickLocation = args.location[0] - rowMarkerOffset;
1333
+ if (args.isTouch) {
1334
+ const vr = visibleRegionRef.current;
1335
+ const touchVr = touchDownArgs.current;
1336
+ if (vr.x !== touchVr.x || vr.y !== touchVr.y) {
1337
+ // we scrolled, abort
1338
+ return;
1339
+ }
1340
+ // take care of context menus first if long pressed item is already selected
1341
+ if (args.isLongTouch === true) {
1342
+ if (args.kind === "cell" && itemsAreEqual(gridSelection.current?.cell, args.location)) {
1343
+ onCellContextMenu?.([clickLocation, args.location[1]], {
1344
+ ...args,
1345
+ preventDefault,
1346
+ });
1347
+ return;
1348
+ }
1349
+ else if (args.kind === "header" && gridSelection.columns.hasIndex(col)) {
1350
+ onHeaderContextMenu?.(clickLocation, { ...args, preventDefault });
1351
+ return;
1352
+ }
1353
+ else if (args.kind === groupHeaderKind) {
1354
+ if (clickLocation < 0) {
1355
+ return;
1356
+ }
1357
+ onGroupHeaderContextMenu?.(clickLocation, { ...args, preventDefault });
1358
+ return;
1359
+ }
1360
+ }
1361
+ if (args.kind === "cell") {
1362
+ // click that cell
1363
+ if (!handleMaybeClick(args)) {
1364
+ handleSelect(args);
1365
+ }
1366
+ }
1367
+ else if (args.kind === groupHeaderKind) {
1368
+ onGroupHeaderClicked?.(clickLocation, { ...args, preventDefault });
1369
+ }
1370
+ else {
1371
+ if (args.kind === headerKind) {
1372
+ onHeaderClicked?.(clickLocation, {
1373
+ ...args,
1374
+ preventDefault,
1375
+ });
1376
+ }
1377
+ handleSelect(args);
1378
+ }
1379
+ return;
1380
+ }
1381
+ if (args.kind === "header") {
1382
+ if (clickLocation < 0) {
1383
+ return;
1384
+ }
1385
+ if (args.isEdge) {
1386
+ if (args.isDoubleClick === true) {
1387
+ void normalSizeColumn(col);
1388
+ }
1389
+ }
1390
+ else if (args.button === 0 && col === lastMouseDownCol && row === lastMouseDownRow) {
1391
+ onHeaderClicked?.(clickLocation, { ...args, preventDefault });
1392
+ }
1393
+ }
1394
+ if (args.kind === groupHeaderKind) {
1395
+ if (clickLocation < 0) {
1396
+ return;
1397
+ }
1398
+ if (args.button === 0 && col === lastMouseDownCol && row === lastMouseDownRow) {
1399
+ onGroupHeaderClicked?.(clickLocation, { ...args, preventDefault });
1400
+ if (!isPrevented.current) {
1401
+ handleGroupHeaderSelection(args);
1402
+ }
1403
+ }
1404
+ }
1405
+ if (args.kind === "cell" && (args.button === 0 || args.button === 1)) {
1406
+ handleMaybeClick(args);
1407
+ }
1408
+ lastMouseSelectLocation.current = undefined;
1409
+ }, [
1410
+ mouseState,
1411
+ gridSelection,
1412
+ rowMarkerOffset,
1413
+ fillHighlightRegion,
1414
+ fillPattern,
1415
+ setGridSelection,
1416
+ onCellClicked,
1417
+ getMangledCellContent,
1418
+ getCellRenderer,
1419
+ cellActivationBehavior,
1420
+ themeForCell,
1421
+ mangledOnCellsEdited,
1422
+ onCellActivated,
1423
+ reselect,
1424
+ onCellContextMenu,
1425
+ onHeaderContextMenu,
1426
+ onGroupHeaderContextMenu,
1427
+ handleSelect,
1428
+ onGroupHeaderClicked,
1429
+ onHeaderClicked,
1430
+ normalSizeColumn,
1431
+ handleGroupHeaderSelection,
1432
+ ]);
1433
+ const onMouseMoveImpl = React.useCallback((args) => {
1434
+ const a = {
1435
+ ...args,
1436
+ location: [args.location[0] - rowMarkerOffset, args.location[1]],
1437
+ };
1438
+ onMouseMove?.(a);
1439
+ if (mouseState !== undefined && args.buttons === 0) {
1440
+ setMouseState(undefined);
1441
+ setFillHighlightRegion(undefined);
1442
+ setScrollDir(undefined);
1443
+ isActivelyDraggingHeader.current = false;
1444
+ }
1445
+ setScrollDir(cv => {
1446
+ if (isActivelyDraggingHeader.current)
1447
+ return [args.scrollEdge[0], 0];
1448
+ if (args.scrollEdge[0] === cv?.[0] && args.scrollEdge[1] === cv[1])
1449
+ return cv;
1450
+ return mouseState === undefined || (mouseDownData.current?.location[0] ?? 0) < rowMarkerOffset
1451
+ ? undefined
1452
+ : args.scrollEdge;
1453
+ });
1454
+ }, [mouseState, onMouseMove, rowMarkerOffset]);
1455
+ const onHeaderMenuClickInner = React.useCallback((col, screenPosition) => {
1456
+ onHeaderMenuClick?.(col - rowMarkerOffset, screenPosition);
1457
+ }, [onHeaderMenuClick, rowMarkerOffset]);
1458
+ const onHeaderIndicatorClickInner = React.useCallback((col, screenPosition) => {
1459
+ onHeaderIndicatorClick?.(col - rowMarkerOffset, screenPosition);
1460
+ }, [onHeaderIndicatorClick, rowMarkerOffset]);
1461
+ const currentCell = gridSelection?.current?.cell;
1462
+ const onVisibleRegionChangedImpl = React.useCallback((region, clientWidth, clientHeight, rightElWidth, tx, ty) => {
1463
+ hasJustScrolled.current = false;
1464
+ let selected = currentCell;
1465
+ if (selected !== undefined) {
1466
+ selected = [selected[0] - rowMarkerOffset, selected[1]];
1467
+ }
1468
+ const freezeRegion = freezeColumns === 0
1469
+ ? undefined
1470
+ : {
1471
+ x: 0,
1472
+ y: region.y,
1473
+ width: freezeColumns,
1474
+ height: region.height,
1475
+ };
1476
+ const freezeRegions = [];
1477
+ if (freezeRegion !== undefined)
1478
+ freezeRegions.push(freezeRegion);
1479
+ if (freezeTrailingRows > 0) {
1480
+ freezeRegions.push({
1481
+ x: region.x - rowMarkerOffset,
1482
+ y: rows - freezeTrailingRows,
1483
+ width: region.width,
1484
+ height: freezeTrailingRows,
1485
+ });
1486
+ if (freezeColumns > 0) {
1487
+ freezeRegions.push({
1488
+ x: 0,
1489
+ y: rows - freezeTrailingRows,
1490
+ width: freezeColumns,
1491
+ height: freezeTrailingRows,
1492
+ });
1493
+ }
1494
+ }
1495
+ const newRegion = {
1496
+ x: region.x - rowMarkerOffset,
1497
+ y: region.y,
1498
+ width: region.width,
1499
+ height: showTrailingBlankRow && region.y + region.height >= rows ? region.height - 1 : region.height,
1500
+ tx,
1501
+ ty,
1502
+ extras: {
1503
+ selected,
1504
+ freezeRegion,
1505
+ freezeRegions,
1506
+ },
1507
+ };
1508
+ visibleRegionRef.current = newRegion;
1509
+ setVisibleRegion(newRegion);
1510
+ setClientSize([clientWidth, clientHeight, rightElWidth]);
1511
+ onVisibleRegionChanged?.(newRegion, newRegion.tx, newRegion.ty, newRegion.extras);
1512
+ }, [
1513
+ currentCell,
1514
+ rowMarkerOffset,
1515
+ showTrailingBlankRow,
1516
+ rows,
1517
+ freezeColumns,
1518
+ freezeTrailingRows,
1519
+ setVisibleRegion,
1520
+ onVisibleRegionChanged,
1521
+ ]);
1522
+ const onColumnProposeMoveImpl = whenDefined(onColumnProposeMove, React.useCallback((startIndex, endIndex) => {
1523
+ return onColumnProposeMove?.(startIndex - rowMarkerOffset, endIndex - rowMarkerOffset) !== false;
1524
+ }, [onColumnProposeMove, rowMarkerOffset]));
1525
+ const onColumnMovedImpl = whenDefined(onColumnMoved, React.useCallback((startIndex, endIndex) => {
1526
+ onColumnMoved?.(startIndex - rowMarkerOffset, endIndex - rowMarkerOffset);
1527
+ if (columnSelect !== "none") {
1528
+ setSelectedColumns(CompactSelection.fromSingleSelection(endIndex), undefined, true);
1529
+ }
1530
+ }, [columnSelect, onColumnMoved, rowMarkerOffset, setSelectedColumns]));
1531
+ const isActivelyDragging = React.useRef(false);
1532
+ const onDragStartImpl = React.useCallback((args) => {
1533
+ if (args.location[0] === 0 && rowMarkerOffset > 0) {
1534
+ args.preventDefault();
1535
+ return;
1536
+ }
1537
+ onDragStart?.({
1538
+ ...args,
1539
+ location: [args.location[0] - rowMarkerOffset, args.location[1]],
1540
+ });
1541
+ if (!args.defaultPrevented()) {
1542
+ isActivelyDragging.current = true;
1543
+ }
1544
+ setMouseState(undefined);
1545
+ }, [onDragStart, rowMarkerOffset]);
1546
+ const onDragEnd = React.useCallback(() => {
1547
+ isActivelyDragging.current = false;
1548
+ }, []);
1549
+ const rowGroupingSelectionBehavior = rowGrouping?.selectionBehavior;
1550
+ const getSelectionRowLimits = React.useCallback((selectedRow) => {
1551
+ if (rowGroupingSelectionBehavior !== "block-spanning")
1552
+ return undefined;
1553
+ const { isGroupHeader, path, groupRows } = mapper(selectedRow);
1554
+ if (isGroupHeader) {
1555
+ return [selectedRow, selectedRow];
1556
+ }
1557
+ const groupRowIndex = path[path.length - 1];
1558
+ const lowerBounds = selectedRow - groupRowIndex;
1559
+ const upperBounds = selectedRow + groupRows - groupRowIndex - 1;
1560
+ return [lowerBounds, upperBounds];
1561
+ }, [mapper, rowGroupingSelectionBehavior]);
1562
+ const hoveredRef = React.useRef(undefined);
1563
+ const onItemHoveredImpl = React.useCallback((args) => {
1564
+ // make sure we still have a button down
1565
+ if (mouseEventArgsAreEqual(args, hoveredRef.current))
1566
+ return;
1567
+ hoveredRef.current = args;
1568
+ if (mouseDownData?.current?.button !== undefined && mouseDownData.current.button >= 1)
1569
+ return;
1570
+ if (args.buttons !== 0 &&
1571
+ mouseState !== undefined &&
1572
+ mouseDownData.current?.location[0] === 0 &&
1573
+ rowMarkerOffset === 1 &&
1574
+ rowSelect === "multi" &&
1575
+ mouseState.previousSelection &&
1576
+ !mouseState.previousSelection.rows.hasIndex(mouseDownData.current.location[1]) &&
1577
+ gridSelection.rows.hasIndex(mouseDownData.current.location[1])) {
1578
+ const start = Math.min(mouseDownData.current.location[1], args.location[1]);
1579
+ const end = Math.max(mouseDownData.current.location[1], args.location[1]) + 1;
1580
+ setSelectedRows(CompactSelection.fromSingleSelection([start, end]), undefined, false);
1581
+ }
1582
+ // Only handle rect selection if not already processed by row selection:
1583
+ else if (args.buttons !== 0 &&
1584
+ mouseState !== undefined &&
1585
+ gridSelection.current !== undefined &&
1586
+ !isActivelyDragging.current &&
1587
+ !isActivelyDraggingHeader.current &&
1588
+ (rangeSelect === "rect" || rangeSelect === "multi-rect")) {
1589
+ const [selectedCol, selectedRow] = gridSelection.current.cell;
1590
+ // eslint-disable-next-line prefer-const
1591
+ let [col, row] = args.location;
1592
+ if (row < 0) {
1593
+ row = visibleRegionRef.current.y;
1594
+ }
1595
+ if (mouseState.fillHandle === true && mouseState.previousSelection?.current !== undefined) {
1596
+ const prevRange = mouseState.previousSelection.current.range;
1597
+ row = Math.min(row, showTrailingBlankRow ? rows - 1 : rows);
1598
+ const rect = getClosestRect(prevRange, col, row, allowedFillDirections);
1599
+ setFillHighlightRegion(rect);
1600
+ }
1601
+ else {
1602
+ const startedFromLastStickyRow = showTrailingBlankRow && selectedRow === rows;
1603
+ if (startedFromLastStickyRow)
1604
+ return;
1605
+ const landedOnLastStickyRow = showTrailingBlankRow && row === rows;
1606
+ if (landedOnLastStickyRow) {
1607
+ if (args.kind === outOfBoundsKind)
1608
+ row--;
1609
+ else
1610
+ return;
1611
+ }
1612
+ col = Math.max(col, rowMarkerOffset);
1613
+ const clampLimits = getSelectionRowLimits(selectedRow);
1614
+ row = clampLimits === undefined ? row : clamp(row, clampLimits[0], clampLimits[1]);
1615
+ // FIXME: Restrict row based on rowGrouping.selectionBehavior here
1616
+ const deltaX = col - selectedCol;
1617
+ const deltaY = row - selectedRow;
1618
+ const newRange = {
1619
+ x: deltaX >= 0 ? selectedCol : col,
1620
+ y: deltaY >= 0 ? selectedRow : row,
1621
+ width: Math.abs(deltaX) + 1,
1622
+ height: Math.abs(deltaY) + 1,
1623
+ };
1624
+ setCurrent({
1625
+ ...gridSelection.current,
1626
+ range: newRange,
1627
+ }, true, false, "drag");
1628
+ }
1629
+ }
1630
+ onItemHovered?.({ ...args, location: [args.location[0] - rowMarkerOffset, args.location[1]] });
1631
+ }, [
1632
+ mouseState,
1633
+ rowMarkerOffset,
1634
+ rowSelect,
1635
+ gridSelection,
1636
+ rangeSelect,
1637
+ onItemHovered,
1638
+ setSelectedRows,
1639
+ showTrailingBlankRow,
1640
+ rows,
1641
+ allowedFillDirections,
1642
+ getSelectionRowLimits,
1643
+ setCurrent,
1644
+ ]);
1645
+ const adjustSelectionOnScroll = React.useCallback(() => {
1646
+ const args = hoveredRef.current;
1647
+ if (args === undefined)
1648
+ return;
1649
+ const [xDir, yDir] = args.scrollEdge;
1650
+ let [col, row] = args.location;
1651
+ const visible = visibleRegionRef.current;
1652
+ if (xDir === -1) {
1653
+ col = visible.extras?.freezeRegion?.x ?? visible.x;
1654
+ }
1655
+ else if (xDir === 1) {
1656
+ col = visible.x + visible.width;
1657
+ }
1658
+ if (yDir === -1) {
1659
+ row = Math.max(0, visible.y);
1660
+ }
1661
+ else if (yDir === 1) {
1662
+ row = Math.min(rows - 1, visible.y + visible.height);
1663
+ }
1664
+ col = clamp(col, 0, mangledCols.length - 1);
1665
+ row = clamp(row, 0, rows - 1);
1666
+ onItemHoveredImpl({
1667
+ ...args,
1668
+ location: [col, row],
1669
+ });
1670
+ }, [mangledCols.length, onItemHoveredImpl, rows]);
1671
+ useAutoscroll(scrollDir, scrollRef, adjustSelectionOnScroll);
1672
+ // 1 === move one
1673
+ // 2 === move to end
1674
+ const adjustSelection = React.useCallback((direction) => {
1675
+ if (gridSelection.current === undefined)
1676
+ return;
1677
+ const [x, y] = direction;
1678
+ const [col, row] = gridSelection.current.cell;
1679
+ const old = gridSelection.current.range;
1680
+ let left = old.x;
1681
+ let right = old.x + old.width;
1682
+ let top = old.y;
1683
+ let bottom = old.y + old.height;
1684
+ const [minRow, maxRowRaw] = getSelectionRowLimits(row) ?? [0, rows - 1];
1685
+ const maxRow = maxRowRaw + 1; // we need an inclusive value
1686
+ // take care of vertical first in case new spans come in
1687
+ if (y !== 0) {
1688
+ switch (y) {
1689
+ case 2: {
1690
+ // go to end
1691
+ bottom = maxRow;
1692
+ top = row;
1693
+ scrollTo(0, bottom, "vertical");
1694
+ break;
1695
+ }
1696
+ case -2: {
1697
+ // go to start
1698
+ top = minRow;
1699
+ bottom = row + 1;
1700
+ scrollTo(0, top, "vertical");
1701
+ break;
1702
+ }
1703
+ case 1: {
1704
+ // motion down
1705
+ if (top < row) {
1706
+ top++;
1707
+ scrollTo(0, top, "vertical");
1708
+ }
1709
+ else {
1710
+ bottom = Math.min(maxRow, bottom + 1);
1711
+ scrollTo(0, bottom, "vertical");
1712
+ }
1713
+ break;
1714
+ }
1715
+ case -1: {
1716
+ // motion up
1717
+ if (bottom > row + 1) {
1718
+ bottom--;
1719
+ scrollTo(0, bottom, "vertical");
1720
+ }
1721
+ else {
1722
+ top = Math.max(minRow, top - 1);
1723
+ scrollTo(0, top, "vertical");
1724
+ }
1725
+ break;
1726
+ }
1727
+ default: {
1728
+ assertNever(y);
1729
+ }
1730
+ }
1731
+ }
1732
+ if (x !== 0) {
1733
+ if (x === 2) {
1734
+ right = mangledCols.length;
1735
+ left = col;
1736
+ scrollTo(right - 1 - rowMarkerOffset, 0, "horizontal");
1737
+ }
1738
+ else if (x === -2) {
1739
+ left = rowMarkerOffset;
1740
+ right = col + 1;
1741
+ scrollTo(left - rowMarkerOffset, 0, "horizontal");
1742
+ }
1743
+ else {
1744
+ let disallowed = [];
1745
+ if (getCellsForSelection !== undefined) {
1746
+ const cells = getCellsForSelection({
1747
+ x: left,
1748
+ y: top,
1749
+ width: right - left - rowMarkerOffset,
1750
+ height: bottom - top,
1751
+ }, abortControllerRef.current.signal);
1752
+ if (typeof cells === "object") {
1753
+ disallowed = getSpanStops(cells);
1754
+ }
1755
+ }
1756
+ if (x === 1) {
1757
+ // motion right
1758
+ let done = false;
1759
+ if (left < col) {
1760
+ if (disallowed.length > 0) {
1761
+ const target = range(left + 1, col + 1).find(n => !disallowed.includes(n - rowMarkerOffset));
1762
+ if (target !== undefined) {
1763
+ left = target;
1764
+ done = true;
1765
+ }
1766
+ }
1767
+ else {
1768
+ left++;
1769
+ done = true;
1770
+ }
1771
+ if (done)
1772
+ scrollTo(left, 0, "horizontal");
1773
+ }
1774
+ if (!done) {
1775
+ right = Math.min(mangledCols.length, right + 1);
1776
+ scrollTo(right - 1 - rowMarkerOffset, 0, "horizontal");
1777
+ }
1778
+ }
1779
+ else if (x === -1) {
1780
+ // motion left
1781
+ let done = false;
1782
+ if (right > col + 1) {
1783
+ if (disallowed.length > 0) {
1784
+ const target = range(right - 1, col, -1).find(n => !disallowed.includes(n - rowMarkerOffset));
1785
+ if (target !== undefined) {
1786
+ right = target;
1787
+ done = true;
1788
+ }
1789
+ }
1790
+ else {
1791
+ right--;
1792
+ done = true;
1793
+ }
1794
+ if (done)
1795
+ scrollTo(right - rowMarkerOffset, 0, "horizontal");
1796
+ }
1797
+ if (!done) {
1798
+ left = Math.max(rowMarkerOffset, left - 1);
1799
+ scrollTo(left - rowMarkerOffset, 0, "horizontal");
1800
+ }
1801
+ }
1802
+ else {
1803
+ assertNever(x);
1804
+ }
1805
+ }
1806
+ }
1807
+ setCurrent({
1808
+ cell: gridSelection.current.cell,
1809
+ range: {
1810
+ x: left,
1811
+ y: top,
1812
+ width: right - left,
1813
+ height: bottom - top,
1814
+ },
1815
+ }, true, false, "keyboard-select");
1816
+ }, [
1817
+ getCellsForSelection,
1818
+ getSelectionRowLimits,
1819
+ gridSelection,
1820
+ mangledCols.length,
1821
+ rowMarkerOffset,
1822
+ rows,
1823
+ scrollTo,
1824
+ setCurrent,
1825
+ ]);
1826
+ const scrollToActiveCellRef = React.useRef(scrollToActiveCell);
1827
+ scrollToActiveCellRef.current = scrollToActiveCell;
1828
+ const updateSelectedCell = React.useCallback((col, row, fromEditingTrailingRow, freeMove) => {
1829
+ const rowMax = mangledRows - (fromEditingTrailingRow ? 0 : 1);
1830
+ col = clamp(col, rowMarkerOffset, columns.length - 1 + rowMarkerOffset);
1831
+ row = clamp(row, 0, rowMax);
1832
+ const curCol = currentCell?.[0];
1833
+ const curRow = currentCell?.[1];
1834
+ if (col === curCol && row === curRow)
1835
+ return false;
1836
+ if (freeMove && gridSelection.current !== undefined) {
1837
+ const newStack = [...gridSelection.current.rangeStack];
1838
+ if (gridSelection.current.range.width > 1 || gridSelection.current.range.height > 1) {
1839
+ newStack.push(gridSelection.current.range);
1840
+ }
1841
+ setGridSelection({
1842
+ ...gridSelection,
1843
+ current: {
1844
+ cell: [col, row],
1845
+ range: { x: col, y: row, width: 1, height: 1 },
1846
+ rangeStack: newStack,
1847
+ },
1848
+ }, true);
1849
+ }
1850
+ else {
1851
+ setCurrent({
1852
+ cell: [col, row],
1853
+ range: { x: col, y: row, width: 1, height: 1 },
1854
+ }, true, false, "keyboard-nav");
1855
+ }
1856
+ if (lastSent.current !== undefined && lastSent.current[0] === col && lastSent.current[1] === row) {
1857
+ lastSent.current = undefined;
1858
+ }
1859
+ if (scrollToActiveCellRef.current) {
1860
+ scrollTo(col - rowMarkerOffset, row);
1861
+ }
1862
+ return true;
1863
+ }, [
1864
+ mangledRows,
1865
+ rowMarkerOffset,
1866
+ columns.length,
1867
+ currentCell,
1868
+ gridSelection,
1869
+ scrollTo,
1870
+ setGridSelection,
1871
+ setCurrent,
1872
+ ]);
1873
+ const onFinishEditing = React.useCallback((newValue, movement) => {
1874
+ if (overlay?.cell !== undefined && newValue !== undefined && isEditableGridCell(newValue)) {
1875
+ mangledOnCellsEdited([{ location: overlay.cell, value: newValue }]);
1876
+ window.requestAnimationFrame(() => {
1877
+ gridRef.current?.damage([
1878
+ {
1879
+ cell: overlay.cell,
1880
+ },
1881
+ ]);
1882
+ });
1883
+ }
1884
+ focus(true);
1885
+ setOverlay(undefined);
1886
+ const [movX, movY] = movement;
1887
+ if (gridSelection.current !== undefined && (movX !== 0 || movY !== 0)) {
1888
+ const isEditingLastRow = gridSelection.current.cell[1] === mangledRows - 1 && newValue !== undefined;
1889
+ const isEditingLastCol = gridSelection.current.cell[0] === mangledCols.length - 1 && newValue !== undefined;
1890
+ let updateSelected = true;
1891
+ if (isEditingLastRow && movY === 1 && onRowAppended !== undefined) {
1892
+ updateSelected = false;
1893
+ const col = gridSelection.current.cell[0] + movX;
1894
+ const customTargetColumn = getCustomNewRowTargetColumn(col);
1895
+ void appendRow(customTargetColumn ?? col, false);
1896
+ }
1897
+ if (isEditingLastCol && movX === 1 && onColumnAppended !== undefined) {
1898
+ updateSelected = false;
1899
+ const row = gridSelection.current.cell[1] + movY;
1900
+ void appendColumn(row, false);
1901
+ }
1902
+ if (updateSelected) {
1903
+ updateSelectedCell(clamp(gridSelection.current.cell[0] + movX, 0, mangledCols.length - 1), clamp(gridSelection.current.cell[1] + movY, 0, mangledRows - 1), isEditingLastRow, false);
1904
+ }
1905
+ }
1906
+ onFinishedEditing?.(newValue, movement);
1907
+ }, [
1908
+ overlay?.cell,
1909
+ focus,
1910
+ gridSelection,
1911
+ onFinishedEditing,
1912
+ mangledOnCellsEdited,
1913
+ mangledRows,
1914
+ updateSelectedCell,
1915
+ mangledCols.length,
1916
+ appendRow,
1917
+ appendColumn,
1918
+ onRowAppended,
1919
+ onColumnAppended,
1920
+ getCustomNewRowTargetColumn,
1921
+ ]);
1922
+ const overlayID = React.useMemo(() => {
1923
+ return `gdg-overlay-${idCounter++}`;
1924
+ }, []);
1925
+ const deleteRange = React.useCallback((r) => {
1926
+ focus();
1927
+ const editList = [];
1928
+ for (let x = r.x; x < r.x + r.width; x++) {
1929
+ for (let y = r.y; y < r.y + r.height; y++) {
1930
+ const cellValue = getCellContent([x - rowMarkerOffset, y]);
1931
+ if (!cellValue.allowOverlay && cellValue.kind !== GridCellKind.Boolean)
1932
+ continue;
1933
+ let newVal = undefined;
1934
+ if (cellValue.kind === GridCellKind.Custom) {
1935
+ const toDelete = getCellRenderer(cellValue);
1936
+ const editor = toDelete?.provideEditor?.({
1937
+ ...cellValue,
1938
+ location: [x - rowMarkerOffset, y],
1939
+ });
1940
+ if (toDelete?.onDelete !== undefined) {
1941
+ newVal = toDelete.onDelete(cellValue);
1942
+ }
1943
+ else if (isObjectEditorCallbackResult(editor)) {
1944
+ newVal = editor?.deletedValue?.(cellValue);
1945
+ }
1946
+ }
1947
+ else if ((isEditableGridCell(cellValue) && cellValue.allowOverlay) ||
1948
+ cellValue.kind === GridCellKind.Boolean) {
1949
+ const toDelete = getCellRenderer(cellValue);
1950
+ newVal = toDelete?.onDelete?.(cellValue);
1951
+ }
1952
+ if (newVal !== undefined && !isInnerOnlyCell(newVal) && isEditableGridCell(newVal)) {
1953
+ editList.push({ location: [x, y], value: newVal });
1954
+ }
1955
+ }
1956
+ }
1957
+ mangledOnCellsEdited(editList);
1958
+ gridRef.current?.damage(editList.map(x => ({ cell: x.location })));
1959
+ }, [focus, getCellContent, getCellRenderer, mangledOnCellsEdited, rowMarkerOffset]);
1960
+ const overlayOpen = overlay !== undefined;
1961
+ const handleFixedKeybindings = React.useCallback((event) => {
1962
+ const cancel = () => {
1963
+ event.stopPropagation();
1964
+ event.preventDefault();
1965
+ };
1966
+ const details = {
1967
+ didMatch: false,
1968
+ };
1969
+ const { bounds } = event;
1970
+ const selectedColumns = gridSelection.columns;
1971
+ const selectedRows = gridSelection.rows;
1972
+ const keys = keybindings;
1973
+ if (!overlayOpen && isHotkey(keys.clear, event, details)) {
1974
+ setGridSelection(emptyGridSelection, false);
1975
+ onSelectionCleared?.();
1976
+ }
1977
+ else if (!overlayOpen && isHotkey(keys.selectAll, event, details)) {
1978
+ setGridSelection({
1979
+ columns: CompactSelection.empty(),
1980
+ rows: CompactSelection.empty(),
1981
+ current: {
1982
+ cell: gridSelection.current?.cell ?? [rowMarkerOffset, 0],
1983
+ range: {
1984
+ x: rowMarkerOffset,
1985
+ y: 0,
1986
+ width: columnsIn.length,
1987
+ height: rows,
1988
+ },
1989
+ rangeStack: [],
1990
+ },
1991
+ }, false);
1992
+ }
1993
+ else if (isHotkey(keys.search, event, details)) {
1994
+ searchInputRef?.current?.focus({ preventScroll: true });
1995
+ setShowSearchInner(true);
1996
+ }
1997
+ else if (isHotkey(keys.delete, event, details)) {
1998
+ const callbackResult = onDelete?.(gridSelection) ?? true;
1999
+ if (callbackResult !== false) {
2000
+ const toDelete = callbackResult === true ? gridSelection : callbackResult;
2001
+ // delete order:
2002
+ // 1) primary range
2003
+ // 2) secondary ranges
2004
+ // 3) columns
2005
+ // 4) rows
2006
+ if (toDelete.current !== undefined) {
2007
+ deleteRange(toDelete.current.range);
2008
+ for (const r of toDelete.current.rangeStack) {
2009
+ deleteRange(r);
2010
+ }
2011
+ }
2012
+ for (const r of toDelete.rows) {
2013
+ deleteRange({
2014
+ x: rowMarkerOffset,
2015
+ y: r,
2016
+ width: columnsIn.length,
2017
+ height: 1,
2018
+ });
2019
+ }
2020
+ for (const col of toDelete.columns) {
2021
+ deleteRange({
2022
+ x: col,
2023
+ y: 0,
2024
+ width: 1,
2025
+ height: rows,
2026
+ });
2027
+ }
2028
+ }
2029
+ }
2030
+ if (details.didMatch) {
2031
+ cancel();
2032
+ return true;
2033
+ }
2034
+ if (gridSelection.current === undefined)
2035
+ return false;
2036
+ let [col, row] = gridSelection.current.cell;
2037
+ const [, startRow] = gridSelection.current.cell;
2038
+ let freeMove = false;
2039
+ let cancelOnlyOnMove = false;
2040
+ if (isHotkey(keys.scrollToSelectedCell, event, details)) {
2041
+ scrollToRef.current(col - rowMarkerOffset, row);
2042
+ }
2043
+ else if (columnSelect !== "none" && isHotkey(keys.selectColumn, event, details)) {
2044
+ if (selectedColumns.hasIndex(col)) {
2045
+ setSelectedColumns(selectedColumns.remove(col), undefined, true);
2046
+ }
2047
+ else {
2048
+ if (columnSelect === "single") {
2049
+ setSelectedColumns(CompactSelection.fromSingleSelection(col), undefined, true);
2050
+ }
2051
+ else {
2052
+ setSelectedColumns(undefined, col, true);
2053
+ }
2054
+ }
2055
+ }
2056
+ else if (rowSelect !== "none" && isHotkey(keys.selectRow, event, details)) {
2057
+ if (selectedRows.hasIndex(row)) {
2058
+ setSelectedRows(selectedRows.remove(row), undefined, true);
2059
+ }
2060
+ else {
2061
+ if (rowSelect === "single") {
2062
+ setSelectedRows(CompactSelection.fromSingleSelection(row), undefined, true);
2063
+ }
2064
+ else {
2065
+ setSelectedRows(undefined, row, true);
2066
+ }
2067
+ }
2068
+ }
2069
+ else if (!overlayOpen && bounds !== undefined && isHotkey(keys.activateCell, event, details)) {
2070
+ if (row === rows && showTrailingBlankRow) {
2071
+ window.setTimeout(() => {
2072
+ const customTargetColumn = getCustomNewRowTargetColumn(col);
2073
+ void appendRow(customTargetColumn ?? col);
2074
+ }, 0);
2075
+ }
2076
+ else {
2077
+ const activationEvent = {
2078
+ inputType: "keyboard",
2079
+ key: event.key,
2080
+ };
2081
+ onCellActivated?.([col - rowMarkerOffset, row], activationEvent);
2082
+ reselect(bounds, activationEvent);
2083
+ }
2084
+ }
2085
+ else if (gridSelection.current.range.height > 1 && isHotkey(keys.downFill, event, details)) {
2086
+ fillDown();
2087
+ }
2088
+ else if (gridSelection.current.range.width > 1 && isHotkey(keys.rightFill, event, details)) {
2089
+ fillRight();
2090
+ }
2091
+ else if (isHotkey(keys.goToNextPage, event, details)) {
2092
+ row += Math.max(1, visibleRegionRef.current.height - 4); // partial cell accounting
2093
+ }
2094
+ else if (isHotkey(keys.goToPreviousPage, event, details)) {
2095
+ row -= Math.max(1, visibleRegionRef.current.height - 4); // partial cell accounting
2096
+ }
2097
+ else if (isHotkey(keys.goToFirstCell, event, details)) {
2098
+ setOverlay(undefined);
2099
+ row = 0;
2100
+ col = 0;
2101
+ }
2102
+ else if (isHotkey(keys.goToLastCell, event, details)) {
2103
+ setOverlay(undefined);
2104
+ row = Number.MAX_SAFE_INTEGER;
2105
+ col = Number.MAX_SAFE_INTEGER;
2106
+ }
2107
+ else if (isHotkey(keys.selectToFirstCell, event, details)) {
2108
+ setOverlay(undefined);
2109
+ adjustSelection([-2, -2]);
2110
+ }
2111
+ else if (isHotkey(keys.selectToLastCell, event, details)) {
2112
+ setOverlay(undefined);
2113
+ adjustSelection([2, 2]);
2114
+ }
2115
+ else if (!overlayOpen) {
2116
+ if (isHotkey(keys.goDownCell, event, details)) {
2117
+ row += 1;
2118
+ }
2119
+ else if (isHotkey(keys.goUpCell, event, details)) {
2120
+ row -= 1;
2121
+ }
2122
+ else if (isHotkey(keys.goRightCell, event, details)) {
2123
+ col += 1;
2124
+ }
2125
+ else if (isHotkey(keys.goLeftCell, event, details)) {
2126
+ col -= 1;
2127
+ }
2128
+ else if (isHotkey(keys.goDownCellRetainSelection, event, details)) {
2129
+ row += 1;
2130
+ freeMove = true;
2131
+ }
2132
+ else if (isHotkey(keys.goUpCellRetainSelection, event, details)) {
2133
+ row -= 1;
2134
+ freeMove = true;
2135
+ }
2136
+ else if (isHotkey(keys.goRightCellRetainSelection, event, details)) {
2137
+ col += 1;
2138
+ freeMove = true;
2139
+ }
2140
+ else if (isHotkey(keys.goLeftCellRetainSelection, event, details)) {
2141
+ col -= 1;
2142
+ freeMove = true;
2143
+ }
2144
+ else if (isHotkey(keys.goToLastRow, event, details)) {
2145
+ row = rows - 1;
2146
+ }
2147
+ else if (isHotkey(keys.goToFirstRow, event, details)) {
2148
+ row = Number.MIN_SAFE_INTEGER;
2149
+ }
2150
+ else if (isHotkey(keys.goToLastColumn, event, details)) {
2151
+ col = Number.MAX_SAFE_INTEGER;
2152
+ }
2153
+ else if (isHotkey(keys.goToFirstColumn, event, details)) {
2154
+ col = Number.MIN_SAFE_INTEGER;
2155
+ }
2156
+ else if (rangeSelect === "rect" || rangeSelect === "multi-rect") {
2157
+ if (isHotkey(keys.selectGrowDown, event, details)) {
2158
+ adjustSelection([0, 1]);
2159
+ }
2160
+ else if (isHotkey(keys.selectGrowUp, event, details)) {
2161
+ adjustSelection([0, -1]);
2162
+ }
2163
+ else if (isHotkey(keys.selectGrowRight, event, details)) {
2164
+ adjustSelection([1, 0]);
2165
+ }
2166
+ else if (isHotkey(keys.selectGrowLeft, event, details)) {
2167
+ adjustSelection([-1, 0]);
2168
+ }
2169
+ else if (isHotkey(keys.selectToLastRow, event, details)) {
2170
+ adjustSelection([0, 2]);
2171
+ }
2172
+ else if (isHotkey(keys.selectToFirstRow, event, details)) {
2173
+ adjustSelection([0, -2]);
2174
+ }
2175
+ else if (isHotkey(keys.selectToLastColumn, event, details)) {
2176
+ adjustSelection([2, 0]);
2177
+ }
2178
+ else if (isHotkey(keys.selectToFirstColumn, event, details)) {
2179
+ adjustSelection([-2, 0]);
2180
+ }
2181
+ }
2182
+ cancelOnlyOnMove = details.didMatch;
2183
+ }
2184
+ else {
2185
+ if (isHotkey(keys.closeOverlay, event, details)) {
2186
+ setOverlay(undefined);
2187
+ }
2188
+ if (isHotkey(keys.acceptOverlayDown, event, details)) {
2189
+ setOverlay(undefined);
2190
+ row++;
2191
+ }
2192
+ if (isHotkey(keys.acceptOverlayUp, event, details)) {
2193
+ setOverlay(undefined);
2194
+ row--;
2195
+ }
2196
+ if (isHotkey(keys.acceptOverlayLeft, event, details)) {
2197
+ setOverlay(undefined);
2198
+ col--;
2199
+ }
2200
+ if (isHotkey(keys.acceptOverlayRight, event, details)) {
2201
+ setOverlay(undefined);
2202
+ col++;
2203
+ }
2204
+ }
2205
+ // #endregion
2206
+ const mustRestrictRow = rowGroupingNavBehavior !== undefined && rowGroupingNavBehavior !== "normal";
2207
+ if (mustRestrictRow && row !== startRow) {
2208
+ const skipUp = rowGroupingNavBehavior === "skip-up" ||
2209
+ rowGroupingNavBehavior === "skip" ||
2210
+ rowGroupingNavBehavior === "block";
2211
+ const skipDown = rowGroupingNavBehavior === "skip-down" ||
2212
+ rowGroupingNavBehavior === "skip" ||
2213
+ rowGroupingNavBehavior === "block";
2214
+ const didMoveUp = row < startRow;
2215
+ if (didMoveUp && skipUp) {
2216
+ while (row >= 0 && mapper(row).isGroupHeader) {
2217
+ row--;
2218
+ }
2219
+ if (row < 0) {
2220
+ row = startRow;
2221
+ }
2222
+ }
2223
+ else if (!didMoveUp && skipDown) {
2224
+ while (row < rows && mapper(row).isGroupHeader) {
2225
+ row++;
2226
+ }
2227
+ if (row >= rows) {
2228
+ row = startRow;
2229
+ }
2230
+ }
2231
+ }
2232
+ const moved = updateSelectedCell(col, row, false, freeMove);
2233
+ const didMatch = details.didMatch;
2234
+ if (didMatch && (moved || !cancelOnlyOnMove || trapFocus)) {
2235
+ cancel();
2236
+ }
2237
+ return didMatch;
2238
+ }, [
2239
+ rowGroupingNavBehavior,
2240
+ overlayOpen,
2241
+ gridSelection,
2242
+ keybindings,
2243
+ columnSelect,
2244
+ rowSelect,
2245
+ rangeSelect,
2246
+ rowMarkerOffset,
2247
+ mapper,
2248
+ rows,
2249
+ updateSelectedCell,
2250
+ setGridSelection,
2251
+ onSelectionCleared,
2252
+ columnsIn.length,
2253
+ onDelete,
2254
+ trapFocus,
2255
+ deleteRange,
2256
+ setSelectedColumns,
2257
+ setSelectedRows,
2258
+ showTrailingBlankRow,
2259
+ getCustomNewRowTargetColumn,
2260
+ appendRow,
2261
+ onCellActivated,
2262
+ reselect,
2263
+ fillDown,
2264
+ fillRight,
2265
+ adjustSelection,
2266
+ ]);
2267
+ const onKeyDown = React.useCallback((event) => {
2268
+ let cancelled = false;
2269
+ if (onKeyDownIn !== undefined) {
2270
+ onKeyDownIn({
2271
+ ...event,
2272
+ ...(event.location && {
2273
+ location: [event.location[0] - rowMarkerOffset, event.location[1]],
2274
+ }),
2275
+ cancel: () => {
2276
+ cancelled = true;
2277
+ },
2278
+ });
2279
+ }
2280
+ if (cancelled)
2281
+ return;
2282
+ if (handleFixedKeybindings(event))
2283
+ return;
2284
+ if (gridSelection.current === undefined)
2285
+ return;
2286
+ const [col, row] = gridSelection.current.cell;
2287
+ const vr = visibleRegionRef.current;
2288
+ if (editOnType &&
2289
+ !event.metaKey &&
2290
+ !event.ctrlKey &&
2291
+ gridSelection.current !== undefined &&
2292
+ event.key.length === 1 &&
2293
+ /[\p{L}\p{M}\p{N}\p{S}\p{P}]/u.test(event.key) &&
2294
+ event.bounds !== undefined &&
2295
+ isReadWriteCell(getCellContent([col - rowMarkerOffset, Math.max(0, Math.min(row, rows - 1))]))) {
2296
+ if ((!showTrailingBlankRow || row !== rows) &&
2297
+ (vr.y > row || row > vr.y + vr.height || vr.x > col || col > vr.x + vr.width)) {
2298
+ return;
2299
+ }
2300
+ const activationEvent = {
2301
+ inputType: "keyboard",
2302
+ key: event.key,
2303
+ };
2304
+ onCellActivated?.([col - rowMarkerOffset, row], activationEvent);
2305
+ reselect(event.bounds, activationEvent, event.key);
2306
+ event.stopPropagation();
2307
+ event.preventDefault();
2308
+ }
2309
+ }, [
2310
+ editOnType,
2311
+ onKeyDownIn,
2312
+ handleFixedKeybindings,
2313
+ gridSelection,
2314
+ getCellContent,
2315
+ rowMarkerOffset,
2316
+ rows,
2317
+ showTrailingBlankRow,
2318
+ onCellActivated,
2319
+ reselect,
2320
+ ]);
2321
+ const onContextMenu = React.useCallback((args, preventDefault) => {
2322
+ const adjustedCol = args.location[0] - rowMarkerOffset;
2323
+ if (args.kind === "header") {
2324
+ onHeaderContextMenu?.(adjustedCol, { ...args, preventDefault });
2325
+ }
2326
+ if (args.kind === groupHeaderKind) {
2327
+ if (adjustedCol < 0) {
2328
+ return;
2329
+ }
2330
+ onGroupHeaderContextMenu?.(adjustedCol, { ...args, preventDefault });
2331
+ }
2332
+ if (args.kind === "cell") {
2333
+ const [col, row] = args.location;
2334
+ onCellContextMenu?.([adjustedCol, row], {
2335
+ ...args,
2336
+ preventDefault,
2337
+ });
2338
+ if (!gridSelectionHasItem(gridSelection, args.location)) {
2339
+ updateSelectedCell(col, row, false, false);
2340
+ }
2341
+ }
2342
+ }, [
2343
+ gridSelection,
2344
+ onCellContextMenu,
2345
+ onGroupHeaderContextMenu,
2346
+ onHeaderContextMenu,
2347
+ rowMarkerOffset,
2348
+ updateSelectedCell,
2349
+ ]);
2350
+ const onPasteInternal = React.useCallback(async (e) => {
2351
+ if (!keybindings.paste)
2352
+ return;
2353
+ function pasteToCell(inner, target, rawValue, formatted) {
2354
+ const stringifiedRawValue = typeof rawValue === "object" ? (rawValue?.join("\n") ?? "") : (rawValue?.toString() ?? "");
2355
+ if (!isInnerOnlyCell(inner) && isReadWriteCell(inner) && inner.readonly !== true) {
2356
+ const coerced = coercePasteValue?.(stringifiedRawValue, inner);
2357
+ if (coerced !== undefined && isEditableGridCell(coerced)) {
2358
+ if (process.env.NODE_ENV !== "production" && coerced.kind !== inner.kind) {
2359
+ // eslint-disable-next-line no-console
2360
+ console.warn("Coercion should not change cell kind.");
2361
+ }
2362
+ return {
2363
+ location: target,
2364
+ value: coerced,
2365
+ };
2366
+ }
2367
+ const r = getCellRenderer(inner);
2368
+ if (r === undefined)
2369
+ return undefined;
2370
+ if (r.kind === GridCellKind.Custom) {
2371
+ assert(inner.kind === GridCellKind.Custom);
2372
+ const newVal = r.onPaste?.(stringifiedRawValue, inner.data);
2373
+ if (newVal === undefined)
2374
+ return undefined;
2375
+ return {
2376
+ location: target,
2377
+ value: {
2378
+ ...inner,
2379
+ data: newVal,
2380
+ },
2381
+ };
2382
+ }
2383
+ else {
2384
+ const newVal = r.onPaste?.(stringifiedRawValue, inner, {
2385
+ formatted,
2386
+ formattedString: typeof formatted === "string" ? formatted : formatted?.join("\n"),
2387
+ rawValue,
2388
+ });
2389
+ if (newVal === undefined)
2390
+ return undefined;
2391
+ assert(newVal.kind === inner.kind);
2392
+ return {
2393
+ location: target,
2394
+ value: newVal,
2395
+ };
2396
+ }
2397
+ }
2398
+ return undefined;
2399
+ }
2400
+ const selectedColumns = gridSelection.columns;
2401
+ const selectedRows = gridSelection.rows;
2402
+ const focused = scrollRef.current?.contains(document.activeElement) === true ||
2403
+ canvasRef.current?.contains(document.activeElement) === true;
2404
+ let target;
2405
+ if (gridSelection.current !== undefined) {
2406
+ target = [gridSelection.current.range.x, gridSelection.current.range.y];
2407
+ }
2408
+ else if (selectedColumns.length === 1) {
2409
+ target = [selectedColumns.first() ?? 0, 0];
2410
+ }
2411
+ else if (selectedRows.length === 1) {
2412
+ target = [rowMarkerOffset, selectedRows.first() ?? 0];
2413
+ }
2414
+ if (focused && target !== undefined) {
2415
+ let data;
2416
+ let text;
2417
+ const textPlain = "text/plain";
2418
+ const textHtml = "text/html";
2419
+ if (navigator.clipboard.read !== undefined) {
2420
+ const clipboardContent = await navigator.clipboard.read();
2421
+ for (const item of clipboardContent) {
2422
+ if (item.types.includes(textHtml)) {
2423
+ const htmlBlob = await item.getType(textHtml);
2424
+ const html = await htmlBlob.text();
2425
+ const decoded = decodeHTML(html);
2426
+ if (decoded !== undefined) {
2427
+ data = decoded;
2428
+ break;
2429
+ }
2430
+ }
2431
+ if (item.types.includes(textPlain)) {
2432
+ // eslint-disable-next-line unicorn/no-await-expression-member
2433
+ text = await (await item.getType(textPlain)).text();
2434
+ }
2435
+ }
2436
+ }
2437
+ else if (navigator.clipboard.readText !== undefined) {
2438
+ text = await navigator.clipboard.readText();
2439
+ }
2440
+ else if (e !== undefined && e?.clipboardData !== null) {
2441
+ if (e.clipboardData.types.includes(textHtml)) {
2442
+ const html = e.clipboardData.getData(textHtml);
2443
+ data = decodeHTML(html);
2444
+ }
2445
+ if (data === undefined && e.clipboardData.types.includes(textPlain)) {
2446
+ text = e.clipboardData.getData(textPlain);
2447
+ }
2448
+ }
2449
+ else {
2450
+ return; // I didn't want to read that paste value anyway
2451
+ }
2452
+ const [targetCol, targetRow] = target;
2453
+ const editList = [];
2454
+ do {
2455
+ if (onPaste === undefined) {
2456
+ const cellData = getMangledCellContent(target);
2457
+ const rawValue = text ?? data?.map(r => r.map(cb => cb.rawValue).join("\t")).join("\t") ?? "";
2458
+ const newVal = pasteToCell(cellData, target, rawValue, undefined);
2459
+ if (newVal !== undefined) {
2460
+ editList.push(newVal);
2461
+ }
2462
+ break;
2463
+ }
2464
+ if (data === undefined) {
2465
+ if (text === undefined)
2466
+ return;
2467
+ data = unquote(text);
2468
+ }
2469
+ if (onPaste === false ||
2470
+ (typeof onPaste === "function" &&
2471
+ onPaste?.([target[0] - rowMarkerOffset, target[1]], data.map(r => r.map(cb => cb.rawValue?.toString() ?? ""))) !== true)) {
2472
+ return;
2473
+ }
2474
+ for (const [row, dataRow] of data.entries()) {
2475
+ if (row + targetRow >= rows)
2476
+ break;
2477
+ for (const [col, dataItem] of dataRow.entries()) {
2478
+ const index = [col + targetCol, row + targetRow];
2479
+ const [writeCol, writeRow] = index;
2480
+ if (writeCol >= mangledCols.length)
2481
+ continue;
2482
+ if (writeRow >= mangledRows)
2483
+ continue;
2484
+ const cellData = getMangledCellContent(index);
2485
+ const newVal = pasteToCell(cellData, index, dataItem.rawValue, dataItem.formatted);
2486
+ if (newVal !== undefined) {
2487
+ editList.push(newVal);
2488
+ }
2489
+ }
2490
+ }
2491
+ // eslint-disable-next-line no-constant-condition
2492
+ } while (false);
2493
+ mangledOnCellsEdited(editList);
2494
+ gridRef.current?.damage(editList.map(c => ({
2495
+ cell: c.location,
2496
+ })));
2497
+ }
2498
+ }, [
2499
+ coercePasteValue,
2500
+ getCellRenderer,
2501
+ getMangledCellContent,
2502
+ gridSelection,
2503
+ keybindings.paste,
2504
+ scrollRef,
2505
+ mangledCols.length,
2506
+ mangledOnCellsEdited,
2507
+ mangledRows,
2508
+ onPaste,
2509
+ rowMarkerOffset,
2510
+ rows,
2511
+ ]);
2512
+ useEventListener("paste", onPasteInternal, safeWindow, false, true);
2513
+ // While this function is async, we deeply prefer not to await if we don't have to. This will lead to unpacking
2514
+ // promises in rather awkward ways when possible to avoid awaiting. We have to use fallback copy mechanisms when
2515
+ // an await has happened.
2516
+ const onCopy = React.useCallback(async (e, ignoreFocus) => {
2517
+ if (!keybindings.copy)
2518
+ return;
2519
+ const focused = ignoreFocus === true ||
2520
+ scrollRef.current?.contains(document.activeElement) === true ||
2521
+ canvasRef.current?.contains(document.activeElement) === true;
2522
+ const selectedColumns = gridSelection.columns;
2523
+ const selectedRows = gridSelection.rows;
2524
+ const copyToClipboardWithHeaders = (cells, columnIndexes) => {
2525
+ if (!copyHeaders) {
2526
+ copyToClipboard(cells, columnIndexes, e);
2527
+ }
2528
+ else {
2529
+ const headers = columnIndexes.map(index => ({
2530
+ kind: GridCellKind.Text,
2531
+ data: columnsIn[index].title,
2532
+ displayData: columnsIn[index].title,
2533
+ allowOverlay: false,
2534
+ }));
2535
+ copyToClipboard([headers, ...cells], columnIndexes, e);
2536
+ }
2537
+ };
2538
+ if (focused && getCellsForSelection !== undefined) {
2539
+ if (gridSelection.current !== undefined) {
2540
+ let thunk = getCellsForSelection(gridSelection.current.range, abortControllerRef.current.signal);
2541
+ if (typeof thunk !== "object") {
2542
+ thunk = await thunk();
2543
+ }
2544
+ copyToClipboardWithHeaders(thunk, range(gridSelection.current.range.x - rowMarkerOffset, gridSelection.current.range.x + gridSelection.current.range.width - rowMarkerOffset));
2545
+ }
2546
+ else if (selectedRows !== undefined && selectedRows.length > 0) {
2547
+ const toCopy = [...selectedRows];
2548
+ const cells = toCopy.map(rowIndex => {
2549
+ const thunk = getCellsForSelection({
2550
+ x: rowMarkerOffset,
2551
+ y: rowIndex,
2552
+ width: columnsIn.length,
2553
+ height: 1,
2554
+ }, abortControllerRef.current.signal);
2555
+ if (typeof thunk === "object") {
2556
+ return thunk[0];
2557
+ }
2558
+ return thunk().then(v => v[0]);
2559
+ });
2560
+ if (cells.some(x => x instanceof Promise)) {
2561
+ const settled = await Promise.all(cells);
2562
+ copyToClipboardWithHeaders(settled, range(columnsIn.length));
2563
+ }
2564
+ else {
2565
+ copyToClipboardWithHeaders(cells, range(columnsIn.length));
2566
+ }
2567
+ }
2568
+ else if (selectedColumns.length > 0) {
2569
+ const results = [];
2570
+ const cols = [];
2571
+ for (const col of selectedColumns) {
2572
+ let thunk = getCellsForSelection({
2573
+ x: col,
2574
+ y: 0,
2575
+ width: 1,
2576
+ height: rows,
2577
+ }, abortControllerRef.current.signal);
2578
+ if (typeof thunk !== "object") {
2579
+ thunk = await thunk();
2580
+ }
2581
+ results.push(thunk);
2582
+ cols.push(col - rowMarkerOffset);
2583
+ }
2584
+ if (results.length === 1) {
2585
+ copyToClipboardWithHeaders(results[0], cols);
2586
+ }
2587
+ else {
2588
+ // FIXME: this is dumb
2589
+ const toCopy = results.reduce((pv, cv) => pv.map((row, index) => [...row, ...cv[index]]));
2590
+ copyToClipboardWithHeaders(toCopy, cols);
2591
+ }
2592
+ }
2593
+ }
2594
+ }, [
2595
+ columnsIn,
2596
+ getCellsForSelection,
2597
+ gridSelection,
2598
+ keybindings.copy,
2599
+ rowMarkerOffset,
2600
+ scrollRef,
2601
+ rows,
2602
+ copyHeaders,
2603
+ ]);
2604
+ useEventListener("copy", onCopy, safeWindow, false, false);
2605
+ const onCut = React.useCallback(async (e) => {
2606
+ if (!keybindings.cut)
2607
+ return;
2608
+ const focused = scrollRef.current?.contains(document.activeElement) === true ||
2609
+ canvasRef.current?.contains(document.activeElement) === true;
2610
+ if (!focused)
2611
+ return;
2612
+ await onCopy(e);
2613
+ if (gridSelection.current !== undefined) {
2614
+ let effectiveSelection = {
2615
+ current: {
2616
+ cell: gridSelection.current.cell,
2617
+ range: gridSelection.current.range,
2618
+ rangeStack: [],
2619
+ },
2620
+ rows: CompactSelection.empty(),
2621
+ columns: CompactSelection.empty(),
2622
+ };
2623
+ const onDeleteResult = onDelete?.(effectiveSelection);
2624
+ if (onDeleteResult === false)
2625
+ return;
2626
+ effectiveSelection = onDeleteResult === true ? effectiveSelection : onDeleteResult;
2627
+ if (effectiveSelection.current === undefined)
2628
+ return;
2629
+ deleteRange(effectiveSelection.current.range);
2630
+ }
2631
+ }, [deleteRange, gridSelection, keybindings.cut, onCopy, scrollRef, onDelete]);
2632
+ useEventListener("cut", onCut, safeWindow, false, false);
2633
+ const onSearchResultsChanged = React.useCallback((results, navIndex) => {
2634
+ if (onSearchResultsChangedIn !== undefined) {
2635
+ if (rowMarkerOffset !== 0) {
2636
+ results = results.map(item => [item[0] - rowMarkerOffset, item[1]]);
2637
+ }
2638
+ onSearchResultsChangedIn(results, navIndex);
2639
+ return;
2640
+ }
2641
+ if (results.length === 0 || navIndex === -1)
2642
+ return;
2643
+ const [col, row] = results[navIndex];
2644
+ if (lastSent.current !== undefined && lastSent.current[0] === col && lastSent.current[1] === row) {
2645
+ return;
2646
+ }
2647
+ lastSent.current = [col, row];
2648
+ updateSelectedCell(col, row, false, false);
2649
+ }, [onSearchResultsChangedIn, rowMarkerOffset, updateSelectedCell]);
2650
+ // this effects purpose in life is to scroll the newly selected cell into view when and ONLY when that cell
2651
+ // is from an external gridSelection change. Also note we want the unmangled out selection because scrollTo
2652
+ // expects unmangled indexes
2653
+ const [outCol, outRow] = gridSelectionOuter?.current?.cell ?? [];
2654
+ const scrollToRef = React.useRef(scrollTo);
2655
+ scrollToRef.current = scrollTo;
2656
+ React.useLayoutEffect(() => {
2657
+ if (scrollToActiveCellRef.current &&
2658
+ !hasJustScrolled.current &&
2659
+ outCol !== undefined &&
2660
+ outRow !== undefined &&
2661
+ (outCol !== expectedExternalGridSelection.current?.current?.cell[0] ||
2662
+ outRow !== expectedExternalGridSelection.current?.current?.cell[1])) {
2663
+ scrollToRef.current(outCol, outRow);
2664
+ }
2665
+ hasJustScrolled.current = false; //only allow skipping a single scroll
2666
+ }, [outCol, outRow]);
2667
+ const selectionOutOfBounds = gridSelection.current !== undefined &&
2668
+ (gridSelection.current.cell[0] >= mangledCols.length || gridSelection.current.cell[1] >= mangledRows);
2669
+ React.useLayoutEffect(() => {
2670
+ if (selectionOutOfBounds) {
2671
+ setGridSelection(emptyGridSelection, false);
2672
+ }
2673
+ }, [selectionOutOfBounds, setGridSelection]);
2674
+ const disabledRows = React.useMemo(() => {
2675
+ if (showTrailingBlankRow === true && trailingRowOptions?.tint === true) {
2676
+ return CompactSelection.fromSingleSelection(mangledRows - 1);
2677
+ }
2678
+ return CompactSelection.empty();
2679
+ }, [mangledRows, showTrailingBlankRow, trailingRowOptions?.tint]);
2680
+ const mangledVerticalBorder = React.useCallback((col) => {
2681
+ return typeof verticalBorder === "boolean"
2682
+ ? verticalBorder
2683
+ : (verticalBorder?.(col - rowMarkerOffset) ?? true);
2684
+ }, [rowMarkerOffset, verticalBorder]);
2685
+ const renameGroupNode = React.useMemo(() => {
2686
+ if (renameGroup === undefined || canvasRef.current === null)
2687
+ return null;
2688
+ const { bounds, group } = renameGroup;
2689
+ const canvasBounds = canvasRef.current.getBoundingClientRect();
2690
+ return (React.createElement(GroupRename, { bounds: bounds, group: group, canvasBounds: canvasBounds, onClose: () => setRenameGroup(undefined), onFinish: (newVal) => {
2691
+ setRenameGroup(undefined);
2692
+ onGroupHeaderRenamed?.(group, newVal);
2693
+ } }));
2694
+ }, [onGroupHeaderRenamed, renameGroup]);
2695
+ const mangledFreezeColumns = Math.min(mangledCols.length, freezeColumns + (hasRowMarkers ? 1 : 0));
2696
+ React.useImperativeHandle(forwardedRef, () => ({
2697
+ appendRow: (col, openOverlay) => appendRow(col + rowMarkerOffset, openOverlay),
2698
+ appendColumn: (row, openOverlay) => appendColumn(row, openOverlay),
2699
+ updateCells: damageList => {
2700
+ if (rowMarkerOffset !== 0) {
2701
+ damageList = damageList.map(x => ({ cell: [x.cell[0] + rowMarkerOffset, x.cell[1]] }));
2702
+ }
2703
+ return gridRef.current?.damage(damageList);
2704
+ },
2705
+ getBounds: (col, row) => {
2706
+ if (canvasRef?.current === null || scrollRef?.current === null) {
2707
+ return undefined;
2708
+ }
2709
+ if (col === undefined && row === undefined) {
2710
+ // Return the bounds of the entire scroll area:
2711
+ const rect = canvasRef.current.getBoundingClientRect();
2712
+ const scale = rect.width / scrollRef.current.clientWidth;
2713
+ return {
2714
+ x: rect.x - scrollRef.current.scrollLeft * scale,
2715
+ y: rect.y - scrollRef.current.scrollTop * scale,
2716
+ width: scrollRef.current.scrollWidth * scale,
2717
+ height: scrollRef.current.scrollHeight * scale,
2718
+ };
2719
+ }
2720
+ return gridRef.current?.getBounds((col ?? 0) + rowMarkerOffset, row);
2721
+ },
2722
+ focus: () => gridRef.current?.focus(),
2723
+ emit: async (e) => {
2724
+ switch (e) {
2725
+ case "delete":
2726
+ onKeyDown({
2727
+ bounds: undefined,
2728
+ cancel: () => undefined,
2729
+ stopPropagation: () => undefined,
2730
+ preventDefault: () => undefined,
2731
+ ctrlKey: false,
2732
+ key: "Delete",
2733
+ keyCode: 46,
2734
+ metaKey: false,
2735
+ shiftKey: false,
2736
+ altKey: false,
2737
+ rawEvent: undefined,
2738
+ location: undefined,
2739
+ });
2740
+ break;
2741
+ case "fill-right":
2742
+ onKeyDown({
2743
+ bounds: undefined,
2744
+ cancel: () => undefined,
2745
+ stopPropagation: () => undefined,
2746
+ preventDefault: () => undefined,
2747
+ ctrlKey: true,
2748
+ key: "r",
2749
+ keyCode: 82,
2750
+ metaKey: false,
2751
+ shiftKey: false,
2752
+ altKey: false,
2753
+ rawEvent: undefined,
2754
+ location: undefined,
2755
+ });
2756
+ break;
2757
+ case "fill-down":
2758
+ onKeyDown({
2759
+ bounds: undefined,
2760
+ cancel: () => undefined,
2761
+ stopPropagation: () => undefined,
2762
+ preventDefault: () => undefined,
2763
+ ctrlKey: true,
2764
+ key: "d",
2765
+ keyCode: 68,
2766
+ metaKey: false,
2767
+ shiftKey: false,
2768
+ altKey: false,
2769
+ rawEvent: undefined,
2770
+ location: undefined,
2771
+ });
2772
+ break;
2773
+ case "copy":
2774
+ await onCopy(undefined, true);
2775
+ break;
2776
+ case "paste":
2777
+ await onPasteInternal();
2778
+ break;
2779
+ }
2780
+ },
2781
+ scrollTo,
2782
+ remeasureColumns: cols => {
2783
+ for (const col of cols) {
2784
+ void normalSizeColumn(col + rowMarkerOffset);
2785
+ }
2786
+ },
2787
+ getMouseArgsForPosition: (posX, posY, ev) => {
2788
+ if (gridRef?.current === null) {
2789
+ return undefined;
2790
+ }
2791
+ const args = gridRef.current.getMouseArgsForPosition(posX, posY, ev);
2792
+ if (args === undefined) {
2793
+ return undefined;
2794
+ }
2795
+ return {
2796
+ ...args,
2797
+ location: [args.location[0] - rowMarkerOffset, args.location[1]],
2798
+ };
2799
+ },
2800
+ }), [
2801
+ appendRow,
2802
+ appendColumn,
2803
+ normalSizeColumn,
2804
+ scrollRef,
2805
+ onCopy,
2806
+ onKeyDown,
2807
+ onPasteInternal,
2808
+ rowMarkerOffset,
2809
+ scrollTo,
2810
+ ]);
2811
+ const [selCol, selRow] = currentCell ?? [];
2812
+ const onCellFocused = React.useCallback((cell) => {
2813
+ const [col, row] = cell;
2814
+ if (row === -1) {
2815
+ if (columnSelect !== "none") {
2816
+ setSelectedColumns(CompactSelection.fromSingleSelection(col), undefined, false);
2817
+ focus();
2818
+ }
2819
+ return;
2820
+ }
2821
+ if (selCol === col && selRow === row)
2822
+ return;
2823
+ setCurrent({
2824
+ cell,
2825
+ range: { x: col, y: row, width: 1, height: 1 },
2826
+ }, true, false, "keyboard-nav");
2827
+ scrollTo(col, row);
2828
+ }, [columnSelect, focus, scrollTo, selCol, selRow, setCurrent, setSelectedColumns]);
2829
+ const [isFocused, setIsFocused] = React.useState(false);
2830
+ const setIsFocusedDebounced = React.useRef(debounce((val) => {
2831
+ setIsFocused(val);
2832
+ }, 5));
2833
+ const onCanvasFocused = React.useCallback(() => {
2834
+ setIsFocusedDebounced.current(true);
2835
+ // check for mouse state, don't do anything if the user is clicked to focus.
2836
+ if (gridSelection.current === undefined &&
2837
+ gridSelection.columns.length === 0 &&
2838
+ gridSelection.rows.length === 0 &&
2839
+ mouseState === undefined) {
2840
+ setCurrent({
2841
+ cell: [rowMarkerOffset, cellYOffset],
2842
+ range: {
2843
+ x: rowMarkerOffset,
2844
+ y: cellYOffset,
2845
+ width: 1,
2846
+ height: 1,
2847
+ },
2848
+ }, true, false, "keyboard-select");
2849
+ }
2850
+ }, [cellYOffset, gridSelection, mouseState, rowMarkerOffset, setCurrent]);
2851
+ const onFocusOut = React.useCallback(() => {
2852
+ setIsFocusedDebounced.current(false);
2853
+ }, []);
2854
+ const [idealWidth, idealHeight] = React.useMemo(() => {
2855
+ let h;
2856
+ const scrollbarWidth = experimental?.scrollbarWidthOverride ?? getScrollBarWidth();
2857
+ const rowsCountWithTrailingRow = rows + (showTrailingBlankRow ? 1 : 0);
2858
+ if (typeof rowHeight === "number") {
2859
+ h = totalHeaderHeight + rowsCountWithTrailingRow * rowHeight;
2860
+ }
2861
+ else {
2862
+ let avg = 0;
2863
+ const toAverage = Math.min(rowsCountWithTrailingRow, 10);
2864
+ for (let i = 0; i < toAverage; i++) {
2865
+ avg += rowHeight(i);
2866
+ }
2867
+ avg = Math.floor(avg / toAverage);
2868
+ h = totalHeaderHeight + rowsCountWithTrailingRow * avg;
2869
+ }
2870
+ h += scrollbarWidth;
2871
+ const w = mangledCols.reduce((acc, x) => x.width + acc, 0) + scrollbarWidth;
2872
+ // We need to set a reasonable cap here as some browsers will just ignore huge values
2873
+ // rather than treat them as huge values.
2874
+ return [`${Math.min(100_000, w)}px`, `${Math.min(100_000, h)}px`];
2875
+ }, [mangledCols, experimental?.scrollbarWidthOverride, rowHeight, rows, showTrailingBlankRow, totalHeaderHeight]);
2876
+ const cssStyle = React.useMemo(() => {
2877
+ return makeCSSStyle(mergedTheme);
2878
+ }, [mergedTheme]);
2879
+ return (React.createElement(ThemeContext.Provider, { value: mergedTheme },
2880
+ React.createElement(DataEditorContainer, { style: cssStyle, className: className, inWidth: width ?? idealWidth, inHeight: height ?? idealHeight },
2881
+ React.createElement(DataGridSearch, { fillHandle: fillHandle, drawFocusRing: drawFocusRing, experimental: experimental, fixedShadowX: fixedShadowX, fixedShadowY: fixedShadowY, getRowThemeOverride: getRowThemeOverride, headerIcons: headerIcons, imageWindowLoader: imageWindowLoader, initialSize: initialSize, isDraggable: isDraggable, onDragLeave: onDragLeave, onRowMoved: onRowMoved, overscrollX: overscrollX, overscrollY: overscrollY, preventDiagonalScrolling: preventDiagonalScrolling, rightElement: rightElement, rightElementProps: rightElementProps, smoothScrollX: smoothScrollX, smoothScrollY: smoothScrollY, className: className, enableGroups: enableGroups, onCanvasFocused: onCanvasFocused, onCanvasBlur: onFocusOut, canvasRef: canvasRef, onContextMenu: onContextMenu, theme: mergedTheme, cellXOffset: cellXOffset, cellYOffset: cellYOffset, accessibilityHeight: visibleRegion.height, onDragEnd: onDragEnd, columns: mangledCols, nonGrowWidth: nonGrowWidth, drawHeader: drawHeader, drawGroupHeader: drawGroupHeaderIn, onColumnProposeMove: onColumnProposeMoveImpl, drawCell: drawCell, disabledRows: disabledRows, freezeColumns: mangledFreezeColumns, lockColumns: rowMarkerOffset, firstColAccessible: rowMarkerOffset === 0, getCellContent: getMangledCellContent, minColumnWidth: minColumnWidth, maxColumnWidth: maxColumnWidth, searchInputRef: searchInputRef, showSearch: showSearch, onSearchClose: onSearchClose, highlightRegions: highlightRegions, getCellsForSelection: getCellsForSelection, getGroupDetails: mangledGetGroupDetails, headerHeight: headerHeight, isFocused: isFocused, groupHeaderHeight: enableGroups ? groupHeaderHeight : 0, freezeTrailingRows: freezeTrailingRows + (showTrailingBlankRow && trailingRowOptions?.sticky === true ? 1 : 0), hasAppendRow: showTrailingBlankRow, onColumnResize: onColumnResize, onColumnResizeEnd: onColumnResizeEnd, onColumnResizeStart: onColumnResizeStart, onCellFocused: onCellFocused, onColumnMoved: onColumnMovedImpl, onDragStart: onDragStartImpl, onHeaderMenuClick: onHeaderMenuClickInner, onHeaderIndicatorClick: onHeaderIndicatorClickInner, onItemHovered: onItemHoveredImpl, isFilling: mouseState?.fillHandle === true, onMouseMove: onMouseMoveImpl, onKeyDown: onKeyDown, onKeyUp: onKeyUpIn, onMouseDown: onMouseDown, onMouseUp: onMouseUp, onDragOverCell: onDragOverCell, onDrop: onDrop, onSearchResultsChanged: onSearchResultsChanged, onVisibleRegionChanged: onVisibleRegionChangedImpl, clientSize: clientSize, rowHeight: rowHeight, searchResults: searchResults, searchValue: searchValue, onSearchValueChange: onSearchValueChange, rows: mangledRows, scrollRef: scrollRef, selection: gridSelection, translateX: visibleRegion.tx, translateY: visibleRegion.ty, verticalBorder: mangledVerticalBorder, gridRef: gridRef, getCellRenderer: getCellRenderer, resizeIndicator: resizeIndicator, setScrollDir: setScrollDir }),
2882
+ renameGroupNode,
2883
+ overlay !== undefined && (React.createElement(React.Suspense, { fallback: null },
2884
+ React.createElement(DataGridOverlayEditor, { ...overlay, validateCell: validateCell, bloom: editorBloom, id: overlayID, getCellRenderer: getCellRenderer, className: experimental?.isSubGrid === true ? "click-outside-ignore" : undefined, provideEditor: provideEditor, imageEditorOverride: imageEditorOverride, portalElementRef: portalElementRef, onFinishEditing: onFinishEditing, markdownDivCreateNode: markdownDivCreateNode, isOutsideClick: isOutsideClick, customEventTarget: experimental?.eventTarget }))))));
2885
+ };
2886
+ /**
2887
+ * The primary component of Glide Data Grid.
2888
+ * @category DataEditor
2889
+ * @param {DataEditorProps} props
2890
+ */
2891
+ export const DataEditor = React.forwardRef(DataEditorImpl);
2892
+ //# sourceMappingURL=data-editor.js.map