@svgrid/grid 2.6.22 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/CHANGELOG.md +88 -88
  2. package/README.md +199 -199
  3. package/dist/FlexRender.svelte +96 -96
  4. package/dist/GridFooter.svelte +181 -181
  5. package/dist/GridMenus.svelte +184 -6
  6. package/dist/SvAutoComplete.svelte +169 -165
  7. package/dist/SvAvatar.svelte +75 -75
  8. package/dist/SvCalendar.svelte +503 -503
  9. package/dist/SvCarousel.svelte +141 -141
  10. package/dist/SvCheckBox.svelte +102 -102
  11. package/dist/SvCircularProgress.svelte +109 -109
  12. package/dist/SvColorInput.svelte +181 -181
  13. package/dist/SvComboBox.svelte +279 -275
  14. package/dist/SvContextMenu.svelte +116 -116
  15. package/dist/SvCountryInput.svelte +163 -163
  16. package/dist/SvDateRangeInput.svelte +25 -3
  17. package/dist/SvDrawer.svelte +254 -254
  18. package/dist/SvDropDownList.svelte +378 -374
  19. package/dist/SvDurationInput.svelte +126 -126
  20. package/dist/SvField.svelte +293 -293
  21. package/dist/SvForm.svelte +437 -437
  22. package/dist/SvGrid.controller.svelte.d.ts +48 -1
  23. package/dist/SvGrid.controller.svelte.js +214 -52
  24. package/dist/SvGrid.css +221 -0
  25. package/dist/SvGrid.helpers.d.ts +55 -0
  26. package/dist/SvGrid.helpers.js +83 -0
  27. package/dist/SvGrid.svelte +145 -0
  28. package/dist/SvGrid.types.d.ts +105 -0
  29. package/dist/SvGridCellEditor.svelte +744 -662
  30. package/dist/SvGridChart.svelte +1716 -1716
  31. package/dist/SvGridChartPanel.svelte +485 -485
  32. package/dist/SvGridChartView.svelte +70 -70
  33. package/dist/SvGridDropdown.svelte +728 -728
  34. package/dist/SvGridSelect.svelte +270 -266
  35. package/dist/SvGridSelect.svelte.d.ts +1 -1
  36. package/dist/SvGroupCell.svelte +116 -116
  37. package/dist/SvListBox.svelte +334 -326
  38. package/dist/SvMaskedInput.svelte +122 -122
  39. package/dist/SvMenu.svelte +124 -124
  40. package/dist/SvMenuList.svelte +146 -146
  41. package/dist/SvMultiSelect.svelte +293 -289
  42. package/dist/SvMultiSelect.svelte.d.ts +1 -1
  43. package/dist/SvNumberInput.svelte +172 -168
  44. package/dist/SvOtpInput.svelte +158 -158
  45. package/dist/SvPasswordInput.svelte +151 -151
  46. package/dist/SvPhoneInput.svelte +133 -133
  47. package/dist/SvPopover.svelte +197 -197
  48. package/dist/SvProgress.svelte +116 -116
  49. package/dist/SvRadioGroup.svelte +107 -107
  50. package/dist/SvRating.svelte +112 -112
  51. package/dist/SvResult.svelte +73 -73
  52. package/dist/SvRichCell.svelte +125 -0
  53. package/dist/SvRichCell.svelte.d.ts +15 -0
  54. package/dist/SvRichText.svelte +211 -211
  55. package/dist/SvRowGroupPanel.svelte +170 -170
  56. package/dist/SvScrollArea.svelte +61 -61
  57. package/dist/SvSlider.svelte +203 -203
  58. package/dist/SvSwitchButton.svelte +108 -108
  59. package/dist/SvTagsInput.svelte +115 -115
  60. package/dist/SvTextArea.svelte +5 -1
  61. package/dist/SvTextInput.svelte +147 -147
  62. package/dist/SvTimePicker.svelte +245 -245
  63. package/dist/SvToaster.svelte +159 -159
  64. package/dist/SvToggleButton.svelte +85 -85
  65. package/dist/SvTooltip.svelte +161 -161
  66. package/dist/SvTour.svelte +208 -208
  67. package/dist/SvTree.svelte +444 -444
  68. package/dist/SvTreeSelect.svelte +239 -235
  69. package/dist/SvTreeSelect.svelte.d.ts +1 -1
  70. package/dist/builtin-editors.d.ts +2 -2
  71. package/dist/builtin-editors.js +19 -3
  72. package/dist/cdn/GridMenus-C4oLsJyj.js +600 -0
  73. package/dist/cdn/GridMenus-yEivjNwl.js +601 -0
  74. package/dist/cdn/SvDateRangeInput-Bh0A0JkF.js +199 -0
  75. package/dist/cdn/SvDateRangeInput-DflbiP7N.js +198 -0
  76. package/dist/cdn/SvDateTimePicker-BWwpfB_o.js +812 -0
  77. package/dist/cdn/SvDateTimePicker-Bivn8dAP.js +816 -0
  78. package/dist/cdn/SvGridCellEditor-AXL8cHGO.js +550 -0
  79. package/dist/cdn/SvGridCellEditor-Ba7rY3eu.js +549 -0
  80. package/dist/cdn/{SvGridChart-BwVos976.js → SvGridChart-Bs2GIR2Q.js} +1 -1
  81. package/dist/cdn/{SvGridChart-BEJmNNx9.js → SvGridChart-CwhFz7GV.js} +1 -1
  82. package/dist/cdn/{SvGridChartPanel-BOknOkrP.js → SvGridChartPanel-1WXuStzM.js} +1 -1
  83. package/dist/cdn/{SvGridChartPanel-D2PjII4O.js → SvGridChartPanel-e5_nqNP9.js} +1 -1
  84. package/dist/cdn/{SvGridChartView-00LPUHL1.js → SvGridChartView-SmPW10dI.js} +1 -1
  85. package/dist/cdn/{SvGridChartView-BhUEJ5ki.js → SvGridChartView-eSPuJE6g.js} +1 -1
  86. package/dist/cdn/{SvGridDropdown-D0VdjeR8.js → SvGridDropdown-B1ZcLpgs.js} +1 -1
  87. package/dist/cdn/{SvGridDropdown-D13MtJ2j.js → SvGridDropdown-CtdbHcIS.js} +1 -1
  88. package/dist/cdn/date-format-CcP1tafP.js +1395 -0
  89. package/dist/cdn/date-format-DZT7T1wf.js +1393 -0
  90. package/dist/cdn/{editor-registry-CiI0xlKg.js → editor-registry-BhgE3S84.js} +51 -25
  91. package/dist/cdn/{src-C9Hihx1W.js → src-COC0vnpg.js} +7233 -6701
  92. package/dist/cdn/{src-D1lXwq1l.js → src-pYGV2rMR.js} +5747 -5215
  93. package/dist/cdn/svgrid.js +15 -13
  94. package/dist/cdn/svgrid.svelte-external.js +15 -13
  95. package/dist/cell-values.d.ts +16 -0
  96. package/dist/cell-values.js +28 -0
  97. package/dist/chart-export.js +8 -8
  98. package/dist/clipboard.d.ts +22 -0
  99. package/dist/clipboard.js +405 -27
  100. package/dist/editing.js +12 -7
  101. package/dist/editors/cell-editors.d.ts +11 -0
  102. package/dist/editors/cell-editors.js +18 -1
  103. package/dist/grid-messages.d.ts +15 -0
  104. package/dist/grid-messages.js +15 -0
  105. package/dist/index.d.ts +4 -0
  106. package/dist/index.js +4 -0
  107. package/dist/list-option.d.ts +6 -0
  108. package/dist/menus.js +40 -7
  109. package/dist/sanitize-html.d.ts +37 -0
  110. package/dist/sanitize-html.js +234 -0
  111. package/dist/selection-bar-view.svelte.d.ts +25 -0
  112. package/dist/selection-bar-view.svelte.js +13 -0
  113. package/dist/selection.d.ts +2 -1
  114. package/dist/selection.js +129 -13
  115. package/package.json +11 -11
  116. package/src/FlexRender.svelte +96 -96
  117. package/src/GridFooter.svelte +181 -181
  118. package/src/GridMenus.svelte +184 -6
  119. package/src/SvAutoComplete.svelte +169 -165
  120. package/src/SvAvatar.svelte +75 -75
  121. package/src/SvCalendar.svelte +503 -503
  122. package/src/SvCalendar.test.ts +226 -226
  123. package/src/SvCarousel.svelte +141 -141
  124. package/src/SvCheckBox.svelte +102 -102
  125. package/src/SvCircularProgress.svelte +109 -109
  126. package/src/SvColorInput.svelte +181 -181
  127. package/src/SvComboBox.svelte +279 -275
  128. package/src/SvContextMenu.svelte +116 -116
  129. package/src/SvCountryInput.svelte +163 -163
  130. package/src/SvDateRangeInput.svelte +25 -3
  131. package/src/SvDrawer.svelte +254 -254
  132. package/src/SvDropDownList.svelte +378 -374
  133. package/src/SvDurationInput.svelte +126 -126
  134. package/src/SvField.svelte +293 -293
  135. package/src/SvForm.svelte +437 -437
  136. package/src/SvForm.test.ts +411 -411
  137. package/src/SvGrid.controller.svelte.ts +251 -61
  138. package/src/SvGrid.css +221 -0
  139. package/src/SvGrid.helpers.ts +87 -0
  140. package/src/SvGrid.svelte +145 -0
  141. package/src/SvGrid.types.ts +2092 -1980
  142. package/src/SvGridCellEditor.svelte +744 -662
  143. package/src/SvGridChart.svelte +1716 -1716
  144. package/src/SvGridChartPanel.svelte +485 -485
  145. package/src/SvGridChartView.svelte +70 -70
  146. package/src/SvGridDropdown.svelte +728 -728
  147. package/src/SvGridSelect.svelte +270 -266
  148. package/src/SvGroupCell.svelte +116 -116
  149. package/src/SvListBox.svelte +334 -326
  150. package/src/SvMaskedInput.svelte +122 -122
  151. package/src/SvMenu.svelte +124 -124
  152. package/src/SvMenu.test.ts +97 -97
  153. package/src/SvMenuList.svelte +146 -146
  154. package/src/SvMultiSelect.svelte +293 -289
  155. package/src/SvNumberInput.svelte +172 -168
  156. package/src/SvOtpInput.svelte +158 -158
  157. package/src/SvPasswordInput.svelte +151 -151
  158. package/src/SvPhoneInput.svelte +133 -133
  159. package/src/SvPopover.svelte +197 -197
  160. package/src/SvProgress.svelte +116 -116
  161. package/src/SvRadioGroup.svelte +107 -107
  162. package/src/SvRating.svelte +112 -112
  163. package/src/SvResult.svelte +73 -73
  164. package/src/SvRichCell.svelte +125 -0
  165. package/src/SvRichText.svelte +211 -211
  166. package/src/SvRowGroupPanel.svelte +170 -170
  167. package/src/SvScrollArea.svelte +61 -61
  168. package/src/SvSlider.svelte +203 -203
  169. package/src/SvSwitchButton.svelte +108 -108
  170. package/src/SvTagsInput.svelte +115 -115
  171. package/src/SvTextArea.svelte +5 -1
  172. package/src/SvTextInput.svelte +147 -147
  173. package/src/SvTimePicker.svelte +245 -245
  174. package/src/SvToaster.svelte +159 -159
  175. package/src/SvToaster.test.ts +95 -95
  176. package/src/SvToggleButton.svelte +85 -85
  177. package/src/SvTooltip.svelte +161 -161
  178. package/src/SvTour.svelte +208 -208
  179. package/src/SvTree.svelte +444 -444
  180. package/src/SvTreeSelect.svelte +239 -235
  181. package/src/a11y/dismissable.test.ts +119 -119
  182. package/src/a11y/dismissable.ts +114 -114
  183. package/src/a11y.contract.test.ts +49 -49
  184. package/src/a11y.test.ts +59 -59
  185. package/src/a11y.ts +61 -61
  186. package/src/ai.test.ts +502 -502
  187. package/src/ai.ts +1419 -1419
  188. package/src/build-api.coverage.test.ts +633 -633
  189. package/src/build-api.ts +846 -846
  190. package/src/builtin-editors.grid.test.ts +83 -83
  191. package/src/builtin-editors.test.ts +18 -1
  192. package/src/builtin-editors.ts +19 -3
  193. package/src/cell-formatting.ts +171 -171
  194. package/src/cell-render.test.ts +513 -513
  195. package/src/cell-render.ts +496 -496
  196. package/src/cell-values.ts +148 -118
  197. package/src/chart-export.ts +202 -202
  198. package/src/chart-view.svelte.ts +36 -36
  199. package/src/chart.ts +2321 -2321
  200. package/src/clipboard.test.ts +93 -20
  201. package/src/clipboard.ts +433 -33
  202. package/src/collaboration.test.ts +104 -104
  203. package/src/collaboration.ts +167 -167
  204. package/src/column-groups.ts +78 -78
  205. package/src/core.performance.test.ts +30 -30
  206. package/src/core.ts +1865 -1865
  207. package/src/createAutocomplete.svelte.ts +132 -132
  208. package/src/createCombobox.svelte.ts +191 -191
  209. package/src/createCountryInput.svelte.ts +157 -157
  210. package/src/createDropdownList.svelte.ts +168 -168
  211. package/src/createForm.svelte.ts +386 -386
  212. package/src/createGrid.svelte.ts +42 -42
  213. package/src/createGrid.test.ts +10 -10
  214. package/src/createGridState.svelte.ts +17 -17
  215. package/src/createListbox.svelte.ts +250 -250
  216. package/src/createMenu.svelte.ts +224 -224
  217. package/src/createPopoverSelect.svelte.ts +213 -213
  218. package/src/createSlider.svelte.ts +191 -191
  219. package/src/createTooltip.svelte.ts +144 -144
  220. package/src/createTree.svelte.ts +322 -322
  221. package/src/date-string-column.test.ts +87 -0
  222. package/src/datetime/date-core.ts +206 -206
  223. package/src/datetime/date-restrict.ts +61 -61
  224. package/src/datetime/timezone.ts +135 -135
  225. package/src/dock-manager-model.ts +596 -596
  226. package/src/dock-model.ts +374 -374
  227. package/src/editing.test.ts +974 -949
  228. package/src/editing.ts +609 -606
  229. package/src/editor-block-prop.test.ts +132 -0
  230. package/src/editor-contract.ts +171 -171
  231. package/src/editor-registry.grid.test.ts +144 -144
  232. package/src/editor-registry.ts +122 -122
  233. package/src/editors/cell-editors.ts +27 -1
  234. package/src/export-data-api.test.ts +126 -126
  235. package/src/export-format.test.ts +107 -107
  236. package/src/export-format.ts +601 -601
  237. package/src/filter-operators.ts +160 -160
  238. package/src/filtering/excel-filters.ts +325 -325
  239. package/src/flex-render.ts +3 -3
  240. package/src/form-field.ts +127 -127
  241. package/src/grid-messages.ts +34 -0
  242. package/src/group-display.test.ts +167 -167
  243. package/src/group-display.ts +200 -200
  244. package/src/headless.ts +87 -87
  245. package/src/index.ts +13 -0
  246. package/src/js-scroller.svelte.ts +173 -173
  247. package/src/keyboard-handlers.ts +270 -270
  248. package/src/keyboard.test.ts +59 -59
  249. package/src/keyboard.ts +97 -97
  250. package/src/list-nav.test.ts +49 -49
  251. package/src/list-nav.ts +29 -29
  252. package/src/list-option.test.ts +56 -56
  253. package/src/list-option.ts +179 -173
  254. package/src/menus.test.ts +43 -0
  255. package/src/menus.ts +597 -567
  256. package/src/merge-objects.ts +48 -48
  257. package/src/move-cells.test.ts +850 -0
  258. package/src/number-editor-literal.test.ts +84 -0
  259. package/src/number-editor.grid.test.ts +160 -0
  260. package/src/overlays.test.ts +90 -90
  261. package/src/positioning.ts +268 -268
  262. package/src/render-component.ts +28 -28
  263. package/src/row-drag-touch.ts +211 -211
  264. package/src/row-drag.test.ts +353 -353
  265. package/src/row-drag.ts +415 -415
  266. package/src/row-resize.test.ts +524 -524
  267. package/src/row-resize.ts +228 -228
  268. package/src/sanitize-html.test.ts +182 -0
  269. package/src/sanitize-html.ts +235 -0
  270. package/src/scheduler-ical.ts +181 -181
  271. package/src/scheduler-model.test.ts +562 -562
  272. package/src/scheduler-model.ts +873 -873
  273. package/src/selection-bar-view.svelte.ts +36 -0
  274. package/src/selection.test.ts +900 -743
  275. package/src/selection.ts +131 -13
  276. package/src/server-data-source.test.ts +383 -383
  277. package/src/server-data-source.ts +469 -469
  278. package/src/sparkline.test.ts +68 -68
  279. package/src/sparkline.ts +169 -169
  280. package/src/spreadsheet.test.ts +488 -488
  281. package/src/spreadsheet.ts +312 -312
  282. package/src/static-functions.ts +11 -11
  283. package/src/subscribe.ts +38 -38
  284. package/src/summaries.ts +113 -113
  285. package/src/svgrid-wrapper.types.ts +563 -563
  286. package/src/svgrid.async-editor-options.test.ts +273 -273
  287. package/src/svgrid.auto-row-height.test.ts +204 -204
  288. package/src/svgrid.behavior.test.ts +910 -910
  289. package/src/svgrid.charting.test.ts +534 -534
  290. package/src/svgrid.comments-autocomplete.test.ts +127 -127
  291. package/src/svgrid.context-menu.test.ts +147 -147
  292. package/src/svgrid.features.test.ts +157 -157
  293. package/src/svgrid.filter-depth.test.ts +163 -163
  294. package/src/svgrid.filter-menu-listbox.svelte.test.ts +377 -331
  295. package/src/svgrid.filter-menu-scroll.test.ts +112 -112
  296. package/src/svgrid.grand-total.test.ts +188 -188
  297. package/src/svgrid.group-display-mode.test.ts +171 -171
  298. package/src/svgrid.group-footers.test.ts +121 -121
  299. package/src/svgrid.group-pagination.test.ts +153 -153
  300. package/src/svgrid.in-suggest-snapshot.svelte.test.ts +91 -0
  301. package/src/svgrid.menu-scroll-close.test.ts +204 -0
  302. package/src/svgrid.new-features.wrapper.test.ts +251 -251
  303. package/src/svgrid.selection-bar-seam.test.ts +185 -0
  304. package/src/svgrid.tree-data.test.ts +186 -186
  305. package/src/svgrid.upsell-license.test.ts +117 -0
  306. package/src/svgrid.wrapper.test.ts +63 -63
  307. package/src/svgriddropdown.async-panel.svelte.test.ts +195 -195
  308. package/src/test-setup.ts +62 -62
  309. package/src/themes/index.ts +288 -288
  310. package/src/toast-store.svelte.ts +250 -250
  311. package/src/toast-store.test.ts +147 -147
  312. package/src/tree-row-model.test.ts +168 -168
  313. package/src/ui-buttons.test.ts +144 -144
  314. package/src/ui-inputs.test.ts +118 -118
  315. package/src/ui-localization.test.ts +113 -113
  316. package/src/ui-range.test.ts +70 -70
  317. package/src/ui-selection.test.ts +155 -155
  318. package/src/ui-tier1.test.ts +142 -142
  319. package/src/virtual.test.ts +88 -88
  320. package/src/virtualization/column-virtualizer.test.ts +27 -27
  321. package/src/virtualization/column-virtualizer.ts +30 -30
  322. package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
  323. package/src/virtualization/types.ts +30 -30
  324. package/src/virtualization/virtualizer.test.ts +47 -47
  325. package/src/virtualization/virtualizer.ts +322 -322
  326. package/dist/cdn/GridMenus-BuoBPqxx.js +0 -493
  327. package/dist/cdn/GridMenus-n4llxoOI.js +0 -494
  328. package/dist/cdn/SvDateTimePicker-CHnUkWcH.js +0 -2206
  329. package/dist/cdn/SvDateTimePicker-CRQH_U7E.js +0 -2201
  330. package/dist/cdn/SvGridCellEditor-BGUCzuPB.js +0 -523
  331. package/dist/cdn/SvGridCellEditor-G8IMWIws.js +0 -522
package/dist/selection.js CHANGED
@@ -224,15 +224,21 @@ export function createSelection(ctx) {
224
224
  * that contains the cell are returned (active range checked last so its
225
225
  * outline wins on overlap). Returns null when the cell is in no range.
226
226
  */
227
+ /** Could `getSelectionRects()` return anything? An anchored active range or
228
+ * a committed one is the only way a rect can exist, and both are plain
229
+ * property reads - so this is the cheap guard in front of anything that
230
+ * would otherwise allocate a rect array to discover there is nothing. */
231
+ function hasAnySelectionRect() {
232
+ const active = ctx.selectionRange;
233
+ const committed = ctx.selectionRanges;
234
+ return Boolean(committed?.length) || Boolean(active?.anchor && active?.focus);
235
+ }
227
236
  function getCellRangeEdges(rowIndex, colIndex) {
228
237
  // Bail before `getSelectionRects()`, which allocates an array and resolves
229
238
  // every range. This runs once per rendered CELL on every render - about 250
230
239
  // times per frame on a default grid - and with nothing selected it did all
231
- // that work to return null every time. An anchored active range or a
232
- // committed one is the only way any rect can exist.
233
- const active = ctx.selectionRange;
234
- const committed = ctx.selectionRanges;
235
- if (!committed?.length && !(active?.anchor && active?.focus))
240
+ // that work to return null every time.
241
+ if (!hasAnySelectionRect())
236
242
  return null;
237
243
  for (const rect of getSelectionRects()) {
238
244
  if (rowIndex < rect.minRow ||
@@ -250,10 +256,40 @@ export function createSelection(ctx) {
250
256
  }
251
257
  return null;
252
258
  }
259
+ /**
260
+ * The rectangle a drag is currently promising, or null when no drag is in
261
+ * flight. A fill grows the source rectangle out to the pointer; a move
262
+ * detaches an identically-sized rectangle and drops it at the offset the
263
+ * pointer has travelled. Both feed the same preview tint and marquee, so a
264
+ * range move looks like the fill handle users already know.
265
+ */
266
+ function dragPreviewRect() {
267
+ const m = ctx.moveDrag;
268
+ if (m)
269
+ return ctx.moveDestRect(m);
270
+ const d = ctx.fillDrag;
271
+ if (!d)
272
+ return null;
273
+ return {
274
+ minRow: Math.min(d.sourceMinRow, d.targetRow),
275
+ maxRow: Math.max(d.sourceMaxRow, d.targetRow),
276
+ minCol: Math.min(d.sourceMinCol, d.targetCol),
277
+ maxCol: Math.max(d.sourceMaxCol, d.targetCol),
278
+ };
279
+ }
253
280
  /** Returns true when the given cell is inside the fill-drag preview
254
281
  * range BUT outside the original source range. Used to paint a
255
282
  * dashed-outline preview while the user is dragging the handle. */
256
283
  function isInFillPreview(rowIndex, colIndex) {
284
+ if (ctx.moveDrag) {
285
+ const rect = dragPreviewRect();
286
+ if (!rect)
287
+ return false;
288
+ return (rowIndex >= rect.minRow &&
289
+ rowIndex <= rect.maxRow &&
290
+ colIndex >= rect.minCol &&
291
+ colIndex <= rect.maxCol);
292
+ }
257
293
  const d = ctx.fillDrag;
258
294
  if (!d)
259
295
  return false;
@@ -279,13 +315,14 @@ export function createSelection(ctx) {
279
315
  * border. Returns null when the cell isn't on the rectangle's boundary.
280
316
  */
281
317
  function fillMarqueeEdges(rowIndex, colIndex) {
282
- const d = ctx.fillDrag;
283
- if (!d)
318
+ // Cheap bail before the shared rect helper, which allocates: this runs
319
+ // once per rendered cell and no drag is in flight almost all the time.
320
+ if (!ctx.fillDrag && !ctx.moveDrag)
284
321
  return null;
285
- const minR = Math.min(d.sourceMinRow, d.targetRow);
286
- const maxR = Math.max(d.sourceMaxRow, d.targetRow);
287
- const minC = Math.min(d.sourceMinCol, d.targetCol);
288
- const maxC = Math.max(d.sourceMaxCol, d.targetCol);
322
+ const rect = dragPreviewRect();
323
+ if (!rect)
324
+ return null;
325
+ const { minRow: minR, maxRow: maxR, minCol: minC, maxCol: maxC } = rect;
289
326
  if (rowIndex < minR || rowIndex > maxR || colIndex < minC || colIndex > maxC) {
290
327
  return null;
291
328
  }
@@ -309,6 +346,18 @@ export function createSelection(ctx) {
309
346
  const column = ctx.allColumns[colIndex];
310
347
  if (!row || !column || isGroupRow(row))
311
348
  return;
349
+ // A pointerdown on the outer few pixels of a selection border grabs the
350
+ // range to move it. Checked before anything else, because everything below
351
+ // would first collapse the selection this drag is about to relocate.
352
+ // Returns false unless the pointer really was on the strip, so a click
353
+ // anywhere further inside falls straight through to the old behaviour.
354
+ if (ctx.startMoveDrag(event, rowIndex, colIndex)) {
355
+ // A grab that never moves still ends in a `click` on the cell under the
356
+ // border. Left alone that click would collapse the range the user was
357
+ // clearly reaching for, and on a checkbox column it would flip the value.
358
+ moveGrabSwallowsClick = true;
359
+ return;
360
+ }
312
361
  // NOTE: we no longer bail for checkbox columns. Bailing here meant a
313
362
  // range drag could never START on a checkbox cell. A plain click still
314
363
  // toggles the checkbox via onCellClick (a same-cell click), while a
@@ -344,27 +393,93 @@ export function createSelection(ctx) {
344
393
  extendSelection(rowIndex, colIndex);
345
394
  setActiveCell(rowIndex, colIndex);
346
395
  }
347
- function endDragSelection() {
396
+ /** `event` is the window `pointerup` when this comes from the real gesture,
397
+ * and absent when `onWindowPointerMove` calls it to recover from a release
398
+ * it never saw. A range move reads its copy modifier from it, so holding
399
+ * Ctrl between the last movement and the release still copies. */
400
+ function endDragSelection(event) {
348
401
  ctx.isDraggingSelection = false;
402
+ // Every drag shares one edge-scroll loop, and it exits on its own once no
403
+ // drag is live - but stopping it here cancels the pending frame rather
404
+ // than letting one more fire after the gesture is over.
405
+ ctx.stopEdgeScroll();
349
406
  // Also commit a fill-handle drag if one was in progress - the user
350
407
  // released the mouse, time to apply the pattern.
351
408
  if (ctx.fillDrag)
352
409
  ctx.onFillPointerUp();
410
+ if (ctx.moveDrag)
411
+ ctx.onMovePointerUp(event);
353
412
  }
354
413
  function onWindowPointerMove(event) {
414
+ if (ctx.moveDrag) {
415
+ ctx.onMovePointerMove(event);
416
+ return;
417
+ }
355
418
  if (ctx.fillDrag) {
356
419
  ctx.onFillPointerMove(event);
357
420
  return;
358
421
  }
359
- if (!ctx.isDraggingSelection)
422
+ if (!ctx.isDraggingSelection) {
423
+ updateMoveGrabHover(event);
360
424
  return;
425
+ }
361
426
  // Safety: if no mouse button is held the drag is over (we may have
362
427
  // missed pointerup because the user lifted outside the window).
363
428
  if (event.buttons === 0) {
364
429
  endDragSelection();
430
+ return;
365
431
  }
432
+ // Drag-select past the viewport edge scrolls the grid, same as the fill
433
+ // and move drags. Without it a range can only ever cover what was already
434
+ // on screen when the drag started. `onCellPointerEnter` keeps extending
435
+ // the range for cells the pointer actually crosses; this covers the case
436
+ // where the pointer has stopped at the edge and the CELLS are moving.
437
+ ctx.trackEdgeScroll(event);
366
438
  }
439
+ /**
440
+ * Switch the grid to a move cursor while the pointer sits on the grab strip
441
+ * of a selection border - without it the feature is invisible, since the
442
+ * border is painted, not a hit target.
443
+ *
444
+ * This runs on every window pointermove, so the order of the guards is the
445
+ * point: `moveCellsEffective` and the already-hovering flag are plain
446
+ * property reads, and `isOnMoveGrabStrip` bails on `getCellRangeEdges`
447
+ * before measuring anything when no range is selected.
448
+ */
449
+ function updateMoveGrabHover(event) {
450
+ const wasHovering = ctx.moveGrabHover;
451
+ // Two property reads before anything touches the DOM. `closest()` walks
452
+ // ancestors on EVERY pointer move over the page, so it has to sit behind
453
+ // both "the feature is on" and "there is a range to grab".
454
+ if (!ctx.moveCellsEffective || !hasAnySelectionRect()) {
455
+ if (wasHovering)
456
+ ctx.moveGrabHover = false;
457
+ return;
458
+ }
459
+ const target = event.target;
460
+ const cell = target?.closest?.("td[data-svgrid-row][data-svgrid-col]");
461
+ let hovering = false;
462
+ if (cell) {
463
+ const r = Number(cell.dataset.svgridRow);
464
+ const c = Number(cell.dataset.svgridCol);
465
+ if (Number.isFinite(r) && Number.isFinite(c)) {
466
+ hovering = ctx.isOnMoveGrabStrip(cell, r, c, event.clientX, event.clientY);
467
+ }
468
+ }
469
+ if (hovering !== wasHovering)
470
+ ctx.moveGrabHover = hovering;
471
+ }
472
+ /** Set when a pointerdown started a range move, so the `click` that
473
+ * follows a zero-distance grab is discarded instead of collapsing the
474
+ * selection it grabbed. One gesture, one flag - cleared on the next click
475
+ * whether or not the grab turned into a real drag. */
476
+ let moveGrabSwallowsClick = false;
367
477
  function onCellClick(rowIndex, colIndex) {
478
+ if (moveGrabSwallowsClick) {
479
+ moveGrabSwallowsClick = false;
480
+ ctx.gridRootEl?.focus({ preventScroll: true });
481
+ return;
482
+ }
368
483
  const row = ctx.allRows[rowIndex];
369
484
  const column = ctx.allColumns[colIndex];
370
485
  if (!row || !column)
@@ -450,6 +565,7 @@ export function createSelection(ctx) {
450
565
  fillMarqueeEdges,
451
566
  getSelectionRects,
452
567
  isInFillPreview,
568
+ dragPreviewRect,
453
569
  findColumnById,
454
570
  onCellPointerDown,
455
571
  onCellPointerEnter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svgrid/grid",
3
- "version": "2.6.22",
3
+ "version": "2.7.0",
4
4
  "description": "Svelte 5-native data grid and data table. Headless-first engine with virtual scrolling for 100k+ rows, Excel-style filtering, inline editing, grouping, tree data, pivot, and server-side data. Drop-in <SvGrid> component. TypeScript, SSR-ready.",
5
5
  "author": "jQWidgets <boikom@jqwidgets.com>",
6
6
  "license": "MIT",
@@ -116,15 +116,6 @@
116
116
  "themes",
117
117
  "CHANGELOG.md"
118
118
  ],
119
- "scripts": {
120
- "clean": "rimraf ./build && rimraf ./dist",
121
- "test:eslint": "eslint ./src",
122
- "test:types": "svelte-check --tsconfig ./tsconfig.json",
123
- "test:lib": "vitest run --coverage",
124
- "test:build": "publint --strict",
125
- "build": "svelte-package --input ./src --output ./dist && node ../../tools/strip-dist-tests.mjs ./dist && node ../../tools/add-dist-extensions.mjs ./dist && node ./scripts/build-cdn.mjs && node ./scripts/build-themes.mjs",
126
- "lint": "eslint ./src"
127
- },
128
119
  "devDependencies": {
129
120
  "@sveltejs/package": "^2.5.7",
130
121
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
@@ -141,5 +132,14 @@
141
132
  },
142
133
  "dependencies": {
143
134
  "esm-env": "^1.2.2"
135
+ },
136
+ "scripts": {
137
+ "clean": "rimraf ./build && rimraf ./dist",
138
+ "test:eslint": "eslint ./src",
139
+ "test:types": "svelte-check --tsconfig ./tsconfig.json",
140
+ "test:lib": "vitest run --coverage",
141
+ "test:build": "publint --strict",
142
+ "build": "svelte-package --input ./src --output ./dist && node ../../tools/strip-dist-tests.mjs ./dist && node ../../tools/add-dist-extensions.mjs ./dist && node ./scripts/build-cdn.mjs && node ./scripts/build-themes.mjs",
143
+ "lint": "eslint ./src"
144
144
  }
145
- }
145
+ }
@@ -1,96 +1,96 @@
1
- <script
2
- lang="ts"
3
- generics="TData extends RowData"
4
- >
5
- import { isFunction } from './core'
6
- import {
7
- RenderComponentConfig,
8
- RenderSnippetConfig,
9
- } from './render-component'
10
- import type {
11
- Cell,
12
- CellContext,
13
- ColumnDefTemplate,
14
- Header,
15
- HeaderContext,
16
- RowData,
17
- } from './core'
18
-
19
- type Props =
20
- | {
21
- content?: ColumnDefTemplate<
22
- | HeaderContext<TData>
23
- | CellContext<TData>
24
- >
25
- context:
26
- | HeaderContext<TData>
27
- | CellContext<TData>
28
- cell?: never
29
- header?: never
30
- footer?: never
31
- }
32
- | {
33
- cell: Cell<TData>
34
- content?: never
35
- context?: never
36
- header?: never
37
- footer?: never
38
- }
39
- | {
40
- header: Header<TData>
41
- content?: never
42
- context?: never
43
- cell?: never
44
- footer?: never
45
- }
46
- | {
47
- footer: Header<TData>
48
- content?: never
49
- context?: never
50
- cell?: never
51
- header?: never
52
- }
53
-
54
- let props: Props = $props()
55
-
56
- const resolved = $derived.by(() => {
57
- if ('cell' in props && props.cell) {
58
- return {
59
- content: props.cell.column.columnDef.cell,
60
- context: props.cell.getContext(),
61
- }
62
- }
63
- if ('header' in props && props.header) {
64
- return {
65
- content: props.header.column.columnDef.header,
66
- context: props.header.getContext(),
67
- }
68
- }
69
- if ('footer' in props && props.footer) {
70
- return {
71
- content: props.footer.column.columnDef.footer,
72
- context: props.footer.getContext(),
73
- }
74
- }
75
- return {
76
- content: props.content,
77
- context: props.context,
78
- }
79
- })
80
-
81
- const result = $derived(
82
- isFunction(resolved.content)
83
- ? resolved.content(resolved.context as any)
84
- : undefined,
85
- )
86
- </script>
87
-
88
- {#if typeof resolved.content === 'string'}
89
- {resolved.content}
90
- {:else if result instanceof RenderComponentConfig}
91
- <result.component {...result.props} />
92
- {:else if result instanceof RenderSnippetConfig}
93
- {@render result.snippet(result.params)}
94
- {:else if result !== undefined}
95
- {result}
96
- {/if}
1
+ <script
2
+ lang="ts"
3
+ generics="TData extends RowData"
4
+ >
5
+ import { isFunction } from './core'
6
+ import {
7
+ RenderComponentConfig,
8
+ RenderSnippetConfig,
9
+ } from './render-component'
10
+ import type {
11
+ Cell,
12
+ CellContext,
13
+ ColumnDefTemplate,
14
+ Header,
15
+ HeaderContext,
16
+ RowData,
17
+ } from './core'
18
+
19
+ type Props =
20
+ | {
21
+ content?: ColumnDefTemplate<
22
+ | HeaderContext<TData>
23
+ | CellContext<TData>
24
+ >
25
+ context:
26
+ | HeaderContext<TData>
27
+ | CellContext<TData>
28
+ cell?: never
29
+ header?: never
30
+ footer?: never
31
+ }
32
+ | {
33
+ cell: Cell<TData>
34
+ content?: never
35
+ context?: never
36
+ header?: never
37
+ footer?: never
38
+ }
39
+ | {
40
+ header: Header<TData>
41
+ content?: never
42
+ context?: never
43
+ cell?: never
44
+ footer?: never
45
+ }
46
+ | {
47
+ footer: Header<TData>
48
+ content?: never
49
+ context?: never
50
+ cell?: never
51
+ header?: never
52
+ }
53
+
54
+ let props: Props = $props()
55
+
56
+ const resolved = $derived.by(() => {
57
+ if ('cell' in props && props.cell) {
58
+ return {
59
+ content: props.cell.column.columnDef.cell,
60
+ context: props.cell.getContext(),
61
+ }
62
+ }
63
+ if ('header' in props && props.header) {
64
+ return {
65
+ content: props.header.column.columnDef.header,
66
+ context: props.header.getContext(),
67
+ }
68
+ }
69
+ if ('footer' in props && props.footer) {
70
+ return {
71
+ content: props.footer.column.columnDef.footer,
72
+ context: props.footer.getContext(),
73
+ }
74
+ }
75
+ return {
76
+ content: props.content,
77
+ context: props.context,
78
+ }
79
+ })
80
+
81
+ const result = $derived(
82
+ isFunction(resolved.content)
83
+ ? resolved.content(resolved.context as any)
84
+ : undefined,
85
+ )
86
+ </script>
87
+
88
+ {#if typeof resolved.content === 'string'}
89
+ {resolved.content}
90
+ {:else if result instanceof RenderComponentConfig}
91
+ <result.component {...result.props} />
92
+ {:else if result instanceof RenderSnippetConfig}
93
+ {@render result.snippet(result.params)}
94
+ {:else if result !== undefined}
95
+ {result}
96
+ {/if}