@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,1978 @@
1
+ import * as React from "react";
2
+ import type { FullTheme } from "../../common/styles.js";
3
+ import {
4
+ computeBounds,
5
+ getColumnIndexForX,
6
+ getEffectiveColumns,
7
+ getRowIndexForY,
8
+ getStickyWidth,
9
+ rectBottomRight,
10
+ useMappedColumns,
11
+ } from "./render/data-grid-lib.js";
12
+ import {
13
+ GridCellKind,
14
+ type Rectangle,
15
+ type GridSelection,
16
+ type InnerGridCell,
17
+ InnerGridCellKind,
18
+ CompactSelection,
19
+ type Item,
20
+ type DrawHeaderCallback,
21
+ type DrawGroupHeaderCallback,
22
+ isReadWriteCell,
23
+ isInnerOnlyCell,
24
+ booleanCellIsEditable,
25
+ type InnerGridColumn,
26
+ type DrawCellCallback,
27
+ type FillHandle,
28
+ DEFAULT_FILL_HANDLE,
29
+ } from "./data-grid-types.js";
30
+ import { CellSet } from "./cell-set.js";
31
+ import { SpriteManager, type SpriteMap } from "./data-grid-sprites.js";
32
+ import { direction, getScrollBarWidth, useDebouncedMemo, useEventListener } from "../../common/utils.js";
33
+ import clamp from "lodash/clamp.js";
34
+ import makeRange from "lodash/range.js";
35
+ import { drawGrid } from "./render/data-grid-render.js";
36
+ import { type BlitData } from "./render/data-grid-render.blit.js";
37
+ import { AnimationManager, type StepCallback } from "./animation-manager.js";
38
+ import { RenderStateProvider, packColRowToNumber } from "../../common/render-state-provider.js";
39
+ import { browserIsFirefox, browserIsSafari } from "../../common/browser-detect.js";
40
+ import { type EnqueueCallback, useAnimationQueue } from "./use-animation-queue.js";
41
+ import { assert } from "../../common/support.js";
42
+ import type { CellRenderer, GetCellRendererCallback } from "../../cells/cell-types.js";
43
+ import type { DrawGridArg } from "./render/draw-grid-arg.js";
44
+ import type { ImageWindowLoader } from "./image-window-loader-interface.js";
45
+ import {
46
+ type GridMouseEventArgs,
47
+ type GridKeyEventArgs,
48
+ type GridDragEventArgs,
49
+ OutOfBoundsRegionAxis,
50
+ outOfBoundsKind,
51
+ groupHeaderKind,
52
+ headerKind,
53
+ mouseEventArgsAreEqual,
54
+ } from "./event-args.js";
55
+ import { pointInRect } from "../../common/math.js";
56
+ import {
57
+ type GroupDetailsCallback,
58
+ type GetRowThemeCallback,
59
+ type Highlight,
60
+ drawCell,
61
+ } from "./render/data-grid-render.cells.js";
62
+ import { getActionBoundsForGroup, drawHeader, computeHeaderLayout } from "./render/data-grid-render.header.js";
63
+
64
+ export interface DataGridProps {
65
+ readonly width: number;
66
+ readonly height: number;
67
+
68
+ readonly cellXOffset: number;
69
+ readonly cellYOffset: number;
70
+
71
+ readonly translateX: number | undefined;
72
+ readonly translateY: number | undefined;
73
+
74
+ readonly accessibilityHeight: number;
75
+
76
+ readonly freezeColumns: number;
77
+ readonly freezeTrailingRows: number;
78
+ readonly hasAppendRow: boolean;
79
+ readonly firstColAccessible: boolean;
80
+
81
+ /**
82
+ * Enables or disables the overlay shadow when scrolling horizontally
83
+ * @group Style
84
+ */
85
+ readonly fixedShadowX: boolean | undefined;
86
+ /**
87
+ * Enables or disables the overlay shadow when scrolling vertical
88
+ * @group Style
89
+ */
90
+ readonly fixedShadowY: boolean | undefined;
91
+
92
+ readonly allowResize: boolean | undefined;
93
+ readonly isResizing: boolean;
94
+ readonly resizeColumn: number | undefined;
95
+ readonly isDragging: boolean;
96
+ readonly isFilling: boolean;
97
+ readonly isFocused: boolean;
98
+
99
+ readonly columns: readonly InnerGridColumn[];
100
+ /**
101
+ * The number of rows in the grid.
102
+ * @group Data
103
+ */
104
+ readonly rows: number;
105
+
106
+ readonly headerHeight: number;
107
+ readonly groupHeaderHeight: number | number[];
108
+ readonly enableGroups: boolean;
109
+ readonly rowHeight: number | ((index: number) => number);
110
+
111
+ readonly canvasRef: React.MutableRefObject<HTMLCanvasElement | null> | undefined;
112
+
113
+ readonly eventTargetRef: React.MutableRefObject<HTMLDivElement | null> | undefined;
114
+
115
+ readonly getCellContent: (cell: Item, forceStrict?: boolean) => InnerGridCell;
116
+ /**
117
+ * Provides additional details about groups to extend group functionality.
118
+ * @group Data
119
+ */
120
+ readonly getGroupDetails: GroupDetailsCallback | undefined;
121
+ /**
122
+ * Provides per row theme overrides.
123
+ * @group Style
124
+ */
125
+ readonly getRowThemeOverride: GetRowThemeCallback | undefined;
126
+ /**
127
+ * Emitted when a header menu disclosure indicator is clicked.
128
+ * @group Events
129
+ */
130
+ readonly onHeaderMenuClick: ((col: number, screenPosition: Rectangle) => void) | undefined;
131
+
132
+ /**
133
+ * Emitted when a header indicator icon is clicked.
134
+ * @group Events
135
+ */
136
+ readonly onHeaderIndicatorClick: ((col: number, screenPosition: Rectangle) => void) | undefined;
137
+
138
+ readonly selection: GridSelection;
139
+ readonly prelightCells: readonly Item[] | undefined;
140
+ /**
141
+ * Highlight regions provide hints to users about relations between cells and selections.
142
+ * @group Selection
143
+ */
144
+ readonly highlightRegions: readonly Highlight[] | undefined;
145
+
146
+ /**
147
+ * Enabled/disables the fill handle.
148
+ * @defaultValue false
149
+ * @group Editing
150
+ */
151
+ readonly fillHandle: FillHandle | undefined;
152
+
153
+ readonly disabledRows: CompactSelection | undefined;
154
+ /**
155
+ * Allows passing a custom image window loader.
156
+ * @group Advanced
157
+ */
158
+ readonly imageWindowLoader: ImageWindowLoader;
159
+
160
+ /**
161
+ * Emitted when an item is hovered.
162
+ * @group Events
163
+ */
164
+ readonly onItemHovered: (args: GridMouseEventArgs) => void;
165
+ readonly onMouseMove: (args: GridMouseEventArgs) => void;
166
+ readonly onMouseDown: (args: GridMouseEventArgs) => void;
167
+ readonly onMouseUp: (args: GridMouseEventArgs, isOutside: boolean) => void;
168
+ readonly onContextMenu: (args: GridMouseEventArgs, preventDefault: () => void) => void;
169
+
170
+ readonly onCanvasFocused: () => void;
171
+ readonly onCanvasBlur: () => void;
172
+ readonly onCellFocused: (args: Item) => void;
173
+
174
+ readonly onMouseMoveRaw: (event: MouseEvent) => void;
175
+
176
+ /**
177
+ * Emitted when the canvas receives a key down event.
178
+ * @group Events
179
+ */
180
+ readonly onKeyDown: (event: GridKeyEventArgs) => void;
181
+ /**
182
+ * Emitted when the canvas receives a key up event.
183
+ * @group Events
184
+ */
185
+ readonly onKeyUp: ((event: GridKeyEventArgs) => void) | undefined;
186
+
187
+ readonly verticalBorder: (col: number) => boolean;
188
+
189
+ /**
190
+ * Determines what can be dragged using HTML drag and drop
191
+ * @defaultValue false
192
+ * @group Drag and Drop
193
+ */
194
+ readonly isDraggable: boolean | "cell" | "header" | undefined;
195
+ /**
196
+ * If `isDraggable` is set, the grid becomes HTML draggable, and `onDragStart` will be called when dragging starts.
197
+ * You can use this to build a UI where the user can drag the Grid around.
198
+ * @group Drag and Drop
199
+ */
200
+ readonly onDragStart: (args: GridDragEventArgs) => void;
201
+ readonly onDragEnd: () => void;
202
+
203
+ /** @group Drag and Drop */
204
+ readonly onDragOverCell: ((cell: Item, dataTransfer: DataTransfer | null) => void) | undefined;
205
+ /** @group Drag and Drop */
206
+ readonly onDragLeave: (() => void) | undefined;
207
+
208
+ /**
209
+ * Called when a HTML Drag and Drop event is ended on the data grid.
210
+ * @group Drag and Drop
211
+ */
212
+ readonly onDrop: ((cell: Item, dataTransfer: DataTransfer | null) => void) | undefined;
213
+
214
+ /**
215
+ * Overrides the rendering of a header. The grid will call this for every header it needs to render. Header
216
+ * rendering is not as well optimized because they do not redraw as often, but very heavy drawing methods can
217
+ * negatively impact horizontal scrolling performance.
218
+ *
219
+ * It is possible to return `false` after rendering just a background and the regular foreground rendering
220
+ * will happen.
221
+ * @group Drawing
222
+ * @returns `false` if default header rendering should still happen, `true` to cancel rendering.
223
+ */
224
+ readonly drawHeader: DrawHeaderCallback | undefined;
225
+
226
+ /**
227
+ * Overrides the rendering of a group header. The grid will call this for every group header it needs to render.
228
+ * Group header rendering is not as well optimized because they do not redraw as often, but very heavy drawing
229
+ * methods can negatively impact horizontal scrolling performance.
230
+ *
231
+ * It is possible to return `false` after rendering just a background and the regular foreground rendering
232
+ * will happen.
233
+ * @group Drawing
234
+ * @returns `false` if default group header rendering should still happen, `true` to cancel rendering.
235
+ */
236
+ readonly drawGroupHeader: DrawGroupHeaderCallback | undefined;
237
+
238
+ readonly drawCell: DrawCellCallback | undefined;
239
+
240
+ /**
241
+ * Controls the drawing of the focus ring.
242
+ * @defaultValue true
243
+ * @group Style
244
+ */
245
+ readonly drawFocusRing: boolean;
246
+
247
+ readonly dragAndDropState:
248
+ | {
249
+ src: number;
250
+ dest: number;
251
+ }
252
+ | undefined;
253
+
254
+ /**
255
+ * Experimental features
256
+ * @group Advanced
257
+ * @experimental
258
+ */
259
+ readonly experimental:
260
+ | {
261
+ readonly disableAccessibilityTree?: boolean;
262
+ readonly disableMinimumCellWidth?: boolean;
263
+ readonly paddingRight?: number;
264
+ readonly paddingBottom?: number;
265
+ readonly enableFirefoxRescaling?: boolean;
266
+ readonly enableSafariRescaling?: boolean;
267
+ readonly kineticScrollPerfHack?: boolean;
268
+ readonly isSubGrid?: boolean;
269
+ readonly strict?: boolean;
270
+ readonly scrollbarWidthOverride?: number;
271
+ readonly hyperWrapping?: boolean;
272
+ readonly renderStrategy?: "single-buffer" | "double-buffer" | "direct";
273
+ /**
274
+ * Allows providing a custom event target for event listeners.
275
+ * If not provided, the grid will use the window as the event target.
276
+ */
277
+ readonly eventTarget?: HTMLElement | Window | Document;
278
+ }
279
+ | undefined;
280
+
281
+ /**
282
+ * Additional header icons for use by `GridColumn`.
283
+ *
284
+ * Providing custom header icons to the data grid must be done with a somewhat non-standard mechanism to allow
285
+ * theming and scaling. The `headerIcons` property takes a dictionary which maps icon names to functions which can
286
+ * take a foreground and background color and returns back a string representation of an svg. The svg should contain
287
+ * a header similar to this `<svg width="20" height="20" fill="none" xmlns="http://www.w3.org/2000/svg">` and
288
+ * interpolate the fg/bg colors into the string.
289
+ *
290
+ * We recognize this process is not fantastic from a graphics workflow standpoint, improvements are very welcome
291
+ * here.
292
+ *
293
+ * @group Style
294
+ */
295
+ readonly headerIcons: SpriteMap | undefined;
296
+
297
+ /** Controls smooth scrolling in the data grid. If smooth scrolling is not enabled the grid will always be cell
298
+ * aligned.
299
+ * @defaultValue `false`
300
+ * @group Style
301
+ */
302
+ readonly smoothScrollX: boolean | undefined;
303
+ /** Controls smooth scrolling in the data grid. If smooth scrolling is not enabled the grid will always be cell
304
+ * aligned.
305
+ * @defaultValue `false`
306
+ * @group Style
307
+ */
308
+ readonly smoothScrollY: boolean | undefined;
309
+
310
+ readonly theme: FullTheme;
311
+
312
+ readonly getCellRenderer: <T extends InnerGridCell>(cell: T) => CellRenderer<T> | undefined;
313
+
314
+ /**
315
+ * Controls the resize indicator behavior.
316
+ *
317
+ * - `full` will show the resize indicator on the full height.
318
+ * - `header` will show the resize indicator only on the header.
319
+ * - `none` will not show the resize indicator.
320
+ *
321
+ * @defaultValue "full"
322
+ * @group Style
323
+ */
324
+ readonly resizeIndicator: "full" | "header" | "none" | undefined;
325
+ }
326
+
327
+ type DamageUpdateList = readonly {
328
+ cell: Item;
329
+ // newValue: GridCell,
330
+ }[];
331
+
332
+ export interface DataGridRef {
333
+ focus: () => void;
334
+ getBounds: (col?: number, row?: number) => Rectangle | undefined;
335
+ damage: (cells: DamageUpdateList) => void;
336
+ getMouseArgsForPosition: (
337
+ posX: number,
338
+ posY: number,
339
+ ev?: MouseEvent | TouchEvent
340
+ ) => GridMouseEventArgs | undefined;
341
+ }
342
+
343
+ const getRowData = (cell: InnerGridCell, getCellRenderer?: GetCellRendererCallback) => {
344
+ if (cell.kind === GridCellKind.Custom) return cell.copyData;
345
+ const r = getCellRenderer?.(cell);
346
+ return r?.getAccessibilityString(cell) ?? "";
347
+ };
348
+
349
+ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p, forwardedRef) => {
350
+ const {
351
+ width,
352
+ height,
353
+ accessibilityHeight,
354
+ columns,
355
+ cellXOffset: cellXOffsetReal,
356
+ cellYOffset,
357
+ headerHeight,
358
+ fillHandle = false,
359
+ groupHeaderHeight,
360
+ rowHeight,
361
+ rows,
362
+ getCellContent,
363
+ getRowThemeOverride,
364
+ onHeaderMenuClick,
365
+ onHeaderIndicatorClick,
366
+ enableGroups,
367
+ isFilling,
368
+ onCanvasFocused,
369
+ onCanvasBlur,
370
+ isFocused,
371
+ selection,
372
+ freezeColumns,
373
+ onContextMenu,
374
+ freezeTrailingRows,
375
+ fixedShadowX = true,
376
+ fixedShadowY = true,
377
+ drawFocusRing,
378
+ onMouseDown,
379
+ onMouseUp,
380
+ onMouseMoveRaw,
381
+ onMouseMove,
382
+ onItemHovered,
383
+ dragAndDropState,
384
+ firstColAccessible,
385
+ onKeyDown,
386
+ onKeyUp,
387
+ highlightRegions,
388
+ canvasRef,
389
+ onDragStart,
390
+ onDragEnd,
391
+ eventTargetRef,
392
+ isResizing,
393
+ resizeColumn: resizeCol,
394
+ isDragging,
395
+ isDraggable = false,
396
+ allowResize,
397
+ disabledRows,
398
+ hasAppendRow,
399
+ getGroupDetails,
400
+ theme,
401
+ prelightCells,
402
+ headerIcons,
403
+ verticalBorder,
404
+ drawCell: drawCellCallback,
405
+ drawHeader: drawHeaderCallback,
406
+ drawGroupHeader: drawGroupHeaderCallback,
407
+ onCellFocused,
408
+ onDragOverCell,
409
+ onDrop,
410
+ onDragLeave,
411
+ imageWindowLoader,
412
+ smoothScrollX = false,
413
+ smoothScrollY = false,
414
+ experimental,
415
+ getCellRenderer,
416
+ resizeIndicator = "full",
417
+ } = p;
418
+ const translateX = p.translateX ?? 0;
419
+ const translateY = p.translateY ?? 0;
420
+ const cellXOffset = Math.max(freezeColumns, Math.min(columns.length - 1, cellXOffsetReal));
421
+
422
+ const ref = React.useRef<HTMLCanvasElement | null>(null);
423
+ const windowEventTargetRef = React.useRef<HTMLElement | Window | Document>(experimental?.eventTarget ?? window);
424
+ const windowEventTarget = windowEventTargetRef.current;
425
+
426
+ const imageLoader = imageWindowLoader;
427
+ const damageRegion = React.useRef<CellSet | undefined>(undefined);
428
+ const [scrolling, setScrolling] = React.useState<boolean>(false);
429
+ const hoverValues = React.useRef<readonly { item: Item; hoverAmount: number }[]>([]);
430
+ const lastBlitData = React.useRef<BlitData | undefined>(undefined);
431
+ const [hoveredItemInfo, setHoveredItemInfo] = React.useState<[Item, readonly [number, number]] | undefined>();
432
+ const [hoveredOnEdge, setHoveredOnEdge] = React.useState<boolean>();
433
+ const overlayRef = React.useRef<HTMLCanvasElement | null>(null);
434
+ const [drawCursorOverride, setDrawCursorOverride] = React.useState<React.CSSProperties["cursor"] | undefined>();
435
+
436
+ const [lastWasTouch, setLastWasTouch] = React.useState(false);
437
+ const lastWasTouchRef = React.useRef(lastWasTouch);
438
+ lastWasTouchRef.current = lastWasTouch;
439
+
440
+ const spriteManager = React.useMemo(
441
+ () =>
442
+ new SpriteManager(headerIcons, () => {
443
+ lastArgsRef.current = undefined;
444
+ lastDrawRef.current();
445
+ }),
446
+ [headerIcons]
447
+ );
448
+ const groupHeights = enableGroups
449
+ ? (Array.isArray(groupHeaderHeight)
450
+ ? groupHeaderHeight.reduce((sum, h) => sum + h, 0)
451
+ : groupHeaderHeight)
452
+ : 0;
453
+ const totalHeaderHeight = headerHeight + groupHeights;
454
+
455
+ const scrollingStopRef = React.useRef(-1);
456
+ const enableFirefoxRescaling = (experimental?.enableFirefoxRescaling ?? false) && browserIsFirefox.value;
457
+ const enableSafariRescaling = (experimental?.enableSafariRescaling ?? false) && browserIsSafari.value;
458
+ React.useLayoutEffect(() => {
459
+ if (window.devicePixelRatio === 1 || (!enableFirefoxRescaling && !enableSafariRescaling)) return;
460
+ // We don't want to go into scroll mode for a single repaint
461
+ if (scrollingStopRef.current !== -1) {
462
+ setScrolling(true);
463
+ }
464
+ window.clearTimeout(scrollingStopRef.current);
465
+ scrollingStopRef.current = window.setTimeout(() => {
466
+ setScrolling(false);
467
+ scrollingStopRef.current = -1;
468
+ }, 200);
469
+ }, [cellYOffset, cellXOffset, translateX, translateY, enableFirefoxRescaling, enableSafariRescaling]);
470
+
471
+ const mappedColumns = useMappedColumns(columns, freezeColumns);
472
+ const stickyX = React.useMemo(
473
+ () => (fixedShadowX ? getStickyWidth(mappedColumns, dragAndDropState) : 0),
474
+ [mappedColumns, dragAndDropState, fixedShadowX]
475
+ );
476
+
477
+ // row: -1 === columnHeader, -2, -3, -4... === groupHeader levels (from top to bottom)
478
+ const getBoundsForItem = React.useCallback(
479
+ (canvas: HTMLCanvasElement, col: number, row: number): Rectangle | undefined => {
480
+ const rect = canvas.getBoundingClientRect();
481
+
482
+ if (col >= mappedColumns.length || row >= rows) {
483
+ return undefined;
484
+ }
485
+
486
+ const scale = rect.width / width;
487
+
488
+ const result = computeBounds(
489
+ col,
490
+ row,
491
+ width,
492
+ height,
493
+ groupHeaderHeight,
494
+ totalHeaderHeight,
495
+ cellXOffset,
496
+ cellYOffset,
497
+ translateX,
498
+ translateY,
499
+ rows,
500
+ freezeColumns,
501
+ freezeTrailingRows,
502
+ mappedColumns,
503
+ rowHeight
504
+ );
505
+
506
+ if (scale !== 1) {
507
+ result.x *= scale;
508
+ result.y *= scale;
509
+ result.width *= scale;
510
+ result.height *= scale;
511
+ }
512
+
513
+ result.x += rect.x;
514
+ result.y += rect.y;
515
+
516
+ return result;
517
+ },
518
+ [
519
+ width,
520
+ height,
521
+ groupHeaderHeight,
522
+ totalHeaderHeight,
523
+ cellXOffset,
524
+ cellYOffset,
525
+ translateX,
526
+ translateY,
527
+ rows,
528
+ freezeColumns,
529
+ freezeTrailingRows,
530
+ mappedColumns,
531
+ rowHeight,
532
+ ]
533
+ );
534
+
535
+ const getMouseArgsForPosition = React.useCallback(
536
+ (
537
+ canvas: HTMLCanvasElement,
538
+ posX: number,
539
+ posY: number,
540
+ ev?: PointerEvent | MouseEvent | TouchEvent
541
+ ): GridMouseEventArgs => {
542
+ const rect = canvas.getBoundingClientRect();
543
+ const scale = rect.width / width;
544
+ const x = (posX - rect.left) / scale;
545
+ const y = (posY - rect.top) / scale;
546
+ const edgeDetectionBuffer = 5;
547
+
548
+ const effectiveCols = getEffectiveColumns(mappedColumns, cellXOffset, width, undefined, translateX);
549
+
550
+ let button = 0;
551
+ let buttons = 0;
552
+
553
+ const isMouse =
554
+ (typeof PointerEvent !== "undefined" && ev instanceof PointerEvent && ev.pointerType === "mouse") ||
555
+ (typeof MouseEvent !== "undefined" && ev instanceof MouseEvent);
556
+
557
+ const isTouch =
558
+ (typeof PointerEvent !== "undefined" && ev instanceof PointerEvent && ev.pointerType === "touch") ||
559
+ (typeof TouchEvent !== "undefined" && ev instanceof TouchEvent);
560
+
561
+ if (isMouse) {
562
+ button = ev.button;
563
+ buttons = ev.buttons;
564
+ }
565
+
566
+ // -1 === off right edge
567
+ const col = getColumnIndexForX(x, effectiveCols, translateX);
568
+
569
+ // -1: header or above
570
+ // undefined: offbottom
571
+ const row = getRowIndexForY(
572
+ y,
573
+ height,
574
+ enableGroups,
575
+ headerHeight,
576
+ groupHeaderHeight,
577
+ rows,
578
+ rowHeight,
579
+ cellYOffset,
580
+ translateY,
581
+ freezeTrailingRows
582
+ );
583
+
584
+ const shiftKey = ev?.shiftKey === true;
585
+ const ctrlKey = ev?.ctrlKey === true;
586
+ const metaKey = ev?.metaKey === true;
587
+
588
+ const scrollEdge: GridMouseEventArgs["scrollEdge"] = [
589
+ x < 0 ? -1 : width < x ? 1 : 0,
590
+ y < totalHeaderHeight ? -1 : height < y ? 1 : 0,
591
+ ];
592
+
593
+ let result: GridMouseEventArgs;
594
+ if (col === -1 || y < 0 || x < 0 || row === undefined || x > width || y > height) {
595
+ const horizontal = x > width ? 1 : x < 0 ? -1 : 0;
596
+ const vertical = y > height ? 1 : y < 0 ? -1 : 0;
597
+
598
+ let innerHorizontal: OutOfBoundsRegionAxis = horizontal * 2;
599
+ let innerVertical: OutOfBoundsRegionAxis = vertical * 2;
600
+ if (horizontal === 0)
601
+ innerHorizontal = col === -1 ? OutOfBoundsRegionAxis.EndPadding : OutOfBoundsRegionAxis.Center;
602
+ if (vertical === 0)
603
+ innerVertical = row === undefined ? OutOfBoundsRegionAxis.EndPadding : OutOfBoundsRegionAxis.Center;
604
+
605
+ let isEdge = false;
606
+ if (col === -1 && row === -1) {
607
+ const b = getBoundsForItem(canvas, mappedColumns.length - 1, -1);
608
+ assert(b !== undefined);
609
+ isEdge = posX < b.x + b.width + edgeDetectionBuffer;
610
+ }
611
+
612
+ // This is used to ensure that clicking on the scrollbar doesn't unset the selection.
613
+ // Unfortunately this doesn't work for overlay scrollbars because they are just a broken interaction
614
+ // by design.
615
+ const isMaybeScrollbar =
616
+ (x > width && x < width + getScrollBarWidth()) || (y > height && y < height + getScrollBarWidth());
617
+
618
+ result = {
619
+ kind: outOfBoundsKind,
620
+ location: [col !== -1 ? col : x < 0 ? 0 : mappedColumns.length - 1, row ?? rows - 1],
621
+ region: [innerHorizontal, innerVertical],
622
+ shiftKey,
623
+ ctrlKey,
624
+ metaKey,
625
+ isEdge,
626
+ isTouch,
627
+ button,
628
+ buttons,
629
+ scrollEdge,
630
+ isMaybeScrollbar,
631
+ };
632
+ } else if (row <= -1) {
633
+ let bounds = getBoundsForItem(canvas, col, row);
634
+ assert(bounds !== undefined);
635
+ let isEdge = bounds !== undefined && bounds.x + bounds.width - posX <= edgeDetectionBuffer;
636
+
637
+ const previousCol = col - 1;
638
+ if (posX - bounds.x <= edgeDetectionBuffer && previousCol >= 0) {
639
+ isEdge = true;
640
+ bounds = getBoundsForItem(canvas, previousCol, row);
641
+ assert(bounds !== undefined);
642
+ result = {
643
+ kind: enableGroups && row <= -2 ? groupHeaderKind : headerKind,
644
+ location: [previousCol, row] as any,
645
+ bounds: bounds,
646
+ group: row <= -2
647
+ ? (Array.isArray(mappedColumns[previousCol].group)
648
+ ? mappedColumns[previousCol].group[-2 - row] ?? ""
649
+ : (row === -2 ? mappedColumns[previousCol].group ?? "" : ""))
650
+ : "",
651
+ isEdge,
652
+ shiftKey,
653
+ ctrlKey,
654
+ metaKey,
655
+ isTouch,
656
+ localEventX: posX - bounds.x,
657
+ localEventY: posY - bounds.y,
658
+ button,
659
+ buttons,
660
+ scrollEdge,
661
+ };
662
+ } else {
663
+ result = {
664
+ kind: enableGroups && row <= -2 ? groupHeaderKind : headerKind,
665
+ group: row <= -2
666
+ ? (Array.isArray(mappedColumns[col].group)
667
+ ? mappedColumns[col].group[-2 - row] ?? ""
668
+ : (row === -2 ? mappedColumns[col].group ?? "" : ""))
669
+ : "",
670
+ location: [col, row] as any,
671
+ bounds: bounds,
672
+ isEdge,
673
+ shiftKey,
674
+ ctrlKey,
675
+ metaKey,
676
+ isTouch,
677
+ localEventX: posX - bounds.x,
678
+ localEventY: posY - bounds.y,
679
+ button,
680
+ buttons,
681
+ scrollEdge,
682
+ };
683
+ }
684
+ } else {
685
+ const bounds = getBoundsForItem(canvas, col, row);
686
+ assert(bounds !== undefined);
687
+ const isEdge = bounds !== undefined && bounds.x + bounds.width - posX < edgeDetectionBuffer;
688
+
689
+ let isFillHandle = false;
690
+ const drawFill = fillHandle !== false && fillHandle !== undefined;
691
+ if (drawFill && selection.current !== undefined) {
692
+ const fill =
693
+ typeof fillHandle === "object"
694
+ ? { ...DEFAULT_FILL_HANDLE, ...fillHandle }
695
+ : DEFAULT_FILL_HANDLE;
696
+
697
+ const fillHandleClickSize = fill.size;
698
+ const half = fillHandleClickSize / 2;
699
+
700
+ const fillHandleLocation = rectBottomRight(selection.current.range);
701
+ const fillBounds = getBoundsForItem(canvas, fillHandleLocation[0], fillHandleLocation[1]);
702
+
703
+ if (fillBounds !== undefined) {
704
+ // Handle center sits exactly on the bottom-right corner of the cell.
705
+ // Offset by half pixel to align with grid lines.
706
+ const centerX = fillBounds.x + fillBounds.width + fill.offsetX - half + 0.5;
707
+ const centerY = fillBounds.y + fillBounds.height + fill.offsetY - half + 0.5;
708
+
709
+ // Check if posX and posY are within fillHandleClickSize from handleLogicalCenter
710
+ isFillHandle =
711
+ Math.abs(centerX - posX) < fillHandleClickSize &&
712
+ Math.abs(centerY - posY) < fillHandleClickSize;
713
+ }
714
+ }
715
+
716
+ result = {
717
+ kind: "cell",
718
+ location: [col, row],
719
+ bounds: bounds,
720
+ isEdge,
721
+ shiftKey,
722
+ ctrlKey,
723
+ isFillHandle,
724
+ metaKey,
725
+ isTouch,
726
+ localEventX: posX - bounds.x,
727
+ localEventY: posY - bounds.y,
728
+ button,
729
+ buttons,
730
+ scrollEdge,
731
+ };
732
+ }
733
+ return result;
734
+ },
735
+ [
736
+ width,
737
+ mappedColumns,
738
+ cellXOffset,
739
+ translateX,
740
+ height,
741
+ enableGroups,
742
+ headerHeight,
743
+ groupHeaderHeight,
744
+ rows,
745
+ rowHeight,
746
+ cellYOffset,
747
+ translateY,
748
+ freezeTrailingRows,
749
+ getBoundsForItem,
750
+ fillHandle,
751
+ selection,
752
+ totalHeaderHeight,
753
+ ]
754
+ );
755
+
756
+ const [hoveredItem] = hoveredItemInfo ?? [];
757
+
758
+ const enqueueRef = React.useRef<EnqueueCallback>(() => {
759
+ // do nothing
760
+ });
761
+ const hoverInfoRef = React.useRef(hoveredItemInfo);
762
+ hoverInfoRef.current = hoveredItemInfo;
763
+
764
+ const [bufferACtx, bufferBCtx] = React.useMemo(() => {
765
+ const a = document.createElement("canvas");
766
+ const b = document.createElement("canvas");
767
+ a.style["display"] = "none";
768
+ a.style["opacity"] = "0";
769
+ a.style["position"] = "fixed";
770
+ b.style["display"] = "none";
771
+ b.style["opacity"] = "0";
772
+ b.style["position"] = "fixed";
773
+ return [a.getContext("2d", { alpha: false }), b.getContext("2d", { alpha: false })];
774
+ }, []);
775
+
776
+ React.useLayoutEffect(() => {
777
+ if (bufferACtx === null || bufferBCtx === null) return;
778
+ document.documentElement.append(bufferACtx.canvas);
779
+ document.documentElement.append(bufferBCtx.canvas);
780
+ return () => {
781
+ bufferACtx.canvas.remove();
782
+ bufferBCtx.canvas.remove();
783
+ };
784
+ }, [bufferACtx, bufferBCtx]);
785
+
786
+ const renderStateProvider = React.useMemo(() => new RenderStateProvider(), []);
787
+
788
+ const maxDPR = enableFirefoxRescaling && scrolling ? 1 : enableSafariRescaling && scrolling ? 2 : 5;
789
+ const minimumCellWidth = experimental?.disableMinimumCellWidth === true ? 1 : 10;
790
+ const lastArgsRef = React.useRef<DrawGridArg | undefined>(undefined);
791
+
792
+ const canvasCtx = React.useRef<CanvasRenderingContext2D | null>(null);
793
+ const overlayCtx = React.useRef<CanvasRenderingContext2D | null>(null);
794
+
795
+ const draw = React.useCallback(() => {
796
+ const canvas = ref.current;
797
+ const overlay = overlayRef.current;
798
+ if (canvas === null || overlay === null) return;
799
+
800
+ if (canvasCtx.current === null) {
801
+ canvasCtx.current = canvas.getContext("2d", { alpha: false });
802
+ canvas.width = 0;
803
+ canvas.height = 0;
804
+ }
805
+
806
+ if (overlayCtx.current === null) {
807
+ overlayCtx.current = overlay.getContext("2d", { alpha: false });
808
+ overlay.width = 0;
809
+ overlay.height = 0;
810
+ }
811
+
812
+ if (canvasCtx.current === null || overlayCtx.current === null || bufferACtx === null || bufferBCtx === null) {
813
+ return;
814
+ }
815
+
816
+ let didOverride = false;
817
+ const overrideCursor = (cursor: React.CSSProperties["cursor"]) => {
818
+ didOverride = true;
819
+ setDrawCursorOverride(cursor);
820
+ };
821
+
822
+ const last = lastArgsRef.current;
823
+ const current = {
824
+ headerCanvasCtx: overlayCtx.current,
825
+ canvasCtx: canvasCtx.current,
826
+ bufferACtx,
827
+ bufferBCtx,
828
+ width,
829
+ height,
830
+ cellXOffset,
831
+ cellYOffset,
832
+ translateX: Math.round(translateX),
833
+ translateY: Math.round(translateY),
834
+ mappedColumns,
835
+ enableGroups,
836
+ freezeColumns,
837
+ dragAndDropState,
838
+ theme,
839
+ headerHeight,
840
+ groupHeaderHeight,
841
+ disabledRows: disabledRows ?? CompactSelection.empty(),
842
+ rowHeight,
843
+ verticalBorder,
844
+ isResizing,
845
+ resizeCol,
846
+ isFocused,
847
+ selection,
848
+ fillHandle,
849
+ drawCellCallback,
850
+ hasAppendRow,
851
+ overrideCursor,
852
+ maxScaleFactor: maxDPR,
853
+ freezeTrailingRows,
854
+ rows,
855
+ drawFocus: drawFocusRing,
856
+ getCellContent,
857
+ getGroupDetails: getGroupDetails ?? (name => ({ name })),
858
+ getRowThemeOverride,
859
+ drawHeaderCallback,
860
+ drawGroupHeaderCallback,
861
+ prelightCells,
862
+ highlightRegions,
863
+ imageLoader,
864
+ lastBlitData,
865
+ damage: damageRegion.current,
866
+ hoverValues: hoverValues.current,
867
+ hoverInfo: hoverInfoRef.current,
868
+ spriteManager,
869
+ scrolling,
870
+ hyperWrapping: experimental?.hyperWrapping ?? false,
871
+ touchMode: lastWasTouch,
872
+ enqueue: enqueueRef.current,
873
+ renderStateProvider,
874
+ renderStrategy: experimental?.renderStrategy ?? (browserIsSafari.value ? "double-buffer" : "single-buffer"),
875
+ getCellRenderer,
876
+ minimumCellWidth,
877
+ resizeIndicator,
878
+ };
879
+
880
+ // This confusing bit of code due to some poor design. Long story short, the damage property is only used
881
+ // with what is effectively the "last args" for the last normal draw anyway. We don't want the drawing code
882
+ // to look at this and go "shit dawg, nothing changed" so we force it to draw frash, but the damage restricts
883
+ // the draw anyway.
884
+ //
885
+ // Dear future Jason, I'm sorry. It was expedient, it worked, and had almost zero perf overhead. THe universe
886
+ // basically made me do it. What choice did I have?
887
+ if (current.damage === undefined) {
888
+ lastArgsRef.current = current;
889
+ drawGrid(current, last);
890
+ } else {
891
+ drawGrid(current, undefined);
892
+ }
893
+
894
+ // don't reset on damage events
895
+ if (!didOverride && (current.damage === undefined || current.damage.has(hoverInfoRef?.current?.[0]))) {
896
+ setDrawCursorOverride(undefined);
897
+ }
898
+ }, [
899
+ bufferACtx,
900
+ bufferBCtx,
901
+ width,
902
+ height,
903
+ cellXOffset,
904
+ cellYOffset,
905
+ translateX,
906
+ translateY,
907
+ mappedColumns,
908
+ enableGroups,
909
+ freezeColumns,
910
+ dragAndDropState,
911
+ theme,
912
+ headerHeight,
913
+ groupHeaderHeight,
914
+ disabledRows,
915
+ rowHeight,
916
+ verticalBorder,
917
+ isResizing,
918
+ hasAppendRow,
919
+ resizeCol,
920
+ isFocused,
921
+ selection,
922
+ fillHandle,
923
+ freezeTrailingRows,
924
+ rows,
925
+ drawFocusRing,
926
+ maxDPR,
927
+ getCellContent,
928
+ getGroupDetails,
929
+ getRowThemeOverride,
930
+ drawCellCallback,
931
+ drawHeaderCallback,
932
+ drawGroupHeaderCallback,
933
+ prelightCells,
934
+ highlightRegions,
935
+ imageLoader,
936
+ spriteManager,
937
+ scrolling,
938
+ experimental?.hyperWrapping,
939
+ experimental?.renderStrategy,
940
+ lastWasTouch,
941
+ renderStateProvider,
942
+ getCellRenderer,
943
+ minimumCellWidth,
944
+ resizeIndicator,
945
+ ]);
946
+
947
+ const lastDrawRef = React.useRef(draw);
948
+ React.useLayoutEffect(() => {
949
+ draw();
950
+ lastDrawRef.current = draw;
951
+ }, [draw]);
952
+
953
+ React.useLayoutEffect(() => {
954
+ const fn = async () => {
955
+ if (document?.fonts?.ready === undefined) return;
956
+ await document.fonts.ready;
957
+ lastArgsRef.current = undefined;
958
+ lastDrawRef.current();
959
+ };
960
+ void fn();
961
+ }, []);
962
+
963
+ const damageInternal = React.useCallback((locations: CellSet) => {
964
+ damageRegion.current = locations;
965
+ lastDrawRef.current();
966
+ damageRegion.current = undefined;
967
+ }, []);
968
+
969
+ const enqueue = useAnimationQueue(damageInternal);
970
+ enqueueRef.current = enqueue;
971
+
972
+ const damage = React.useCallback(
973
+ (cells: DamageUpdateList) => {
974
+ damageInternal(new CellSet(cells.map(x => x.cell)));
975
+ },
976
+ [damageInternal]
977
+ );
978
+
979
+ imageLoader.setCallback(damageInternal);
980
+
981
+ const [overFill, setOverFill] = React.useState(false);
982
+
983
+ const [hCol, hRow] = hoveredItem ?? [];
984
+ const headerHovered =
985
+ hCol !== undefined &&
986
+ hRow === -1 &&
987
+ hCol >= 0 &&
988
+ hCol < mappedColumns.length &&
989
+ mappedColumns[hCol].headerRowMarkerDisabled !== true;
990
+ const groupHeaderHovered = hCol !== undefined && hRow === -2;
991
+ let clickableInnerCellHovered = false;
992
+ let editableBoolHovered = false;
993
+ let cursorOverride: React.CSSProperties["cursor"] | undefined = drawCursorOverride;
994
+ if (cursorOverride === undefined && hCol !== undefined && hRow !== undefined && hRow > -1 && hRow < rows) {
995
+ const cell = getCellContent([hCol, hRow], true);
996
+ clickableInnerCellHovered =
997
+ cell.kind === InnerGridCellKind.NewRow ||
998
+ (cell.kind === InnerGridCellKind.Marker && cell.markerKind !== "number");
999
+ editableBoolHovered = cell.kind === GridCellKind.Boolean && booleanCellIsEditable(cell);
1000
+ cursorOverride = cell.cursor;
1001
+ }
1002
+ const canDrag = hoveredOnEdge ?? false;
1003
+ const cursor = isDragging
1004
+ ? "grabbing"
1005
+ : canDrag || isResizing
1006
+ ? "col-resize"
1007
+ : overFill || isFilling
1008
+ ? "crosshair"
1009
+ : cursorOverride !== undefined
1010
+ ? cursorOverride
1011
+ : headerHovered || clickableInnerCellHovered || editableBoolHovered || groupHeaderHovered
1012
+ ? "pointer"
1013
+ : "default";
1014
+
1015
+ const style = React.useMemo(
1016
+ () => ({
1017
+ // width,
1018
+ // height,
1019
+ contain: "strict",
1020
+ display: "block",
1021
+ cursor,
1022
+ }),
1023
+ [cursor]
1024
+ );
1025
+
1026
+ const lastSetCursor = React.useRef<typeof cursor>("default");
1027
+ const target = eventTargetRef?.current;
1028
+ if (target !== null && target !== undefined && lastSetCursor.current !== style.cursor) {
1029
+ // because we have an event target we need to set its cursor instead.
1030
+ target.style.cursor = lastSetCursor.current = style.cursor;
1031
+ }
1032
+
1033
+ const groupHeaderActionForEvent = React.useCallback(
1034
+ (group: string, bounds: Rectangle, localEventX: number, localEventY: number) => {
1035
+ if (getGroupDetails === undefined) return undefined;
1036
+ const groupDesc = getGroupDetails(group);
1037
+ if (groupDesc.actions !== undefined) {
1038
+ const boxes = getActionBoundsForGroup(bounds, groupDesc.actions);
1039
+ for (const [i, box] of boxes.entries()) {
1040
+ if (pointInRect(box, localEventX + bounds.x, localEventY + box.y)) {
1041
+ return groupDesc.actions[i];
1042
+ }
1043
+ }
1044
+ }
1045
+ return undefined;
1046
+ },
1047
+ [getGroupDetails]
1048
+ );
1049
+
1050
+ const isOverHeaderElement = React.useCallback(
1051
+ (
1052
+ canvas: HTMLCanvasElement,
1053
+ col: number,
1054
+ clientX: number,
1055
+ clientY: number
1056
+ ):
1057
+ | {
1058
+ area: "menu" | "indicator";
1059
+ bounds: Rectangle;
1060
+ }
1061
+ | undefined => {
1062
+ const header = mappedColumns[col];
1063
+
1064
+ if (!isDragging && !isResizing && !(hoveredOnEdge ?? false)) {
1065
+ const headerBounds = getBoundsForItem(canvas, col, -1);
1066
+ assert(headerBounds !== undefined);
1067
+ const headerLayout = computeHeaderLayout(
1068
+ undefined,
1069
+ header,
1070
+ headerBounds.x,
1071
+ headerBounds.y,
1072
+ headerBounds.width,
1073
+ headerBounds.height,
1074
+ theme,
1075
+ direction(header.title) === "rtl"
1076
+ );
1077
+ if (
1078
+ header.hasMenu === true &&
1079
+ headerLayout.menuBounds !== undefined &&
1080
+ pointInRect(headerLayout.menuBounds, clientX, clientY)
1081
+ ) {
1082
+ return {
1083
+ area: "menu",
1084
+ bounds: headerLayout.menuBounds,
1085
+ };
1086
+ } else if (
1087
+ header.indicatorIcon !== undefined &&
1088
+ headerLayout.indicatorIconBounds !== undefined &&
1089
+ pointInRect(headerLayout.indicatorIconBounds, clientX, clientY)
1090
+ ) {
1091
+ return {
1092
+ area: "indicator",
1093
+ bounds: headerLayout.indicatorIconBounds,
1094
+ };
1095
+ }
1096
+ }
1097
+ return undefined;
1098
+ },
1099
+ [mappedColumns, getBoundsForItem, hoveredOnEdge, isDragging, isResizing, theme]
1100
+ );
1101
+
1102
+ const downTime = React.useRef(0);
1103
+ const downPosition = React.useRef<Item | undefined>(undefined);
1104
+ const mouseDown = React.useRef(false);
1105
+ const onPointerDown = React.useCallback(
1106
+ (ev: PointerEvent) => {
1107
+ const canvas = ref.current;
1108
+ const eventTarget = eventTargetRef?.current;
1109
+ if (canvas === null || (ev.target !== canvas && ev.target !== eventTarget)) return;
1110
+ mouseDown.current = true;
1111
+
1112
+ const clientX = ev.clientX;
1113
+ const clientY = ev.clientY;
1114
+
1115
+ if (ev.target === eventTarget && eventTarget !== null) {
1116
+ const bounds = eventTarget.getBoundingClientRect();
1117
+ if (clientX > bounds.right || clientY > bounds.bottom) return;
1118
+ }
1119
+
1120
+ const args = getMouseArgsForPosition(canvas, clientX, clientY, ev);
1121
+ downPosition.current = args.location;
1122
+
1123
+ if (args.isTouch) {
1124
+ downTime.current = Date.now();
1125
+ }
1126
+ if (lastWasTouchRef.current !== args.isTouch) {
1127
+ setLastWasTouch(args.isTouch);
1128
+ }
1129
+
1130
+ if (
1131
+ args.kind === headerKind &&
1132
+ isOverHeaderElement(canvas, args.location[0], clientX, clientY) !== undefined
1133
+ ) {
1134
+ return;
1135
+ } else if (args.kind === groupHeaderKind) {
1136
+ const action = groupHeaderActionForEvent(args.group, args.bounds, args.localEventX, args.localEventY);
1137
+ if (action !== undefined) {
1138
+ return;
1139
+ }
1140
+ }
1141
+
1142
+ onMouseDown?.(args);
1143
+ if (
1144
+ !args.isTouch &&
1145
+ isDraggable !== true &&
1146
+ isDraggable !== args.kind &&
1147
+ args.button < 3 &&
1148
+ args.button !== 1
1149
+ ) {
1150
+ // preventing default in touch events stops scroll
1151
+ ev.preventDefault();
1152
+ }
1153
+ },
1154
+ [
1155
+ eventTargetRef,
1156
+ isDraggable,
1157
+ getMouseArgsForPosition,
1158
+ groupHeaderActionForEvent,
1159
+ isOverHeaderElement,
1160
+ onMouseDown,
1161
+ ]
1162
+ );
1163
+ useEventListener("pointerdown", onPointerDown, windowEventTarget, false);
1164
+
1165
+ const lastUpTime = React.useRef(0);
1166
+
1167
+ const onPointerUp = React.useCallback(
1168
+ (ev: PointerEvent) => {
1169
+ const lastUpTimeValue = lastUpTime.current;
1170
+ lastUpTime.current = Date.now();
1171
+ const canvas = ref.current;
1172
+ mouseDown.current = false;
1173
+ if (onMouseUp === undefined || canvas === null) return;
1174
+ const eventTarget = eventTargetRef?.current;
1175
+
1176
+ const isOutside = ev.target !== canvas && ev.target !== eventTarget;
1177
+ const clientX = ev.clientX;
1178
+ const clientY = ev.clientY;
1179
+ const canCancel = ev.pointerType === "mouse" ? ev.button < 3 : true;
1180
+
1181
+ let args = getMouseArgsForPosition(canvas, clientX, clientY, ev);
1182
+
1183
+ if (args.isTouch && downTime.current !== 0 && Date.now() - downTime.current > 500) {
1184
+ args = {
1185
+ ...args,
1186
+ isLongTouch: true,
1187
+ };
1188
+ }
1189
+
1190
+ if (lastUpTimeValue !== 0 && Date.now() - lastUpTimeValue < (args.isTouch ? 1000 : 500)) {
1191
+ args = {
1192
+ ...args,
1193
+ isDoubleClick: true,
1194
+ };
1195
+ }
1196
+
1197
+ if (lastWasTouchRef.current !== args.isTouch) {
1198
+ setLastWasTouch(args.isTouch);
1199
+ }
1200
+
1201
+ if (!isOutside && ev.cancelable && canCancel) {
1202
+ ev.preventDefault();
1203
+ }
1204
+
1205
+ const [col] = args.location;
1206
+ const headerBounds = isOverHeaderElement(canvas, col, clientX, clientY);
1207
+ if (args.kind === headerKind && headerBounds !== undefined) {
1208
+ if (args.button !== 0 || downPosition.current?.[0] !== col || downPosition.current?.[1] !== -1) {
1209
+ // force outside so that click will not process
1210
+ onMouseUp(args, true);
1211
+ }
1212
+ return;
1213
+ } else if (args.kind === groupHeaderKind) {
1214
+ const action = groupHeaderActionForEvent(args.group, args.bounds, args.localEventX, args.localEventY);
1215
+ if (action !== undefined) {
1216
+ if (args.button === 0) {
1217
+ action.onClick(args);
1218
+ }
1219
+ return;
1220
+ }
1221
+ }
1222
+
1223
+ onMouseUp(args, isOutside);
1224
+ },
1225
+ [onMouseUp, eventTargetRef, getMouseArgsForPosition, isOverHeaderElement, groupHeaderActionForEvent]
1226
+ );
1227
+ useEventListener("pointerup", onPointerUp, windowEventTarget, false);
1228
+
1229
+ const onClickImpl = React.useCallback(
1230
+ (ev: MouseEvent | TouchEvent) => {
1231
+ const canvas = ref.current;
1232
+ if (canvas === null) return;
1233
+ const eventTarget = eventTargetRef?.current;
1234
+
1235
+ const isOutside = ev.target !== canvas && ev.target !== eventTarget;
1236
+
1237
+ let clientX: number;
1238
+ let clientY: number;
1239
+ let canCancel = true;
1240
+ if (ev instanceof MouseEvent) {
1241
+ clientX = ev.clientX;
1242
+ clientY = ev.clientY;
1243
+ canCancel = ev.button < 3;
1244
+ } else {
1245
+ clientX = ev.changedTouches[0].clientX;
1246
+ clientY = ev.changedTouches[0].clientY;
1247
+ }
1248
+
1249
+ const args = getMouseArgsForPosition(canvas, clientX, clientY, ev);
1250
+
1251
+ if (lastWasTouchRef.current !== args.isTouch) {
1252
+ setLastWasTouch(args.isTouch);
1253
+ }
1254
+
1255
+ if (!isOutside && ev.cancelable && canCancel) {
1256
+ ev.preventDefault();
1257
+ }
1258
+
1259
+ const [col] = args.location;
1260
+ if (args.kind === headerKind) {
1261
+ const headerBounds = isOverHeaderElement(canvas, col, clientX, clientY);
1262
+ if (
1263
+ headerBounds !== undefined &&
1264
+ args.button === 0 &&
1265
+ downPosition.current?.[0] === col &&
1266
+ downPosition.current?.[1] === -1
1267
+ ) {
1268
+ if (headerBounds.area === "menu") {
1269
+ onHeaderMenuClick?.(col, headerBounds.bounds);
1270
+ } else if (headerBounds.area === "indicator") {
1271
+ onHeaderIndicatorClick?.(col, headerBounds.bounds);
1272
+ }
1273
+ }
1274
+ }
1275
+ },
1276
+ [eventTargetRef, getMouseArgsForPosition, isOverHeaderElement, onHeaderMenuClick, onHeaderIndicatorClick]
1277
+ );
1278
+ useEventListener("click", onClickImpl, windowEventTarget, false);
1279
+
1280
+ const onContextMenuImpl = React.useCallback(
1281
+ (ev: MouseEvent) => {
1282
+ const canvas = ref.current;
1283
+ const eventTarget = eventTargetRef?.current;
1284
+ if (canvas === null || (ev.target !== canvas && ev.target !== eventTarget) || onContextMenu === undefined)
1285
+ return;
1286
+ const args = getMouseArgsForPosition(canvas, ev.clientX, ev.clientY, ev);
1287
+ onContextMenu(args, () => {
1288
+ if (ev.cancelable) ev.preventDefault();
1289
+ });
1290
+ },
1291
+ [eventTargetRef, getMouseArgsForPosition, onContextMenu]
1292
+ );
1293
+ useEventListener("contextmenu", onContextMenuImpl, eventTargetRef?.current ?? null, false);
1294
+
1295
+ const onAnimationFrame = React.useCallback<StepCallback>(values => {
1296
+ damageRegion.current = new CellSet(values.map(x => x.item));
1297
+ hoverValues.current = values;
1298
+ lastDrawRef.current();
1299
+ damageRegion.current = undefined;
1300
+ }, []);
1301
+
1302
+ const animManagerValue = React.useMemo(() => new AnimationManager(onAnimationFrame), [onAnimationFrame]);
1303
+ const animationManager = React.useRef(animManagerValue);
1304
+ animationManager.current = animManagerValue;
1305
+ React.useLayoutEffect(() => {
1306
+ const am = animationManager.current;
1307
+ if (hoveredItem === undefined || hoveredItem[1] < 0) {
1308
+ am.setHovered(hoveredItem);
1309
+ return;
1310
+ }
1311
+ const cell = getCellContent(hoveredItem as [number, number], true);
1312
+ const r = getCellRenderer(cell);
1313
+ const cellNeedsHover =
1314
+ (r === undefined && cell.kind === GridCellKind.Custom) ||
1315
+ (r?.needsHover !== undefined && (typeof r.needsHover === "boolean" ? r.needsHover : r.needsHover(cell)));
1316
+ am.setHovered(cellNeedsHover ? hoveredItem : undefined);
1317
+ }, [getCellContent, getCellRenderer, hoveredItem]);
1318
+
1319
+ const hoveredRef = React.useRef<GridMouseEventArgs | undefined>(undefined);
1320
+ const onPointerMove = React.useCallback(
1321
+ (ev: MouseEvent) => {
1322
+ const canvas = ref.current;
1323
+ if (canvas === null) return;
1324
+
1325
+ const eventTarget = eventTargetRef?.current;
1326
+ const isIndirect = ev.target !== canvas && ev.target !== eventTarget;
1327
+
1328
+ const args = getMouseArgsForPosition(canvas, ev.clientX, ev.clientY, ev);
1329
+ if (args.kind !== "out-of-bounds" && isIndirect && !mouseDown.current && !args.isTouch) {
1330
+ // we are obscured by something else, so we want to not register events if we are not doing anything
1331
+ // important already
1332
+ return;
1333
+ }
1334
+
1335
+ // the point here is not to trigger re-renders every time the mouse moves over a cell
1336
+ // that doesn't care about the mouse positon.
1337
+ const maybeSetHoveredInfo = (newVal: typeof hoveredItemInfo, needPosition: boolean) => {
1338
+ setHoveredItemInfo(cv => {
1339
+ if (cv === newVal) return cv;
1340
+ if (
1341
+ cv?.[0][0] === newVal?.[0][0] &&
1342
+ cv?.[0][1] === newVal?.[0][1] &&
1343
+ ((cv?.[1][0] === newVal?.[1][0] && cv?.[1][1] === newVal?.[1][1]) || !needPosition)
1344
+ ) {
1345
+ return cv;
1346
+ }
1347
+ return newVal;
1348
+ });
1349
+ };
1350
+
1351
+ if (!mouseEventArgsAreEqual(args, hoveredRef.current)) {
1352
+ setDrawCursorOverride(undefined);
1353
+ onItemHovered?.(args);
1354
+ maybeSetHoveredInfo(
1355
+ args.kind === outOfBoundsKind ? undefined : [args.location, [args.localEventX, args.localEventY]],
1356
+ true
1357
+ );
1358
+ hoveredRef.current = args;
1359
+ } else if (args.kind === "cell" || args.kind === headerKind || args.kind === groupHeaderKind) {
1360
+ let needsDamageCell = false;
1361
+ let needsHoverPosition = true;
1362
+
1363
+ if (args.kind === "cell") {
1364
+ const toCheck = getCellContent(args.location);
1365
+ const rendererNeeds = getCellRenderer(toCheck)?.needsHoverPosition;
1366
+ // custom cells we will assume need the position if they don't explicitly say they don't, everything
1367
+ // else we will assume doesn't need it.
1368
+ needsHoverPosition = rendererNeeds ?? toCheck.kind === GridCellKind.Custom;
1369
+ needsDamageCell = needsHoverPosition;
1370
+ } else {
1371
+ needsDamageCell = true;
1372
+ }
1373
+
1374
+ const newInfo: typeof hoverInfoRef.current = [args.location, [args.localEventX, args.localEventY]];
1375
+ maybeSetHoveredInfo(newInfo, needsHoverPosition);
1376
+ hoverInfoRef.current = newInfo;
1377
+ if (needsDamageCell) {
1378
+ damageInternal(new CellSet([args.location]));
1379
+ }
1380
+ }
1381
+
1382
+ const notRowMarkerCol = args.location[0] >= (firstColAccessible ? 0 : 1);
1383
+ setHoveredOnEdge(args.kind === headerKind && args.isEdge && notRowMarkerCol && allowResize === true);
1384
+
1385
+ setOverFill(args.kind === "cell" && args.isFillHandle);
1386
+
1387
+ onMouseMoveRaw?.(ev);
1388
+ onMouseMove(args);
1389
+ },
1390
+ [
1391
+ eventTargetRef,
1392
+ getMouseArgsForPosition,
1393
+ firstColAccessible,
1394
+ allowResize,
1395
+ onMouseMoveRaw,
1396
+ onMouseMove,
1397
+ onItemHovered,
1398
+ getCellContent,
1399
+ getCellRenderer,
1400
+ damageInternal,
1401
+ ]
1402
+ );
1403
+ useEventListener("pointermove", onPointerMove, windowEventTarget, true);
1404
+
1405
+ const onKeyDownImpl = React.useCallback(
1406
+ (event: React.KeyboardEvent<HTMLCanvasElement>) => {
1407
+ const canvas = ref.current;
1408
+ if (canvas === null) return;
1409
+
1410
+ let bounds: Rectangle | undefined;
1411
+ let location: Item | undefined = undefined;
1412
+ if (selection.current !== undefined) {
1413
+ bounds = getBoundsForItem(canvas, selection.current.cell[0], selection.current.cell[1]);
1414
+ location = selection.current.cell;
1415
+ }
1416
+
1417
+ onKeyDown?.({
1418
+ bounds,
1419
+ stopPropagation: () => event.stopPropagation(),
1420
+ preventDefault: () => event.preventDefault(),
1421
+ cancel: () => undefined,
1422
+ ctrlKey: event.ctrlKey,
1423
+ metaKey: event.metaKey,
1424
+ shiftKey: event.shiftKey,
1425
+ altKey: event.altKey,
1426
+ key: event.key,
1427
+ keyCode: event.keyCode,
1428
+ rawEvent: event,
1429
+ location,
1430
+ });
1431
+ },
1432
+ [onKeyDown, selection, getBoundsForItem]
1433
+ );
1434
+
1435
+ const onKeyUpImpl = React.useCallback(
1436
+ (event: React.KeyboardEvent<HTMLCanvasElement>) => {
1437
+ const canvas = ref.current;
1438
+ if (canvas === null) return;
1439
+
1440
+ let bounds: Rectangle | undefined;
1441
+ let location: Item | undefined = undefined;
1442
+ if (selection.current !== undefined) {
1443
+ bounds = getBoundsForItem(canvas, selection.current.cell[0], selection.current.cell[1]);
1444
+ location = selection.current.cell;
1445
+ }
1446
+
1447
+ onKeyUp?.({
1448
+ bounds,
1449
+ stopPropagation: () => event.stopPropagation(),
1450
+ preventDefault: () => event.preventDefault(),
1451
+ cancel: () => undefined,
1452
+ ctrlKey: event.ctrlKey,
1453
+ metaKey: event.metaKey,
1454
+ shiftKey: event.shiftKey,
1455
+ altKey: event.altKey,
1456
+ key: event.key,
1457
+ keyCode: event.keyCode,
1458
+ rawEvent: event,
1459
+ location,
1460
+ });
1461
+ },
1462
+ [onKeyUp, selection, getBoundsForItem]
1463
+ );
1464
+
1465
+ const refImpl = React.useCallback(
1466
+ (instance: HTMLCanvasElement | null) => {
1467
+ ref.current = instance;
1468
+ if (canvasRef !== undefined) {
1469
+ canvasRef.current = instance;
1470
+ }
1471
+
1472
+ if (experimental?.eventTarget) {
1473
+ windowEventTargetRef.current = experimental.eventTarget;
1474
+ } else if (instance === null) {
1475
+ windowEventTargetRef.current = window;
1476
+ } else {
1477
+ const docRoot = instance.getRootNode();
1478
+
1479
+ if (docRoot === document) windowEventTargetRef.current = window;
1480
+ windowEventTargetRef.current = docRoot as any;
1481
+ }
1482
+ },
1483
+ [canvasRef, experimental?.eventTarget]
1484
+ );
1485
+
1486
+ const onDragStartImpl = React.useCallback(
1487
+ (event: DragEvent) => {
1488
+ const canvas = ref.current;
1489
+ if (canvas === null || isDraggable === false || isResizing) {
1490
+ event.preventDefault();
1491
+ return;
1492
+ }
1493
+
1494
+ let dragMime: string | undefined;
1495
+ let dragData: string | undefined;
1496
+
1497
+ const args = getMouseArgsForPosition(canvas, event.clientX, event.clientY);
1498
+
1499
+ if (isDraggable !== true && args.kind !== isDraggable) {
1500
+ event.preventDefault();
1501
+ return;
1502
+ }
1503
+
1504
+ const setData = (mime: string, payload: string) => {
1505
+ dragMime = mime;
1506
+ dragData = payload;
1507
+ };
1508
+
1509
+ let dragImage: Element | undefined;
1510
+ let dragImageX: number | undefined;
1511
+ let dragImageY: number | undefined;
1512
+ const setDragImage = (image: Element, x: number, y: number) => {
1513
+ dragImage = image;
1514
+ dragImageX = x;
1515
+ dragImageY = y;
1516
+ };
1517
+
1518
+ let prevented = false;
1519
+
1520
+ onDragStart?.({
1521
+ ...args,
1522
+ setData,
1523
+ setDragImage,
1524
+ preventDefault: () => (prevented = true),
1525
+ defaultPrevented: () => prevented,
1526
+ });
1527
+ if (!prevented && dragMime !== undefined && dragData !== undefined && event.dataTransfer !== null) {
1528
+ event.dataTransfer.setData(dragMime, dragData);
1529
+ event.dataTransfer.effectAllowed = "copyLink";
1530
+
1531
+ if (dragImage !== undefined && dragImageX !== undefined && dragImageY !== undefined) {
1532
+ event.dataTransfer.setDragImage(dragImage, dragImageX, dragImageY);
1533
+ } else {
1534
+ const [col, row] = args.location;
1535
+ if (row !== undefined) {
1536
+ const offscreen = document.createElement("canvas");
1537
+ const boundsForDragTarget = getBoundsForItem(canvas, col, row);
1538
+
1539
+ assert(boundsForDragTarget !== undefined);
1540
+ const dpr = Math.ceil(window.devicePixelRatio ?? 1);
1541
+ offscreen.width = boundsForDragTarget.width * dpr;
1542
+ offscreen.height = boundsForDragTarget.height * dpr;
1543
+
1544
+ const ctx = offscreen.getContext("2d");
1545
+ if (ctx !== null) {
1546
+ ctx.scale(dpr, dpr);
1547
+ ctx.textBaseline = "middle";
1548
+ if (row === -1) {
1549
+ ctx.font = theme.headerFontFull;
1550
+ ctx.fillStyle = theme.bgHeader;
1551
+ ctx.fillRect(0, 0, offscreen.width, offscreen.height);
1552
+ drawHeader(
1553
+ ctx,
1554
+ 0,
1555
+ 0,
1556
+ boundsForDragTarget.width,
1557
+ boundsForDragTarget.height,
1558
+ mappedColumns[col],
1559
+ false,
1560
+ theme,
1561
+ false,
1562
+ undefined,
1563
+ undefined,
1564
+ false,
1565
+ 0,
1566
+ spriteManager,
1567
+ drawHeaderCallback,
1568
+ false
1569
+ );
1570
+ } else {
1571
+ ctx.font = theme.baseFontFull;
1572
+ ctx.fillStyle = theme.bgCell;
1573
+ ctx.fillRect(0, 0, offscreen.width, offscreen.height);
1574
+ drawCell(
1575
+ ctx,
1576
+ getCellContent([col, row]),
1577
+ 0,
1578
+ row,
1579
+ false,
1580
+ false,
1581
+ 0,
1582
+ 0,
1583
+ boundsForDragTarget.width,
1584
+ boundsForDragTarget.height,
1585
+ false,
1586
+ theme,
1587
+ theme.bgCell,
1588
+ imageLoader,
1589
+ spriteManager,
1590
+ 1,
1591
+ undefined,
1592
+ false,
1593
+ 0,
1594
+ undefined,
1595
+ undefined,
1596
+ undefined,
1597
+ renderStateProvider,
1598
+ getCellRenderer,
1599
+ () => undefined
1600
+ );
1601
+ }
1602
+ }
1603
+
1604
+ offscreen.style.left = "-100%";
1605
+ offscreen.style.position = "absolute";
1606
+ offscreen.style.width = `${boundsForDragTarget.width}px`;
1607
+ offscreen.style.height = `${boundsForDragTarget.height}px`;
1608
+
1609
+ document.body.append(offscreen);
1610
+
1611
+ event.dataTransfer.setDragImage(
1612
+ offscreen,
1613
+ boundsForDragTarget.width / 2,
1614
+ boundsForDragTarget.height / 2
1615
+ );
1616
+
1617
+ window.setTimeout(() => {
1618
+ offscreen.remove();
1619
+ }, 0);
1620
+ }
1621
+ }
1622
+ } else {
1623
+ event.preventDefault();
1624
+ }
1625
+ },
1626
+ [
1627
+ isDraggable,
1628
+ isResizing,
1629
+ getMouseArgsForPosition,
1630
+ onDragStart,
1631
+ getBoundsForItem,
1632
+ theme,
1633
+ mappedColumns,
1634
+ spriteManager,
1635
+ drawHeaderCallback,
1636
+ getCellContent,
1637
+ imageLoader,
1638
+ renderStateProvider,
1639
+ getCellRenderer,
1640
+ ]
1641
+ );
1642
+ useEventListener("dragstart", onDragStartImpl, eventTargetRef?.current ?? null, false, false);
1643
+
1644
+ const activeDropTarget = React.useRef<Item | undefined>(undefined);
1645
+
1646
+ const onDragOverImpl = React.useCallback(
1647
+ (event: DragEvent) => {
1648
+ const canvas = ref.current;
1649
+ if (onDrop !== undefined) {
1650
+ // Need to preventDefault to allow drop
1651
+ event.preventDefault();
1652
+ }
1653
+
1654
+ if (canvas === null || onDragOverCell === undefined) {
1655
+ return;
1656
+ }
1657
+
1658
+ const args = getMouseArgsForPosition(canvas, event.clientX, event.clientY);
1659
+
1660
+ const [rawCol, row] = args.location;
1661
+ const col = rawCol - (firstColAccessible ? 0 : 1);
1662
+ const [activeCol, activeRow] = activeDropTarget.current ?? [];
1663
+
1664
+ if (activeCol !== col || activeRow !== row) {
1665
+ activeDropTarget.current = [col, row];
1666
+ onDragOverCell([col, row], event.dataTransfer);
1667
+ }
1668
+ },
1669
+ [firstColAccessible, getMouseArgsForPosition, onDragOverCell, onDrop]
1670
+ );
1671
+ useEventListener("dragover", onDragOverImpl, eventTargetRef?.current ?? null, false, false);
1672
+
1673
+ const onDragEndImpl = React.useCallback(() => {
1674
+ activeDropTarget.current = undefined;
1675
+ onDragEnd?.();
1676
+ }, [onDragEnd]);
1677
+ useEventListener("dragend", onDragEndImpl, eventTargetRef?.current ?? null, false, false);
1678
+
1679
+ const onDropImpl = React.useCallback(
1680
+ (event: DragEvent) => {
1681
+ const canvas = ref.current;
1682
+ if (canvas === null || onDrop === undefined) {
1683
+ return;
1684
+ }
1685
+
1686
+ // Default can mess up sometimes.
1687
+ event.preventDefault();
1688
+
1689
+ const args = getMouseArgsForPosition(canvas, event.clientX, event.clientY);
1690
+
1691
+ const [rawCol, row] = args.location;
1692
+ const col = rawCol - (firstColAccessible ? 0 : 1);
1693
+
1694
+ onDrop([col, row], event.dataTransfer);
1695
+ },
1696
+ [firstColAccessible, getMouseArgsForPosition, onDrop]
1697
+ );
1698
+ useEventListener("drop", onDropImpl, eventTargetRef?.current ?? null, false, false);
1699
+
1700
+ const onDragLeaveImpl = React.useCallback(() => {
1701
+ onDragLeave?.();
1702
+ }, [onDragLeave]);
1703
+ useEventListener("dragleave", onDragLeaveImpl, eventTargetRef?.current ?? null, false, false);
1704
+
1705
+ const selectionRef = React.useRef(selection);
1706
+ selectionRef.current = selection;
1707
+ const focusRef = React.useRef<HTMLElement | null>(null);
1708
+ const focusElement = React.useCallback(
1709
+ (el: HTMLElement | null) => {
1710
+ // We don't want to steal the focus if we don't currently own the focus.
1711
+ if (ref.current === null || !ref.current.contains(document.activeElement)) return;
1712
+ if (el === null && selectionRef.current.current !== undefined) {
1713
+ canvasRef?.current?.focus({
1714
+ preventScroll: true,
1715
+ });
1716
+ } else if (el !== null) {
1717
+ el.focus({
1718
+ preventScroll: true,
1719
+ });
1720
+ }
1721
+ focusRef.current = el;
1722
+ },
1723
+ [canvasRef]
1724
+ );
1725
+
1726
+ React.useImperativeHandle(
1727
+ forwardedRef,
1728
+ () => ({
1729
+ focus: () => {
1730
+ const el = focusRef.current;
1731
+ // The element in the ref may have been removed however our callback method ref
1732
+ // won't see the removal so bad things happen. Checking to see if the element is
1733
+ // no longer attached is enough to resolve the problem. In the future this
1734
+ // should be replaced with something much more robust.
1735
+ if (el === null || !document.contains(el)) {
1736
+ canvasRef?.current?.focus({
1737
+ preventScroll: true,
1738
+ });
1739
+ } else {
1740
+ el.focus({
1741
+ preventScroll: true,
1742
+ });
1743
+ }
1744
+ },
1745
+ getBounds: (col?: number, row?: number) => {
1746
+ if (canvasRef === undefined || canvasRef.current === null) {
1747
+ return undefined;
1748
+ }
1749
+
1750
+ return getBoundsForItem(canvasRef.current, col ?? 0, row ?? -1);
1751
+ },
1752
+ damage,
1753
+ getMouseArgsForPosition: (posX: number, posY: number, ev?: MouseEvent | TouchEvent) => {
1754
+ if (canvasRef === undefined || canvasRef.current === null) {
1755
+ return undefined;
1756
+ }
1757
+
1758
+ return getMouseArgsForPosition(canvasRef.current, posX, posY, ev);
1759
+ },
1760
+ }),
1761
+ [canvasRef, damage, getBoundsForItem, getMouseArgsForPosition]
1762
+ );
1763
+
1764
+ const lastFocusedSubdomNode = React.useRef<Item | undefined>(undefined);
1765
+
1766
+ const accessibilityTree = useDebouncedMemo(
1767
+ () => {
1768
+ if (width < 50 || experimental?.disableAccessibilityTree === true) return null;
1769
+ let effectiveCols = getEffectiveColumns(mappedColumns, cellXOffset, width, dragAndDropState, translateX);
1770
+ const colOffset = firstColAccessible ? 0 : -1;
1771
+ if (!firstColAccessible && effectiveCols[0]?.sourceIndex === 0) {
1772
+ effectiveCols = effectiveCols.slice(1);
1773
+ }
1774
+
1775
+ const [fCol, fRow] = selection.current?.cell ?? [];
1776
+ const range = selection.current?.range;
1777
+
1778
+ const visibleCols = effectiveCols.map(c => c.sourceIndex);
1779
+ const visibleRows = makeRange(cellYOffset, Math.min(rows, cellYOffset + accessibilityHeight));
1780
+
1781
+ // Maintain focus within grid if we own it but focused cell is outside visible viewport
1782
+ // and not rendered.
1783
+ if (
1784
+ fCol !== undefined &&
1785
+ fRow !== undefined &&
1786
+ !(visibleCols.includes(fCol) && visibleRows.includes(fRow))
1787
+ ) {
1788
+ focusElement(null);
1789
+ }
1790
+
1791
+ return (
1792
+ <table
1793
+ key="access-tree"
1794
+ role="grid"
1795
+ aria-rowcount={rows + 1}
1796
+ aria-multiselectable="true"
1797
+ aria-colcount={mappedColumns.length + colOffset}>
1798
+ <thead role="rowgroup">
1799
+ <tr role="row" aria-rowindex={1}>
1800
+ {effectiveCols.map(c => (
1801
+ <th
1802
+ role="columnheader"
1803
+ aria-selected={selection.columns.hasIndex(c.sourceIndex)}
1804
+ aria-colindex={c.sourceIndex + 1 + colOffset}
1805
+ tabIndex={-1}
1806
+ onFocus={e => {
1807
+ if (e.target === focusRef.current) return;
1808
+ return onCellFocused?.([c.sourceIndex, -1]);
1809
+ }}
1810
+ key={c.sourceIndex}>
1811
+ {c.title}
1812
+ </th>
1813
+ ))}
1814
+ </tr>
1815
+ </thead>
1816
+ <tbody role="rowgroup">
1817
+ {visibleRows.map(row => (
1818
+ <tr
1819
+ role="row"
1820
+ aria-selected={selection.rows.hasIndex(row)}
1821
+ key={row}
1822
+ aria-rowindex={row + 2}>
1823
+ {effectiveCols.map(c => {
1824
+ const col = c.sourceIndex;
1825
+ const key = packColRowToNumber(col, row);
1826
+ const focused = fCol === col && fRow === row;
1827
+ const selected =
1828
+ range !== undefined &&
1829
+ col >= range.x &&
1830
+ col < range.x + range.width &&
1831
+ row >= range.y &&
1832
+ row < range.y + range.height;
1833
+ const id = `glide-cell-${col}-${row}`;
1834
+ const location: Item = [col, row];
1835
+ const cellContent = getCellContent(location, true);
1836
+ return (
1837
+ <td
1838
+ key={key}
1839
+ role="gridcell"
1840
+ aria-colindex={col + 1 + colOffset}
1841
+ aria-selected={selected}
1842
+ aria-readonly={
1843
+ isInnerOnlyCell(cellContent) || !isReadWriteCell(cellContent)
1844
+ }
1845
+ id={id}
1846
+ data-testid={id}
1847
+ onClick={() => {
1848
+ const canvas = canvasRef?.current;
1849
+ if (canvas === null || canvas === undefined) return;
1850
+ return onKeyDown?.({
1851
+ bounds: getBoundsForItem(canvas, col, row),
1852
+ cancel: () => undefined,
1853
+ preventDefault: () => undefined,
1854
+ stopPropagation: () => undefined,
1855
+ ctrlKey: false,
1856
+ key: "Enter",
1857
+ keyCode: 13,
1858
+ metaKey: false,
1859
+ shiftKey: false,
1860
+ altKey: false,
1861
+ rawEvent: undefined,
1862
+ location,
1863
+ });
1864
+ }}
1865
+ onFocusCapture={e => {
1866
+ if (
1867
+ e.target === focusRef.current ||
1868
+ (lastFocusedSubdomNode.current?.[0] === col &&
1869
+ lastFocusedSubdomNode.current?.[1] === row)
1870
+ )
1871
+ return;
1872
+ lastFocusedSubdomNode.current = location;
1873
+ return onCellFocused?.(location);
1874
+ }}
1875
+ ref={focused ? focusElement : undefined}
1876
+ tabIndex={-1}>
1877
+ {getRowData(cellContent, getCellRenderer)}
1878
+ </td>
1879
+ );
1880
+ })}
1881
+ </tr>
1882
+ ))}
1883
+ </tbody>
1884
+ </table>
1885
+ );
1886
+ },
1887
+ [
1888
+ width,
1889
+ mappedColumns,
1890
+ cellXOffset,
1891
+ dragAndDropState,
1892
+ translateX,
1893
+ rows,
1894
+ cellYOffset,
1895
+ accessibilityHeight,
1896
+ selection,
1897
+ focusElement,
1898
+ getCellContent,
1899
+ canvasRef,
1900
+ onKeyDown,
1901
+ getBoundsForItem,
1902
+ onCellFocused,
1903
+ ],
1904
+ 200
1905
+ );
1906
+
1907
+ const opacityX =
1908
+ freezeColumns === 0 || !fixedShadowX ? 0 : cellXOffset > freezeColumns ? 1 : clamp(-translateX / 100, 0, 1);
1909
+
1910
+ const absoluteOffsetY = -cellYOffset * 32 + translateY;
1911
+ const opacityY = !fixedShadowY ? 0 : clamp(-absoluteOffsetY / 100, 0, 1);
1912
+
1913
+ const stickyShadow = React.useMemo(() => {
1914
+ if (!opacityX && !opacityY) {
1915
+ return null;
1916
+ }
1917
+
1918
+ const styleX: React.CSSProperties = {
1919
+ position: "absolute",
1920
+ top: 0,
1921
+ left: stickyX,
1922
+ width: width - stickyX,
1923
+ height: height,
1924
+ opacity: opacityX,
1925
+ pointerEvents: "none",
1926
+ transition: !smoothScrollX ? "opacity 0.2s" : undefined,
1927
+ boxShadow: "inset 13px 0 10px -13px rgba(0, 0, 0, 0.2)",
1928
+ };
1929
+
1930
+ const styleY: React.CSSProperties = {
1931
+ position: "absolute",
1932
+ top: totalHeaderHeight,
1933
+ left: 0,
1934
+ width: width,
1935
+ height: height,
1936
+ opacity: opacityY,
1937
+ pointerEvents: "none",
1938
+ transition: !smoothScrollY ? "opacity 0.2s" : undefined,
1939
+ boxShadow: "inset 0 13px 10px -13px rgba(0, 0, 0, 0.2)",
1940
+ };
1941
+
1942
+ return (
1943
+ <>
1944
+ {opacityX > 0 && <div id="shadow-x" style={styleX} />}
1945
+ {opacityY > 0 && <div id="shadow-y" style={styleY} />}
1946
+ </>
1947
+ );
1948
+ }, [opacityX, opacityY, stickyX, width, smoothScrollX, totalHeaderHeight, height, smoothScrollY]);
1949
+
1950
+ const overlayStyle = React.useMemo<React.CSSProperties>(
1951
+ () => ({
1952
+ position: "absolute",
1953
+ top: 0,
1954
+ left: 0,
1955
+ }),
1956
+ []
1957
+ );
1958
+
1959
+ return (
1960
+ <>
1961
+ <canvas
1962
+ data-testid="data-grid-canvas"
1963
+ tabIndex={0}
1964
+ onKeyDown={onKeyDownImpl}
1965
+ onKeyUp={onKeyUpImpl}
1966
+ onFocus={onCanvasFocused}
1967
+ onBlur={onCanvasBlur}
1968
+ ref={refImpl}
1969
+ style={style}>
1970
+ {accessibilityTree}
1971
+ </canvas>
1972
+ <canvas ref={overlayRef} style={overlayStyle} />
1973
+ {stickyShadow}
1974
+ </>
1975
+ );
1976
+ };
1977
+
1978
+ export default React.memo(React.forwardRef(DataGrid));