@svgrid/grid 2.2.32 → 2.4.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 (405) hide show
  1. package/README.md +199 -199
  2. package/dist/DockNodeView.svelte +1 -1
  3. package/dist/FlexRender.svelte +96 -96
  4. package/dist/GridFooter.svelte +178 -179
  5. package/dist/GridMenus.svelte +705 -782
  6. package/dist/SvAutoComplete.svelte +165 -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 +275 -275
  14. package/dist/SvContextMenu.svelte +116 -116
  15. package/dist/SvCountryInput.svelte +160 -160
  16. package/dist/SvDateRangeInput.svelte +1 -1
  17. package/dist/SvDrawer.svelte +254 -254
  18. package/dist/SvDropDownList.svelte +374 -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.css +2814 -2804
  23. package/dist/SvGrid.svelte +3490 -3513
  24. package/dist/SvGridChart.svelte +1716 -1724
  25. package/dist/SvGridChartPanel.svelte +485 -485
  26. package/dist/SvGridChartView.svelte +70 -70
  27. package/dist/SvGridDropdown.svelte +728 -728
  28. package/dist/SvGridSelect.svelte +266 -268
  29. package/dist/SvGroupCell.svelte +116 -116
  30. package/dist/SvKbd.svelte +1 -1
  31. package/dist/SvList.svelte +1 -1
  32. package/dist/SvListBox.svelte +326 -326
  33. package/dist/SvMaskedInput.svelte +122 -122
  34. package/dist/SvMenu.svelte +124 -124
  35. package/dist/SvMenuList.svelte +146 -146
  36. package/dist/SvMenubar.svelte +1 -1
  37. package/dist/SvMultiSelect.svelte +289 -290
  38. package/dist/SvNumberInput.svelte +168 -168
  39. package/dist/SvOtpInput.svelte +158 -158
  40. package/dist/SvPasswordInput.svelte +151 -151
  41. package/dist/SvPhoneInput.svelte +133 -133
  42. package/dist/SvPopover.svelte +197 -197
  43. package/dist/SvProgress.svelte +116 -116
  44. package/dist/SvRadioGroup.svelte +107 -107
  45. package/dist/SvRating.svelte +112 -112
  46. package/dist/SvResult.svelte +73 -73
  47. package/dist/SvRichText.svelte +211 -207
  48. package/dist/SvRowGroupPanel.svelte +170 -170
  49. package/dist/SvScrollArea.svelte +61 -61
  50. package/dist/SvSlider.svelte +200 -200
  51. package/dist/SvSwitchButton.svelte +108 -108
  52. package/dist/SvTagsInput.svelte +112 -112
  53. package/dist/SvTextInput.svelte +147 -147
  54. package/dist/SvTimePicker.svelte +245 -245
  55. package/dist/SvToaster.svelte +159 -159
  56. package/dist/SvToggleButton.svelte +85 -85
  57. package/dist/SvTooltip.svelte +161 -161
  58. package/dist/SvTour.svelte +208 -204
  59. package/dist/SvTree.svelte +444 -444
  60. package/dist/SvTreeSelect.svelte +235 -237
  61. package/dist/cdn/{GridMenus-C6ixSGWW.js → GridMenus-BpVcKyUr.js} +5 -7
  62. package/dist/cdn/{GridMenus-Cyk3qpJ7.js → GridMenus-CeXL5IW4.js} +153 -152
  63. package/dist/cdn/{SvDateTimePicker-ClqtVIj3.js → SvDateTimePicker-DSUhIta8.js} +165 -165
  64. package/dist/cdn/{SvDateTimePicker-CdqaP61H.js → SvDateTimePicker-h9kPyszT.js} +572 -555
  65. package/dist/cdn/{SvGridChart-BcLCYvw9.js → SvGridChart-Bs2GIR2Q.js} +28 -21
  66. package/dist/cdn/{SvGridChart-BhnFdLd0.js → SvGridChart-CwhFz7GV.js} +2 -2
  67. package/dist/cdn/{SvGridChartPanel-Cmx9DHAS.js → SvGridChartPanel-1WXuStzM.js} +2 -2
  68. package/dist/cdn/{SvGridChartPanel-DvjwxLvK.js → SvGridChartPanel-e5_nqNP9.js} +22 -14
  69. package/dist/cdn/{SvGridChartView-PwqI4s02.js → SvGridChartView-SmPW10dI.js} +3 -3
  70. package/dist/cdn/{SvGridChartView-B40DTJSX.js → SvGridChartView-eSPuJE6g.js} +2 -2
  71. package/dist/cdn/{SvGridDropdown-D0VdjeR8.js → SvGridDropdown-B1ZcLpgs.js} +1 -1
  72. package/dist/cdn/{SvGridDropdown-Dh-2ej8j.js → SvGridDropdown-CtdbHcIS.js} +6 -5
  73. package/dist/cdn/{chart-T1usDN0o.js → chart-i4XcXyHJ.js} +12 -10
  74. package/dist/cdn/disclose-version-Dr7rEVv-.js +2866 -0
  75. package/dist/cdn/{export-format-JT5pWVT8.js → export-format-Cv1Dll6k.js} +66 -245
  76. package/dist/cdn/{src-CgD-wiuS.js → src-DbeN1ReZ.js} +9223 -8944
  77. package/dist/cdn/{src-BgHjWF0Q.js → src-DmEQFW5_.js} +9023 -8828
  78. package/dist/cdn/svgrid.js +9 -9
  79. package/dist/cdn/svgrid.svelte-external.js +9 -9
  80. package/dist/chart-export.js +8 -8
  81. package/dist/chart.d.ts +2 -0
  82. package/dist/chart.js +1 -4
  83. package/dist/columns.js +9 -2
  84. package/dist/createMenu.svelte.js +0 -1
  85. package/dist/createPopoverSelect.svelte.d.ts +2 -2
  86. package/dist/editing.js +1 -1
  87. package/dist/export-format.js +3 -0
  88. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/_svelte_metadata.json +1 -0
  89. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/_metadata.json +178 -0
  90. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/attachments-qzRy9DX4.js +3843 -0
  91. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/attachments-qzRy9DX4.js.map +1 -0
  92. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/constants-RLNOXCpz.js +23 -0
  93. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/constants-RLNOXCpz.js.map +1 -0
  94. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/dev-DPd12uEU.js +1925 -0
  95. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/dev-DPd12uEU.js.map +1 -0
  96. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/events-CDC4DKuQ.js +206 -0
  97. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/events-CDC4DKuQ.js.map +1 -0
  98. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/flags-BD-lYX7s.js +20 -0
  99. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/flags-BD-lYX7s.js.map +1 -0
  100. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/hydration-D3UBU2t8.js +264 -0
  101. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/hydration-D3UBU2t8.js.map +1 -0
  102. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/legacy-client-B0ZUlbSQ.js +698 -0
  103. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/legacy-client-B0ZUlbSQ.js.map +1 -0
  104. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/package.json +3 -0
  105. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte.js +135 -0
  106. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte.js.map +1 -0
  107. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_animate.js +57 -0
  108. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_animate.js.map +1 -0
  109. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_attachments.js +2 -0
  110. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_compiler.js +46691 -0
  111. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_compiler.js.map +1 -0
  112. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_easing.js +239 -0
  113. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_easing.js.map +1 -0
  114. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_events.js +2 -0
  115. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal.js +6 -0
  116. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal.js.map +1 -0
  117. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_client.js +7 -0
  118. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_disclose-version.js +6 -0
  119. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_disclose-version.js.map +1 -0
  120. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_async.js +7 -0
  121. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_async.js.map +1 -0
  122. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_legacy.js +7 -0
  123. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_legacy.js.map +1 -0
  124. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_tracing.js +7 -0
  125. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_tracing.js.map +1 -0
  126. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_server.js +6 -0
  127. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_legacy.js +85 -0
  128. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_legacy.js.map +1 -0
  129. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_motion.js +561 -0
  130. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_motion.js.map +1 -0
  131. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity.js +26 -0
  132. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity.js.map +1 -0
  133. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity_window.js +124 -0
  134. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity_window.js.map +1 -0
  135. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_server.js +2 -0
  136. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_store.js +91 -0
  137. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_store.js.map +1 -0
  138. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_transition.js +242 -0
  139. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_transition.js.map +1 -0
  140. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-lObbumRX.js +497 -0
  141. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-lObbumRX.js.map +1 -0
  142. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-mR9mAWyK.js +4929 -0
  143. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-mR9mAWyK.js.map +1 -0
  144. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/validate-CezNmRkM.js +192 -0
  145. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/validate-CezNmRkM.js.map +1 -0
  146. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/version-BHHo0WE-.js +10 -0
  147. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/version-BHHo0WE-.js.map +1 -0
  148. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/warnings-yiExAB06.js +140 -0
  149. package/dist/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/warnings-yiExAB06.js.map +1 -0
  150. package/dist/selection.js +0 -1
  151. package/package.json +11 -10
  152. package/src/DockNodeView.svelte +1 -1
  153. package/src/FlexRender.svelte +96 -96
  154. package/src/GridFooter.svelte +178 -179
  155. package/src/GridMenus.svelte +705 -782
  156. package/src/SvAutoComplete.svelte +165 -165
  157. package/src/SvAvatar.svelte +75 -75
  158. package/src/SvCalendar.svelte +503 -503
  159. package/src/SvCalendar.test.ts +226 -226
  160. package/src/SvCarousel.svelte +141 -141
  161. package/src/SvCheckBox.svelte +102 -102
  162. package/src/SvCircularProgress.svelte +109 -109
  163. package/src/SvColorInput.svelte +181 -181
  164. package/src/SvComboBox.svelte +275 -275
  165. package/src/SvContextMenu.svelte +116 -116
  166. package/src/SvCountryInput.svelte +160 -160
  167. package/src/SvDateRangeInput.svelte +1 -1
  168. package/src/SvDrawer.svelte +254 -254
  169. package/src/SvDropDownList.svelte +374 -374
  170. package/src/SvDurationInput.svelte +126 -126
  171. package/src/SvField.svelte +293 -293
  172. package/src/SvForm.svelte +437 -437
  173. package/src/SvForm.test.ts +411 -411
  174. package/src/SvGrid.controller.svelte.ts +3680 -3685
  175. package/src/SvGrid.css +2814 -2804
  176. package/src/SvGrid.svelte +3490 -3513
  177. package/src/SvGrid.types.ts +1708 -1709
  178. package/src/SvGridChart.svelte +1716 -1724
  179. package/src/SvGridChartPanel.svelte +485 -485
  180. package/src/SvGridChartView.svelte +70 -70
  181. package/src/SvGridDropdown.svelte +728 -728
  182. package/src/SvGridSelect.svelte +266 -268
  183. package/src/SvGroupCell.svelte +116 -116
  184. package/src/SvKbd.svelte +1 -1
  185. package/src/SvList.svelte +1 -1
  186. package/src/SvListBox.svelte +326 -326
  187. package/src/SvMaskedInput.svelte +122 -122
  188. package/src/SvMenu.svelte +124 -124
  189. package/src/SvMenu.test.ts +97 -97
  190. package/src/SvMenuList.svelte +146 -146
  191. package/src/SvMenubar.svelte +1 -1
  192. package/src/SvMultiSelect.svelte +289 -290
  193. package/src/SvNumberInput.svelte +168 -168
  194. package/src/SvOtpInput.svelte +158 -158
  195. package/src/SvPasswordInput.svelte +151 -151
  196. package/src/SvPhoneInput.svelte +133 -133
  197. package/src/SvPopover.svelte +197 -197
  198. package/src/SvProgress.svelte +116 -116
  199. package/src/SvRadioGroup.svelte +107 -107
  200. package/src/SvRating.svelte +112 -112
  201. package/src/SvResult.svelte +73 -73
  202. package/src/SvRichText.svelte +211 -207
  203. package/src/SvRowGroupPanel.svelte +170 -170
  204. package/src/SvScrollArea.svelte +61 -61
  205. package/src/SvSlider.svelte +200 -200
  206. package/src/SvSwitchButton.svelte +108 -108
  207. package/src/SvTagsInput.svelte +112 -112
  208. package/src/SvTextInput.svelte +147 -147
  209. package/src/SvTimePicker.svelte +245 -245
  210. package/src/SvToaster.svelte +159 -159
  211. package/src/SvToaster.test.ts +95 -95
  212. package/src/SvToggleButton.svelte +85 -85
  213. package/src/SvTooltip.svelte +161 -161
  214. package/src/SvTour.svelte +208 -204
  215. package/src/SvTree.svelte +444 -444
  216. package/src/SvTreeSelect.svelte +235 -237
  217. package/src/a11y/dismissable.test.ts +119 -119
  218. package/src/a11y/dismissable.ts +114 -114
  219. package/src/a11y.contract.test.ts +49 -49
  220. package/src/a11y.test.ts +59 -59
  221. package/src/a11y.ts +61 -61
  222. package/src/ai.test.ts +502 -502
  223. package/src/ai.ts +1391 -1391
  224. package/src/build-api.coverage.test.ts +633 -633
  225. package/src/build-api.ts +805 -910
  226. package/src/builtin-editors.grid.test.ts +85 -85
  227. package/src/cell-formatting.test.ts +1 -1
  228. package/src/cell-formatting.ts +169 -169
  229. package/src/cell-render.test.ts +513 -513
  230. package/src/cell-render.ts +496 -590
  231. package/src/cell-values.ts +118 -118
  232. package/src/chart-export.ts +201 -201
  233. package/src/chart-view.svelte.ts +36 -36
  234. package/src/chart.ts +2295 -2296
  235. package/src/clipboard.ts +0 -102
  236. package/src/collaboration.test.ts +104 -104
  237. package/src/collaboration.ts +167 -167
  238. package/src/columns.ts +7 -117
  239. package/src/core.performance.test.ts +30 -30
  240. package/src/core.ts +1261 -1261
  241. package/src/createAutocomplete.svelte.ts +132 -132
  242. package/src/createCombobox.svelte.ts +191 -191
  243. package/src/createCountryInput.svelte.ts +157 -157
  244. package/src/createDropdownList.svelte.ts +168 -168
  245. package/src/createForm.svelte.ts +386 -386
  246. package/src/createGrid.svelte.ts +42 -42
  247. package/src/createGrid.test.ts +10 -10
  248. package/src/createGridState.svelte.ts +17 -17
  249. package/src/createListbox.svelte.ts +250 -250
  250. package/src/createMenu.svelte.ts +224 -225
  251. package/src/createPopoverSelect.svelte.ts +213 -213
  252. package/src/createSlider.svelte.ts +191 -191
  253. package/src/createTooltip.svelte.ts +144 -144
  254. package/src/createTree.svelte.ts +319 -319
  255. package/src/editing.test.ts +949 -949
  256. package/src/editing.ts +606 -709
  257. package/src/editor-contract.ts +164 -164
  258. package/src/editor-registry.grid.test.ts +144 -146
  259. package/src/editor-registry.ts +122 -122
  260. package/src/export-data-api.test.ts +126 -126
  261. package/src/export-format.test.ts +107 -107
  262. package/src/export-format.ts +601 -598
  263. package/src/features.ts +0 -90
  264. package/src/filter-operators.ts +157 -157
  265. package/src/flex-render.ts +3 -3
  266. package/src/form-field.ts +127 -127
  267. package/src/group-display.test.ts +167 -167
  268. package/src/group-display.ts +200 -200
  269. package/src/index.ts +724 -724
  270. package/src/js-scroller.svelte.ts +173 -173
  271. package/src/keyboard-handlers.coverage.test.ts +1 -1
  272. package/src/keyboard-handlers.ts +270 -390
  273. package/src/keyboard.test.ts +59 -59
  274. package/src/keyboard.ts +97 -97
  275. package/src/list-nav.test.ts +49 -49
  276. package/src/list-nav.ts +29 -29
  277. package/src/list-option.test.ts +56 -56
  278. package/src/list-option.ts +172 -172
  279. package/src/menus.test.ts +0 -1
  280. package/src/menus.ts +567 -679
  281. package/src/merge-objects.ts +48 -48
  282. package/src/new-features.test.ts +3 -1
  283. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/_svelte_metadata.json +1 -0
  284. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/_metadata.json +178 -0
  285. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/attachments-qzRy9DX4.js +3843 -0
  286. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/attachments-qzRy9DX4.js.map +1 -0
  287. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/constants-RLNOXCpz.js +23 -0
  288. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/constants-RLNOXCpz.js.map +1 -0
  289. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/dev-DPd12uEU.js +1925 -0
  290. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/dev-DPd12uEU.js.map +1 -0
  291. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/events-CDC4DKuQ.js +206 -0
  292. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/events-CDC4DKuQ.js.map +1 -0
  293. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/flags-BD-lYX7s.js +20 -0
  294. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/flags-BD-lYX7s.js.map +1 -0
  295. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/hydration-D3UBU2t8.js +264 -0
  296. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/hydration-D3UBU2t8.js.map +1 -0
  297. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/legacy-client-B0ZUlbSQ.js +698 -0
  298. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/legacy-client-B0ZUlbSQ.js.map +1 -0
  299. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/package.json +3 -0
  300. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte.js +135 -0
  301. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte.js.map +1 -0
  302. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_animate.js +57 -0
  303. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_animate.js.map +1 -0
  304. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_attachments.js +2 -0
  305. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_compiler.js +46691 -0
  306. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_compiler.js.map +1 -0
  307. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_easing.js +239 -0
  308. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_easing.js.map +1 -0
  309. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_events.js +2 -0
  310. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal.js +6 -0
  311. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal.js.map +1 -0
  312. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_client.js +7 -0
  313. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_disclose-version.js +6 -0
  314. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_disclose-version.js.map +1 -0
  315. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_async.js +7 -0
  316. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_async.js.map +1 -0
  317. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_legacy.js +7 -0
  318. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_legacy.js.map +1 -0
  319. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_tracing.js +7 -0
  320. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_flags_tracing.js.map +1 -0
  321. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_internal_server.js +6 -0
  322. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_legacy.js +85 -0
  323. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_legacy.js.map +1 -0
  324. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_motion.js +561 -0
  325. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_motion.js.map +1 -0
  326. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity.js +26 -0
  327. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity.js.map +1 -0
  328. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity_window.js +124 -0
  329. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_reactivity_window.js.map +1 -0
  330. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_server.js +2 -0
  331. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_store.js +91 -0
  332. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_store.js.map +1 -0
  333. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_transition.js +242 -0
  334. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/svelte_transition.js.map +1 -0
  335. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-lObbumRX.js +497 -0
  336. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-lObbumRX.js.map +1 -0
  337. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-mR9mAWyK.js +4929 -0
  338. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/utils-mR9mAWyK.js.map +1 -0
  339. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/validate-CezNmRkM.js +192 -0
  340. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/validate-CezNmRkM.js.map +1 -0
  341. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/version-BHHo0WE-.js +10 -0
  342. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/version-BHHo0WE-.js.map +1 -0
  343. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/warnings-yiExAB06.js +140 -0
  344. package/src/node_modules/.vite/vitest/67d8ed22ed986c5e2e948f64d892f30be166cc36/deps___vitest__/warnings-yiExAB06.js.map +1 -0
  345. package/src/overlays.test.ts +90 -90
  346. package/src/render-component.ts +28 -28
  347. package/src/row-drag.test.ts +1 -1
  348. package/src/row-resize.test.ts +1 -2
  349. package/src/row-resize.ts +210 -210
  350. package/src/scheduler-model.test.ts +562 -562
  351. package/src/scheduler-model.ts +872 -872
  352. package/src/scroll-sync.test.ts +4 -7
  353. package/src/scroll-sync.ts +0 -122
  354. package/src/selection.test.ts +754 -754
  355. package/src/selection.ts +491 -600
  356. package/src/server-data-source.test.ts +289 -289
  357. package/src/server-data-source.ts +413 -413
  358. package/src/server-group-model.test.ts +2 -2
  359. package/src/sparkline.test.ts +68 -68
  360. package/src/sparkline.ts +169 -169
  361. package/src/spreadsheet.test.ts +488 -488
  362. package/src/spreadsheet.ts +312 -312
  363. package/src/static-functions.ts +11 -11
  364. package/src/subscribe.ts +38 -38
  365. package/src/summaries.ts +0 -112
  366. package/src/svgrid-wrapper.types.ts +526 -526
  367. package/src/svgrid.async-editor-options.test.ts +271 -271
  368. package/src/svgrid.auto-row-height.test.ts +204 -204
  369. package/src/svgrid.behavior.test.ts +705 -706
  370. package/src/svgrid.charting.test.ts +534 -534
  371. package/src/svgrid.column-reorder.test.ts +0 -8
  372. package/src/svgrid.comments-autocomplete.test.ts +123 -123
  373. package/src/svgrid.context-menu.test.ts +147 -147
  374. package/src/svgrid.features.test.ts +157 -157
  375. package/src/svgrid.filter-depth.test.ts +163 -163
  376. package/src/svgrid.filter-menu-listbox.svelte.test.ts +322 -322
  377. package/src/svgrid.filter-menu-scroll.test.ts +112 -112
  378. package/src/svgrid.footer-pagesize.svelte.test.ts +86 -0
  379. package/src/svgrid.grand-total.test.ts +188 -188
  380. package/src/svgrid.group-display-mode.test.ts +171 -171
  381. package/src/svgrid.group-footers.test.ts +121 -121
  382. package/src/svgrid.group-pagination.test.ts +153 -153
  383. package/src/svgrid.new-features.wrapper.test.ts +251 -251
  384. package/src/svgrid.tree-data.test.ts +186 -186
  385. package/src/svgrid.wrapper.test.ts +40 -40
  386. package/src/svgriddropdown.async-panel.svelte.test.ts +195 -195
  387. package/src/test-setup.ts +62 -62
  388. package/src/themes/index.ts +257 -257
  389. package/src/toast-store.svelte.ts +246 -246
  390. package/src/toast-store.test.ts +147 -147
  391. package/src/tree-row-model.test.ts +168 -169
  392. package/src/ui-buttons.test.ts +144 -144
  393. package/src/ui-inputs.test.ts +118 -118
  394. package/src/ui-localization.test.ts +113 -113
  395. package/src/ui-range.test.ts +70 -70
  396. package/src/ui-selection.test.ts +155 -155
  397. package/src/ui-tier1.test.ts +142 -142
  398. package/src/virtual.test.ts +88 -88
  399. package/src/virtualization/column-virtualizer.test.ts +27 -27
  400. package/src/virtualization/column-virtualizer.ts +30 -30
  401. package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
  402. package/src/virtualization/types.ts +30 -30
  403. package/src/virtualization/virtualizer.test.ts +47 -47
  404. package/src/virtualization/virtualizer.ts +296 -296
  405. package/dist/cdn/disclose-version-DoD9AFD_.js +0 -2958
@@ -1,633 +1,633 @@
1
- /**
2
- * Coverage-focused behavioral tests for the SvGridApi assembled in
3
- * `build-api.ts`. The existing `svgrid.api.test.ts` / `svgrid.api-extensions
4
- * .test.ts` cover filters, row selection, pagination, navigation, and
5
- * getState/setState. This file exercises the remaining surface:
6
- * - getCellValue / setCellValue
7
- * - selectCells / getSelected
8
- * - addRow(s) / removeRow(s) / applyTransaction
9
- * - addColumn(s) / removeColumn / setColumnVisible / getColumns
10
- * - setColumnWidth / setColumnPinning / setColumnOrder
11
- * - setFacetFilter
12
- * - undo / redo / canUndo / canRedo / clearHistory
13
- * - find (open/close/query/hits)
14
- * - grouping (setGroupBy / expandAllGroups / collapseAllGroups)
15
- * - autosizeColumn / refresh
16
- *
17
- * All tests mount the real <SvGrid /> in jsdom and drive the api handed back
18
- * from onApiReady.
19
- */
20
-
21
- import { describe, expect, it } from "vitest";
22
- import { mount, unmount } from "svelte";
23
- import SvGrid from "./SvGrid.svelte";
24
- import {
25
- columnFilteringFeature,
26
- columnGroupingFeature,
27
- rowExpandingFeature,
28
- rowSelectionFeature,
29
- rowSortingFeature,
30
- tableFeatures,
31
- } from "./index";
32
- import type { ColumnDef, SvGridApi } from "./index";
33
-
34
- type Row = { id: number; name: string; team: string; salary: number };
35
-
36
- const baseRows: Row[] = [
37
- { id: 1, name: "Ada Lovelace", team: "Research", salary: 142_000 },
38
- { id: 2, name: "Grace Hopper", team: "Compilers", salary: 158_000 },
39
- { id: 3, name: "Alan Turing", team: "Research", salary: 138_000 },
40
- { id: 4, name: "Margaret Hamilton", team: "Apollo", salary: 165_000 },
41
- { id: 5, name: "Linus Torvalds", team: "Kernel", salary: 175_000 },
42
- ];
43
-
44
- const baseColumns: ColumnDef<any, Row>[] = [
45
- { field: "name", header: "Name", width: 200 },
46
- { field: "team", header: "Team", width: 160 },
47
- { field: "salary", header: "Salary", width: 140 },
48
- ];
49
-
50
- const flush = () => Promise.resolve();
51
-
52
- function mountGrid(
53
- extraProps: Record<string, unknown> = {},
54
- features: any = tableFeatures({
55
- columnFilteringFeature,
56
- rowSortingFeature,
57
- rowSelectionFeature,
58
- columnGroupingFeature,
59
- rowExpandingFeature,
60
- }),
61
- ): Promise<{ api: SvGridApi<any, Row>; target: HTMLElement; destroy: () => void }> {
62
- return new Promise((resolveApi, rejectApi) => {
63
- const target = document.createElement("div");
64
- document.body.appendChild(target);
65
- let captured: SvGridApi<any, Row> | null = null;
66
- const app = mount(SvGrid, {
67
- target,
68
- props: {
69
- data: baseRows.map((r) => ({ ...r })),
70
- columns: baseColumns.map((c) => ({ ...c })),
71
- features,
72
- getRowId: (r: Row) => String(r.id),
73
- rowHeight: 36,
74
- containerHeight: 480,
75
- virtualization: false,
76
- enableCellSelection: true,
77
- onApiReady(api: SvGridApi<any, Row>) {
78
- captured = api;
79
- resolveApi({
80
- api,
81
- target,
82
- destroy: () => {
83
- unmount(app);
84
- target.remove();
85
- },
86
- });
87
- },
88
- ...extraProps,
89
- } as any,
90
- });
91
- queueMicrotask(() => {
92
- if (!captured) rejectApi(new Error("onApiReady never fired"));
93
- });
94
- });
95
- }
96
-
97
- describe("SvGridApi - cell read / write", () => {
98
- it("getCellValue reads through the column field", async () => {
99
- const { api, destroy } = await mountGrid();
100
- try {
101
- expect(api.getCellValue(0, "name")).toBe("Ada Lovelace");
102
- expect(api.getCellValue(3, "team")).toBe("Apollo");
103
- } finally {
104
- destroy();
105
- }
106
- });
107
-
108
- it("getCellValue returns undefined for out-of-range row or unknown column", async () => {
109
- const { api, destroy } = await mountGrid();
110
- try {
111
- expect(api.getCellValue(999, "name")).toBeUndefined();
112
- expect(api.getCellValue(0, "nope")).toBeUndefined();
113
- } finally {
114
- destroy();
115
- }
116
- });
117
-
118
- it("setCellValue writes a new immutable row and reads back", async () => {
119
- const { api, destroy } = await mountGrid();
120
- try {
121
- api.setCellValue(0, "name", "Ada L.");
122
- await flush();
123
- expect(api.getCellValue(0, "name")).toBe("Ada L.");
124
- // other rows untouched
125
- expect(api.getCellValue(1, "name")).toBe("Grace Hopper");
126
- } finally {
127
- destroy();
128
- }
129
- });
130
-
131
- it("setCellValue is a no-op for an invalid target", async () => {
132
- const { api, destroy } = await mountGrid();
133
- try {
134
- expect(() => api.setCellValue(999, "name", "x")).not.toThrow();
135
- expect(() => api.setCellValue(0, "unknown", "x")).not.toThrow();
136
- } finally {
137
- destroy();
138
- }
139
- });
140
- });
141
-
142
- describe("SvGridApi - cell selection", () => {
143
- it("selectCells sets a rectangle; getSelected reads it back normalized", async () => {
144
- const { api, destroy } = await mountGrid();
145
- try {
146
- api.selectCells([[2, 1, 0, 0]]); // unsorted corners
147
- await flush();
148
- expect(api.getSelected()).toEqual([[0, 0, 2, 1]]);
149
- } finally {
150
- destroy();
151
- }
152
- });
153
-
154
- it("selectCells clamps open-ended (Infinity) coordinates to grid bounds", async () => {
155
- const { api, destroy } = await mountGrid();
156
- try {
157
- api.selectCells([[0, 0, Infinity, Infinity]]);
158
- await flush();
159
- // 5 rows (0..4), 3 cols (0..2)
160
- expect(api.getSelected()).toEqual([[0, 0, 4, 2]]);
161
- } finally {
162
- destroy();
163
- }
164
- });
165
-
166
- it("empty selectCells clears the range; getSelected returns []", async () => {
167
- const { api, destroy } = await mountGrid();
168
- try {
169
- api.selectCells([[0, 0, 1, 1]]);
170
- await flush();
171
- api.selectCells([]);
172
- await flush();
173
- expect(api.getSelected()).toEqual([]);
174
- } finally {
175
- destroy();
176
- }
177
- });
178
- });
179
-
180
- describe("SvGridApi - row mutations", () => {
181
- it("addRow appends to the bottom by default", async () => {
182
- const { api, destroy } = await mountGrid();
183
- try {
184
- api.addRow({ id: 6, name: "New", team: "QA", salary: 1 } as Row);
185
- await flush();
186
- const data = api.getData() as Row[];
187
- expect(data.length).toBe(6);
188
- expect(data[5]!.id).toBe(6);
189
- } finally {
190
- destroy();
191
- }
192
- });
193
-
194
- it("addRows at top / numeric index insert in place", async () => {
195
- const { api, destroy } = await mountGrid();
196
- try {
197
- api.addRows([{ id: 7, name: "Top", team: "T", salary: 1 } as Row], "top");
198
- await flush();
199
- expect((api.getData() as Row[])[0]!.id).toBe(7);
200
-
201
- api.addRows([{ id: 8, name: "Mid", team: "M", salary: 1 } as Row], 2);
202
- await flush();
203
- expect((api.getData() as Row[])[2]!.id).toBe(8);
204
- } finally {
205
- destroy();
206
- }
207
- });
208
-
209
- it("removeRow / removeRows drop by index", async () => {
210
- const { api, destroy } = await mountGrid();
211
- try {
212
- api.removeRow(0);
213
- await flush();
214
- expect((api.getData() as Row[]).map((r) => r.id)).toEqual([2, 3, 4, 5]);
215
-
216
- api.removeRows([0, 2]); // drops ids 2 and 4
217
- await flush();
218
- expect((api.getData() as Row[]).map((r) => r.id)).toEqual([3, 5]);
219
- } finally {
220
- destroy();
221
- }
222
- });
223
-
224
- it("applyTransaction adds, updates (by id), and removes; returns counts", async () => {
225
- const { api, destroy } = await mountGrid();
226
- try {
227
- const result = api.applyTransaction({
228
- add: [{ id: 9, name: "Added", team: "X", salary: 1 } as Row],
229
- update: [
230
- { id: 2, name: "Grace H.", team: "Compilers", salary: 999 } as Row,
231
- ],
232
- remove: ["3"], // by getRowId string
233
- });
234
- await flush();
235
- expect(result).toEqual({ added: 1, updated: 1, removed: 1 });
236
- const data = api.getData() as Row[];
237
- expect(data.find((r) => r.id === 3)).toBeUndefined();
238
- expect(data.find((r) => r.id === 2)!.salary).toBe(999);
239
- expect(data.find((r) => r.id === 9)).toBeTruthy();
240
- } finally {
241
- destroy();
242
- }
243
- });
244
-
245
- it("applyTransaction removes by object reference too", async () => {
246
- const { api, destroy } = await mountGrid();
247
- try {
248
- const target = (api.getData() as Row[])[0]!;
249
- const result = api.applyTransaction({ remove: [target] });
250
- await flush();
251
- expect(result.removed).toBe(1);
252
- expect((api.getData() as Row[]).find((r) => r === target)).toBeUndefined();
253
- } finally {
254
- destroy();
255
- }
256
- });
257
- });
258
-
259
- describe("SvGridApi - column mutations", () => {
260
- it("addColumn left / right / numeric position, then getColumns reflects it", async () => {
261
- const { api, destroy } = await mountGrid();
262
- try {
263
- api.addColumn({ field: "id", header: "ID" } as any, "left");
264
- await flush();
265
- expect(api.getColumns()[0]!.id).toBe("id");
266
-
267
- api.addColumns([{ field: "extra", header: "Extra" } as any], "right");
268
- await flush();
269
- const cols = api.getColumns();
270
- expect(cols[cols.length - 1]!.id).toBe("extra");
271
- } finally {
272
- destroy();
273
- }
274
- });
275
-
276
- it("removeColumn drops a column from the visible set", async () => {
277
- const { api, destroy } = await mountGrid();
278
- try {
279
- api.removeColumn("team");
280
- await flush();
281
- expect(api.getColumns().find((c) => c.id === "team")).toBeUndefined();
282
- } finally {
283
- destroy();
284
- }
285
- });
286
-
287
- it("setColumnVisible toggles visibility; getColumns lists hidden as visible:false", async () => {
288
- const { api, destroy } = await mountGrid();
289
- try {
290
- api.setColumnVisible("team", false);
291
- await flush();
292
- expect(api.isColumnVisible("team")).toBe(false);
293
- const hidden = api.getColumns().find((c) => c.id === "team");
294
- expect(hidden!.visible).toBe(false);
295
-
296
- api.setColumnVisible("team", true);
297
- await flush();
298
- expect(api.isColumnVisible("team")).toBe(true);
299
- } finally {
300
- destroy();
301
- }
302
- });
303
-
304
- it("setColumnWidth clamps + getColumnWidths round-trips", async () => {
305
- const { api, destroy } = await mountGrid();
306
- try {
307
- api.setColumnWidth("name", 333.7);
308
- await flush();
309
- expect(api.getColumnWidths().name).toBe(333);
310
- } finally {
311
- destroy();
312
- }
313
- });
314
-
315
- it("setColumnPinning dedupes; getColumnPinning returns copies", async () => {
316
- const { api, destroy } = await mountGrid();
317
- try {
318
- api.setColumnPinning({ left: ["name", "name"], right: ["salary"] });
319
- await flush();
320
- const pin = api.getColumnPinning();
321
- expect(pin.left).toEqual(["name"]);
322
- expect(pin.right).toEqual(["salary"]);
323
- // mutating the returned copy doesn't affect internal state
324
- pin.left.push("hacked");
325
- expect(api.getColumnPinning().left).toEqual(["name"]);
326
- } finally {
327
- destroy();
328
- }
329
- });
330
-
331
- it("setColumnOrder + getColumnOrder round-trip", async () => {
332
- const { api, destroy } = await mountGrid();
333
- try {
334
- api.setColumnOrder(["salary", "name", "team"]);
335
- await flush();
336
- expect(api.getColumnOrder().slice(0, 3)).toEqual([
337
- "salary",
338
- "name",
339
- "team",
340
- ]);
341
- } finally {
342
- destroy();
343
- }
344
- });
345
-
346
- // Note: autosizeColumn / autosizeAllColumns are intentionally not asserted
347
- // here - they measure text via real DOM layout (canvas/escape), which jsdom
348
- // does not provide, so they throw in this environment. They are exercised by
349
- // the demo gallery / Playwright suite per the coverage config notes.
350
- });
351
-
352
- describe("SvGridApi - facet filter", () => {
353
- it("setFacetFilter narrows displayed rows; null clears it", async () => {
354
- const { api, destroy } = await mountGrid();
355
- try {
356
- api.setFacetFilter("team", ["Research"]);
357
- await flush();
358
- const displayed = api.getDisplayedRows() as Row[];
359
- expect(displayed.every((r) => r.team === "Research")).toBe(true);
360
- expect(displayed.length).toBe(2);
361
-
362
- api.setFacetFilter("team", null);
363
- await flush();
364
- expect((api.getDisplayedRows() as Row[]).length).toBe(5);
365
- } finally {
366
- destroy();
367
- }
368
- });
369
-
370
- it("setFacetFilter with an empty array also clears", async () => {
371
- const { api, destroy } = await mountGrid();
372
- try {
373
- api.setFacetFilter("team", ["Apollo"]);
374
- await flush();
375
- api.setFacetFilter("team", []);
376
- await flush();
377
- expect((api.getDisplayedRows() as Row[]).length).toBe(5);
378
- } finally {
379
- destroy();
380
- }
381
- });
382
- });
383
-
384
- describe("SvGridApi - find", () => {
385
- it("openFind / setFindQuery / getFindHits / closeFind", async () => {
386
- const { api, destroy } = await mountGrid();
387
- try {
388
- api.openFind();
389
- api.setFindQuery("Research");
390
- await flush();
391
- const hits = api.getFindHits();
392
- expect(Array.isArray(hits)).toBe(true);
393
- // two cells contain "Research"
394
- expect(hits.length).toBeGreaterThanOrEqual(2);
395
-
396
- api.closeFind();
397
- await flush();
398
- expect(api.getFindHits()).toEqual([]);
399
- } finally {
400
- destroy();
401
- }
402
- });
403
- });
404
-
405
- describe("SvGridApi - undo / redo / history", () => {
406
- it("canUndo is false before any history; undo/redo are no-ops then", async () => {
407
- const { api, destroy } = await mountGrid();
408
- try {
409
- expect(api.canUndo()).toBe(false);
410
- expect(api.canRedo()).toBe(false);
411
- expect(api.undo()).toBe(false);
412
- expect(api.redo()).toBe(false);
413
- } finally {
414
- destroy();
415
- }
416
- });
417
-
418
- it("clearHistory resets the stacks without throwing", async () => {
419
- const { api, destroy } = await mountGrid();
420
- try {
421
- expect(() => api.clearHistory()).not.toThrow();
422
- expect(api.canUndo()).toBe(false);
423
- expect(api.canRedo()).toBe(false);
424
- } finally {
425
- destroy();
426
- }
427
- });
428
- });
429
-
430
- describe("SvGridApi - grouping / expansion", () => {
431
- it("setGroupBy groups rows; the underlying data is unchanged", async () => {
432
- const { api, destroy } = await mountGrid();
433
- try {
434
- api.setGroupBy(["team"]);
435
- await flush();
436
- // Grouping reshapes the display pipeline; the source data is intact.
437
- expect((api.getData() as Row[]).length).toBe(5);
438
- expect(api.getState().grouping).toContain("team");
439
- } finally {
440
- destroy();
441
- }
442
- });
443
-
444
- it("expandAllGroups / collapseAllGroups run without error", async () => {
445
- const { api, destroy } = await mountGrid();
446
- try {
447
- api.setGroupBy(["team"]);
448
- await flush();
449
- expect(() => api.expandAllGroups()).not.toThrow();
450
- await flush();
451
- expect(() => api.collapseAllGroups()).not.toThrow();
452
- await flush();
453
- // un-group
454
- api.setGroupBy([]);
455
- await flush();
456
- expect((api.getData() as Row[]).length).toBe(5);
457
- } finally {
458
- destroy();
459
- }
460
- });
461
-
462
- it("setRowExpanded toggles a row's expanded flag", async () => {
463
- const { api, destroy } = await mountGrid();
464
- try {
465
- expect(() => api.setRowExpanded("1", true)).not.toThrow();
466
- await flush();
467
- expect(() => api.setRowExpanded("1", false)).not.toThrow();
468
- } finally {
469
- destroy();
470
- }
471
- });
472
- });
473
-
474
- describe("SvGridApi - sort opt-out + refresh", () => {
475
- it("setSort with a direction sets a single active clause", async () => {
476
- const { api, destroy } = await mountGrid();
477
- try {
478
- api.setSort("salary", "asc");
479
- await flush();
480
- expect(api.getState().sorting).toEqual([{ id: "salary", desc: false }]);
481
-
482
- api.setSort("name", "desc");
483
- await flush();
484
- // Setting a direction replaces the active sort clause.
485
- expect(api.getState().sorting).toEqual([{ id: "name", desc: true }]);
486
- } finally {
487
- destroy();
488
- }
489
- });
490
-
491
- it("setSort with a falsy direction removes that column's clause", async () => {
492
- const { api, destroy } = await mountGrid();
493
- try {
494
- api.setSort("salary", "asc");
495
- await flush();
496
- api.setSort("salary", null as any);
497
- await flush();
498
- expect(
499
- api.getState().sorting.find((s) => s.id === "salary"),
500
- ).toBeUndefined();
501
- } finally {
502
- destroy();
503
- }
504
- });
505
-
506
- it("setSort is ignored for a non-sortable column", async () => {
507
- const { api, destroy } = await mountGrid({
508
- columns: [
509
- { field: "name", header: "Name", width: 200, sortable: false },
510
- { field: "team", header: "Team", width: 160 },
511
- ],
512
- });
513
- try {
514
- api.setSort("name", "asc");
515
- await flush();
516
- expect(api.getState().sorting.find((s) => s.id === "name")).toBeUndefined();
517
- } finally {
518
- destroy();
519
- }
520
- });
521
-
522
- it("refresh re-runs the pipeline without throwing or losing data", async () => {
523
- const { api, destroy } = await mountGrid();
524
- try {
525
- expect(() => api.refresh()).not.toThrow();
526
- await flush();
527
- expect((api.getData() as Row[]).length).toBe(5);
528
- } finally {
529
- destroy();
530
- }
531
- });
532
- });
533
-
534
- describe("SvGridApi - setOption / getOption (runtime prop overrides)", () => {
535
- it("getOption returns the incoming prop when no override is set", async () => {
536
- const { api, destroy } = await mountGrid();
537
- try {
538
- expect(api.getOption("rowHeight")).toBe(36);
539
- expect(api.getOption("zebraRows")).toBeUndefined();
540
- } finally {
541
- destroy();
542
- }
543
- });
544
-
545
- it("setOption overrides a prop, getOption reflects it, undefined clears it", async () => {
546
- const { api, destroy } = await mountGrid();
547
- try {
548
- api.setOption("rowHeight", 48);
549
- await flush();
550
- expect(api.getOption("rowHeight")).toBe(48);
551
-
552
- api.setOption("zebraRows", true);
553
- await flush();
554
- expect(api.getOption("zebraRows")).toBe(true);
555
-
556
- // Clearing an override falls back to the incoming prop.
557
- api.setOption("rowHeight", undefined);
558
- await flush();
559
- expect(api.getOption("rowHeight")).toBe(36);
560
- } finally {
561
- destroy();
562
- }
563
- });
564
-
565
- it("setOption('sortable', true) turns sorting on at runtime; false turns it off", async () => {
566
- // Mount with NO features so sorting starts disabled - only the runtime
567
- // override can inject rowSortingFeature (mirrors resolveEffectiveFeatures).
568
- const { api, destroy } = await mountGrid({}, tableFeatures({}));
569
- try {
570
- // Off by default: setSort is guarded to a no-op.
571
- api.setSort("salary", "asc");
572
- await flush();
573
- expect(api.getState().sorting).toEqual([]);
574
-
575
- // Turn sorting on via the override, then setSort takes effect.
576
- api.setOption("sortable", true);
577
- await flush();
578
- api.setSort("salary", "asc");
579
- await flush();
580
- expect(api.getState().sorting).toEqual([{ id: "salary", desc: false }]);
581
-
582
- // Turn it back off: setSort is guarded again.
583
- api.setOption("sortable", false);
584
- await flush();
585
- api.clearSort();
586
- await flush();
587
- api.setSort("team", "asc");
588
- await flush();
589
- expect(api.getState().sorting).toEqual([]);
590
- } finally {
591
- destroy();
592
- }
593
- });
594
-
595
- it("a view-direct prop (zebraRows) visually re-renders on override", async () => {
596
- const { api, target, destroy } = await mountGrid();
597
- try {
598
- // No striping to start.
599
- expect(target.querySelectorAll(".sv-grid-row-alt").length).toBe(0);
600
-
601
- api.setOption("zebraRows", true);
602
- await flush();
603
- await flush();
604
- // Odd rows now carry the alternate-row class (view reads props.zebraRows,
605
- // which is the effective proxy).
606
- expect(target.querySelectorAll(".sv-grid-row-alt").length).toBeGreaterThan(0);
607
-
608
- api.setOption("zebraRows", undefined);
609
- await flush();
610
- await flush();
611
- expect(target.querySelectorAll(".sv-grid-row-alt").length).toBe(0);
612
- } finally {
613
- destroy();
614
- }
615
- });
616
-
617
- it("resetOptions clears every override", async () => {
618
- const { api, destroy } = await mountGrid();
619
- try {
620
- api.setOption("rowHeight", 60);
621
- api.setOption("zebraRows", true);
622
- await flush();
623
- expect(api.getOption("rowHeight")).toBe(60);
624
-
625
- api.resetOptions();
626
- await flush();
627
- expect(api.getOption("rowHeight")).toBe(36);
628
- expect(api.getOption("zebraRows")).toBeUndefined();
629
- } finally {
630
- destroy();
631
- }
632
- });
633
- });
1
+ /**
2
+ * Coverage-focused behavioral tests for the SvGridApi assembled in
3
+ * `build-api.ts`. The existing `svgrid.api.test.ts` / `svgrid.api-extensions
4
+ * .test.ts` cover filters, row selection, pagination, navigation, and
5
+ * getState/setState. This file exercises the remaining surface:
6
+ * - getCellValue / setCellValue
7
+ * - selectCells / getSelected
8
+ * - addRow(s) / removeRow(s) / applyTransaction
9
+ * - addColumn(s) / removeColumn / setColumnVisible / getColumns
10
+ * - setColumnWidth / setColumnPinning / setColumnOrder
11
+ * - setFacetFilter
12
+ * - undo / redo / canUndo / canRedo / clearHistory
13
+ * - find (open/close/query/hits)
14
+ * - grouping (setGroupBy / expandAllGroups / collapseAllGroups)
15
+ * - autosizeColumn / refresh
16
+ *
17
+ * All tests mount the real <SvGrid /> in jsdom and drive the api handed back
18
+ * from onApiReady.
19
+ */
20
+
21
+ import { describe, expect, it } from "vitest";
22
+ import { mount, unmount } from "svelte";
23
+ import SvGrid from "./SvGrid.svelte";
24
+ import {
25
+ columnFilteringFeature,
26
+ columnGroupingFeature,
27
+ rowExpandingFeature,
28
+ rowSelectionFeature,
29
+ rowSortingFeature,
30
+ tableFeatures,
31
+ } from "./index";
32
+ import type { ColumnDef, SvGridApi } from "./index";
33
+
34
+ type Row = { id: number; name: string; team: string; salary: number };
35
+
36
+ const baseRows: Row[] = [
37
+ { id: 1, name: "Ada Lovelace", team: "Research", salary: 142_000 },
38
+ { id: 2, name: "Grace Hopper", team: "Compilers", salary: 158_000 },
39
+ { id: 3, name: "Alan Turing", team: "Research", salary: 138_000 },
40
+ { id: 4, name: "Margaret Hamilton", team: "Apollo", salary: 165_000 },
41
+ { id: 5, name: "Linus Torvalds", team: "Kernel", salary: 175_000 },
42
+ ];
43
+
44
+ const baseColumns: ColumnDef<any, Row>[] = [
45
+ { field: "name", header: "Name", width: 200 },
46
+ { field: "team", header: "Team", width: 160 },
47
+ { field: "salary", header: "Salary", width: 140 },
48
+ ];
49
+
50
+ const flush = () => Promise.resolve();
51
+
52
+ function mountGrid(
53
+ extraProps: Record<string, unknown> = {},
54
+ features: any = tableFeatures({
55
+ columnFilteringFeature,
56
+ rowSortingFeature,
57
+ rowSelectionFeature,
58
+ columnGroupingFeature,
59
+ rowExpandingFeature,
60
+ }),
61
+ ): Promise<{ api: SvGridApi<any, Row>; target: HTMLElement; destroy: () => void }> {
62
+ return new Promise((resolveApi, rejectApi) => {
63
+ const target = document.createElement("div");
64
+ document.body.appendChild(target);
65
+ let captured: SvGridApi<any, Row> | null = null;
66
+ const app = mount(SvGrid, {
67
+ target,
68
+ props: {
69
+ data: baseRows.map((r) => ({ ...r })),
70
+ columns: baseColumns.map((c) => ({ ...c })),
71
+ features,
72
+ getRowId: (r: Row) => String(r.id),
73
+ rowHeight: 36,
74
+ containerHeight: 480,
75
+ virtualization: false,
76
+ enableCellSelection: true,
77
+ onApiReady(api: SvGridApi<any, Row>) {
78
+ captured = api;
79
+ resolveApi({
80
+ api,
81
+ target,
82
+ destroy: () => {
83
+ unmount(app);
84
+ target.remove();
85
+ },
86
+ });
87
+ },
88
+ ...extraProps,
89
+ } as any,
90
+ });
91
+ queueMicrotask(() => {
92
+ if (!captured) rejectApi(new Error("onApiReady never fired"));
93
+ });
94
+ });
95
+ }
96
+
97
+ describe("SvGridApi - cell read / write", () => {
98
+ it("getCellValue reads through the column field", async () => {
99
+ const { api, destroy } = await mountGrid();
100
+ try {
101
+ expect(api.getCellValue(0, "name")).toBe("Ada Lovelace");
102
+ expect(api.getCellValue(3, "team")).toBe("Apollo");
103
+ } finally {
104
+ destroy();
105
+ }
106
+ });
107
+
108
+ it("getCellValue returns undefined for out-of-range row or unknown column", async () => {
109
+ const { api, destroy } = await mountGrid();
110
+ try {
111
+ expect(api.getCellValue(999, "name")).toBeUndefined();
112
+ expect(api.getCellValue(0, "nope")).toBeUndefined();
113
+ } finally {
114
+ destroy();
115
+ }
116
+ });
117
+
118
+ it("setCellValue writes a new immutable row and reads back", async () => {
119
+ const { api, destroy } = await mountGrid();
120
+ try {
121
+ api.setCellValue(0, "name", "Ada L.");
122
+ await flush();
123
+ expect(api.getCellValue(0, "name")).toBe("Ada L.");
124
+ // other rows untouched
125
+ expect(api.getCellValue(1, "name")).toBe("Grace Hopper");
126
+ } finally {
127
+ destroy();
128
+ }
129
+ });
130
+
131
+ it("setCellValue is a no-op for an invalid target", async () => {
132
+ const { api, destroy } = await mountGrid();
133
+ try {
134
+ expect(() => api.setCellValue(999, "name", "x")).not.toThrow();
135
+ expect(() => api.setCellValue(0, "unknown", "x")).not.toThrow();
136
+ } finally {
137
+ destroy();
138
+ }
139
+ });
140
+ });
141
+
142
+ describe("SvGridApi - cell selection", () => {
143
+ it("selectCells sets a rectangle; getSelected reads it back normalized", async () => {
144
+ const { api, destroy } = await mountGrid();
145
+ try {
146
+ api.selectCells([[2, 1, 0, 0]]); // unsorted corners
147
+ await flush();
148
+ expect(api.getSelected()).toEqual([[0, 0, 2, 1]]);
149
+ } finally {
150
+ destroy();
151
+ }
152
+ });
153
+
154
+ it("selectCells clamps open-ended (Infinity) coordinates to grid bounds", async () => {
155
+ const { api, destroy } = await mountGrid();
156
+ try {
157
+ api.selectCells([[0, 0, Infinity, Infinity]]);
158
+ await flush();
159
+ // 5 rows (0..4), 3 cols (0..2)
160
+ expect(api.getSelected()).toEqual([[0, 0, 4, 2]]);
161
+ } finally {
162
+ destroy();
163
+ }
164
+ });
165
+
166
+ it("empty selectCells clears the range; getSelected returns []", async () => {
167
+ const { api, destroy } = await mountGrid();
168
+ try {
169
+ api.selectCells([[0, 0, 1, 1]]);
170
+ await flush();
171
+ api.selectCells([]);
172
+ await flush();
173
+ expect(api.getSelected()).toEqual([]);
174
+ } finally {
175
+ destroy();
176
+ }
177
+ });
178
+ });
179
+
180
+ describe("SvGridApi - row mutations", () => {
181
+ it("addRow appends to the bottom by default", async () => {
182
+ const { api, destroy } = await mountGrid();
183
+ try {
184
+ api.addRow({ id: 6, name: "New", team: "QA", salary: 1 } as Row);
185
+ await flush();
186
+ const data = api.getData() as Row[];
187
+ expect(data.length).toBe(6);
188
+ expect(data[5]!.id).toBe(6);
189
+ } finally {
190
+ destroy();
191
+ }
192
+ });
193
+
194
+ it("addRows at top / numeric index insert in place", async () => {
195
+ const { api, destroy } = await mountGrid();
196
+ try {
197
+ api.addRows([{ id: 7, name: "Top", team: "T", salary: 1 } as Row], "top");
198
+ await flush();
199
+ expect((api.getData() as Row[])[0]!.id).toBe(7);
200
+
201
+ api.addRows([{ id: 8, name: "Mid", team: "M", salary: 1 } as Row], 2);
202
+ await flush();
203
+ expect((api.getData() as Row[])[2]!.id).toBe(8);
204
+ } finally {
205
+ destroy();
206
+ }
207
+ });
208
+
209
+ it("removeRow / removeRows drop by index", async () => {
210
+ const { api, destroy } = await mountGrid();
211
+ try {
212
+ api.removeRow(0);
213
+ await flush();
214
+ expect((api.getData() as Row[]).map((r) => r.id)).toEqual([2, 3, 4, 5]);
215
+
216
+ api.removeRows([0, 2]); // drops ids 2 and 4
217
+ await flush();
218
+ expect((api.getData() as Row[]).map((r) => r.id)).toEqual([3, 5]);
219
+ } finally {
220
+ destroy();
221
+ }
222
+ });
223
+
224
+ it("applyTransaction adds, updates (by id), and removes; returns counts", async () => {
225
+ const { api, destroy } = await mountGrid();
226
+ try {
227
+ const result = api.applyTransaction({
228
+ add: [{ id: 9, name: "Added", team: "X", salary: 1 } as Row],
229
+ update: [
230
+ { id: 2, name: "Grace H.", team: "Compilers", salary: 999 } as Row,
231
+ ],
232
+ remove: ["3"], // by getRowId string
233
+ });
234
+ await flush();
235
+ expect(result).toEqual({ added: 1, updated: 1, removed: 1 });
236
+ const data = api.getData() as Row[];
237
+ expect(data.find((r) => r.id === 3)).toBeUndefined();
238
+ expect(data.find((r) => r.id === 2)!.salary).toBe(999);
239
+ expect(data.find((r) => r.id === 9)).toBeTruthy();
240
+ } finally {
241
+ destroy();
242
+ }
243
+ });
244
+
245
+ it("applyTransaction removes by object reference too", async () => {
246
+ const { api, destroy } = await mountGrid();
247
+ try {
248
+ const target = (api.getData() as Row[])[0]!;
249
+ const result = api.applyTransaction({ remove: [target] });
250
+ await flush();
251
+ expect(result.removed).toBe(1);
252
+ expect((api.getData() as Row[]).find((r) => r === target)).toBeUndefined();
253
+ } finally {
254
+ destroy();
255
+ }
256
+ });
257
+ });
258
+
259
+ describe("SvGridApi - column mutations", () => {
260
+ it("addColumn left / right / numeric position, then getColumns reflects it", async () => {
261
+ const { api, destroy } = await mountGrid();
262
+ try {
263
+ api.addColumn({ field: "id", header: "ID" } as any, "left");
264
+ await flush();
265
+ expect(api.getColumns()[0]!.id).toBe("id");
266
+
267
+ api.addColumns([{ field: "extra", header: "Extra" } as any], "right");
268
+ await flush();
269
+ const cols = api.getColumns();
270
+ expect(cols[cols.length - 1]!.id).toBe("extra");
271
+ } finally {
272
+ destroy();
273
+ }
274
+ });
275
+
276
+ it("removeColumn drops a column from the visible set", async () => {
277
+ const { api, destroy } = await mountGrid();
278
+ try {
279
+ api.removeColumn("team");
280
+ await flush();
281
+ expect(api.getColumns().find((c) => c.id === "team")).toBeUndefined();
282
+ } finally {
283
+ destroy();
284
+ }
285
+ });
286
+
287
+ it("setColumnVisible toggles visibility; getColumns lists hidden as visible:false", async () => {
288
+ const { api, destroy } = await mountGrid();
289
+ try {
290
+ api.setColumnVisible("team", false);
291
+ await flush();
292
+ expect(api.isColumnVisible("team")).toBe(false);
293
+ const hidden = api.getColumns().find((c) => c.id === "team");
294
+ expect(hidden!.visible).toBe(false);
295
+
296
+ api.setColumnVisible("team", true);
297
+ await flush();
298
+ expect(api.isColumnVisible("team")).toBe(true);
299
+ } finally {
300
+ destroy();
301
+ }
302
+ });
303
+
304
+ it("setColumnWidth clamps + getColumnWidths round-trips", async () => {
305
+ const { api, destroy } = await mountGrid();
306
+ try {
307
+ api.setColumnWidth("name", 333.7);
308
+ await flush();
309
+ expect(api.getColumnWidths().name).toBe(333);
310
+ } finally {
311
+ destroy();
312
+ }
313
+ });
314
+
315
+ it("setColumnPinning dedupes; getColumnPinning returns copies", async () => {
316
+ const { api, destroy } = await mountGrid();
317
+ try {
318
+ api.setColumnPinning({ left: ["name", "name"], right: ["salary"] });
319
+ await flush();
320
+ const pin = api.getColumnPinning();
321
+ expect(pin.left).toEqual(["name"]);
322
+ expect(pin.right).toEqual(["salary"]);
323
+ // mutating the returned copy doesn't affect internal state
324
+ pin.left.push("hacked");
325
+ expect(api.getColumnPinning().left).toEqual(["name"]);
326
+ } finally {
327
+ destroy();
328
+ }
329
+ });
330
+
331
+ it("setColumnOrder + getColumnOrder round-trip", async () => {
332
+ const { api, destroy } = await mountGrid();
333
+ try {
334
+ api.setColumnOrder(["salary", "name", "team"]);
335
+ await flush();
336
+ expect(api.getColumnOrder().slice(0, 3)).toEqual([
337
+ "salary",
338
+ "name",
339
+ "team",
340
+ ]);
341
+ } finally {
342
+ destroy();
343
+ }
344
+ });
345
+
346
+ // Note: autosizeColumn / autosizeAllColumns are intentionally not asserted
347
+ // here - they measure text via real DOM layout (canvas/escape), which jsdom
348
+ // does not provide, so they throw in this environment. They are exercised by
349
+ // the demo gallery / Playwright suite per the coverage config notes.
350
+ });
351
+
352
+ describe("SvGridApi - facet filter", () => {
353
+ it("setFacetFilter narrows displayed rows; null clears it", async () => {
354
+ const { api, destroy } = await mountGrid();
355
+ try {
356
+ api.setFacetFilter("team", ["Research"]);
357
+ await flush();
358
+ const displayed = api.getDisplayedRows() as Row[];
359
+ expect(displayed.every((r) => r.team === "Research")).toBe(true);
360
+ expect(displayed.length).toBe(2);
361
+
362
+ api.setFacetFilter("team", null);
363
+ await flush();
364
+ expect((api.getDisplayedRows() as Row[]).length).toBe(5);
365
+ } finally {
366
+ destroy();
367
+ }
368
+ });
369
+
370
+ it("setFacetFilter with an empty array also clears", async () => {
371
+ const { api, destroy } = await mountGrid();
372
+ try {
373
+ api.setFacetFilter("team", ["Apollo"]);
374
+ await flush();
375
+ api.setFacetFilter("team", []);
376
+ await flush();
377
+ expect((api.getDisplayedRows() as Row[]).length).toBe(5);
378
+ } finally {
379
+ destroy();
380
+ }
381
+ });
382
+ });
383
+
384
+ describe("SvGridApi - find", () => {
385
+ it("openFind / setFindQuery / getFindHits / closeFind", async () => {
386
+ const { api, destroy } = await mountGrid();
387
+ try {
388
+ api.openFind();
389
+ api.setFindQuery("Research");
390
+ await flush();
391
+ const hits = api.getFindHits();
392
+ expect(Array.isArray(hits)).toBe(true);
393
+ // two cells contain "Research"
394
+ expect(hits.length).toBeGreaterThanOrEqual(2);
395
+
396
+ api.closeFind();
397
+ await flush();
398
+ expect(api.getFindHits()).toEqual([]);
399
+ } finally {
400
+ destroy();
401
+ }
402
+ });
403
+ });
404
+
405
+ describe("SvGridApi - undo / redo / history", () => {
406
+ it("canUndo is false before any history; undo/redo are no-ops then", async () => {
407
+ const { api, destroy } = await mountGrid();
408
+ try {
409
+ expect(api.canUndo()).toBe(false);
410
+ expect(api.canRedo()).toBe(false);
411
+ expect(api.undo()).toBe(false);
412
+ expect(api.redo()).toBe(false);
413
+ } finally {
414
+ destroy();
415
+ }
416
+ });
417
+
418
+ it("clearHistory resets the stacks without throwing", async () => {
419
+ const { api, destroy } = await mountGrid();
420
+ try {
421
+ expect(() => api.clearHistory()).not.toThrow();
422
+ expect(api.canUndo()).toBe(false);
423
+ expect(api.canRedo()).toBe(false);
424
+ } finally {
425
+ destroy();
426
+ }
427
+ });
428
+ });
429
+
430
+ describe("SvGridApi - grouping / expansion", () => {
431
+ it("setGroupBy groups rows; the underlying data is unchanged", async () => {
432
+ const { api, destroy } = await mountGrid();
433
+ try {
434
+ api.setGroupBy(["team"]);
435
+ await flush();
436
+ // Grouping reshapes the display pipeline; the source data is intact.
437
+ expect((api.getData() as Row[]).length).toBe(5);
438
+ expect(api.getState().grouping).toContain("team");
439
+ } finally {
440
+ destroy();
441
+ }
442
+ });
443
+
444
+ it("expandAllGroups / collapseAllGroups run without error", async () => {
445
+ const { api, destroy } = await mountGrid();
446
+ try {
447
+ api.setGroupBy(["team"]);
448
+ await flush();
449
+ expect(() => api.expandAllGroups()).not.toThrow();
450
+ await flush();
451
+ expect(() => api.collapseAllGroups()).not.toThrow();
452
+ await flush();
453
+ // un-group
454
+ api.setGroupBy([]);
455
+ await flush();
456
+ expect((api.getData() as Row[]).length).toBe(5);
457
+ } finally {
458
+ destroy();
459
+ }
460
+ });
461
+
462
+ it("setRowExpanded toggles a row's expanded flag", async () => {
463
+ const { api, destroy } = await mountGrid();
464
+ try {
465
+ expect(() => api.setRowExpanded("1", true)).not.toThrow();
466
+ await flush();
467
+ expect(() => api.setRowExpanded("1", false)).not.toThrow();
468
+ } finally {
469
+ destroy();
470
+ }
471
+ });
472
+ });
473
+
474
+ describe("SvGridApi - sort opt-out + refresh", () => {
475
+ it("setSort with a direction sets a single active clause", async () => {
476
+ const { api, destroy } = await mountGrid();
477
+ try {
478
+ api.setSort("salary", "asc");
479
+ await flush();
480
+ expect(api.getState().sorting).toEqual([{ id: "salary", desc: false }]);
481
+
482
+ api.setSort("name", "desc");
483
+ await flush();
484
+ // Setting a direction replaces the active sort clause.
485
+ expect(api.getState().sorting).toEqual([{ id: "name", desc: true }]);
486
+ } finally {
487
+ destroy();
488
+ }
489
+ });
490
+
491
+ it("setSort with a falsy direction removes that column's clause", async () => {
492
+ const { api, destroy } = await mountGrid();
493
+ try {
494
+ api.setSort("salary", "asc");
495
+ await flush();
496
+ api.setSort("salary", null as any);
497
+ await flush();
498
+ expect(
499
+ api.getState().sorting.find((s) => s.id === "salary"),
500
+ ).toBeUndefined();
501
+ } finally {
502
+ destroy();
503
+ }
504
+ });
505
+
506
+ it("setSort is ignored for a non-sortable column", async () => {
507
+ const { api, destroy } = await mountGrid({
508
+ columns: [
509
+ { field: "name", header: "Name", width: 200, sortable: false },
510
+ { field: "team", header: "Team", width: 160 },
511
+ ],
512
+ });
513
+ try {
514
+ api.setSort("name", "asc");
515
+ await flush();
516
+ expect(api.getState().sorting.find((s) => s.id === "name")).toBeUndefined();
517
+ } finally {
518
+ destroy();
519
+ }
520
+ });
521
+
522
+ it("refresh re-runs the pipeline without throwing or losing data", async () => {
523
+ const { api, destroy } = await mountGrid();
524
+ try {
525
+ expect(() => api.refresh()).not.toThrow();
526
+ await flush();
527
+ expect((api.getData() as Row[]).length).toBe(5);
528
+ } finally {
529
+ destroy();
530
+ }
531
+ });
532
+ });
533
+
534
+ describe("SvGridApi - setOption / getOption (runtime prop overrides)", () => {
535
+ it("getOption returns the incoming prop when no override is set", async () => {
536
+ const { api, destroy } = await mountGrid();
537
+ try {
538
+ expect(api.getOption("rowHeight")).toBe(36);
539
+ expect(api.getOption("zebraRows")).toBeUndefined();
540
+ } finally {
541
+ destroy();
542
+ }
543
+ });
544
+
545
+ it("setOption overrides a prop, getOption reflects it, undefined clears it", async () => {
546
+ const { api, destroy } = await mountGrid();
547
+ try {
548
+ api.setOption("rowHeight", 48);
549
+ await flush();
550
+ expect(api.getOption("rowHeight")).toBe(48);
551
+
552
+ api.setOption("zebraRows", true);
553
+ await flush();
554
+ expect(api.getOption("zebraRows")).toBe(true);
555
+
556
+ // Clearing an override falls back to the incoming prop.
557
+ api.setOption("rowHeight", undefined);
558
+ await flush();
559
+ expect(api.getOption("rowHeight")).toBe(36);
560
+ } finally {
561
+ destroy();
562
+ }
563
+ });
564
+
565
+ it("setOption('sortable', true) turns sorting on at runtime; false turns it off", async () => {
566
+ // Mount with NO features so sorting starts disabled - only the runtime
567
+ // override can inject rowSortingFeature (mirrors resolveEffectiveFeatures).
568
+ const { api, destroy } = await mountGrid({}, tableFeatures({}));
569
+ try {
570
+ // Off by default: setSort is guarded to a no-op.
571
+ api.setSort("salary", "asc");
572
+ await flush();
573
+ expect(api.getState().sorting).toEqual([]);
574
+
575
+ // Turn sorting on via the override, then setSort takes effect.
576
+ api.setOption("sortable", true);
577
+ await flush();
578
+ api.setSort("salary", "asc");
579
+ await flush();
580
+ expect(api.getState().sorting).toEqual([{ id: "salary", desc: false }]);
581
+
582
+ // Turn it back off: setSort is guarded again.
583
+ api.setOption("sortable", false);
584
+ await flush();
585
+ api.clearSort();
586
+ await flush();
587
+ api.setSort("team", "asc");
588
+ await flush();
589
+ expect(api.getState().sorting).toEqual([]);
590
+ } finally {
591
+ destroy();
592
+ }
593
+ });
594
+
595
+ it("a view-direct prop (zebraRows) visually re-renders on override", async () => {
596
+ const { api, target, destroy } = await mountGrid();
597
+ try {
598
+ // No striping to start.
599
+ expect(target.querySelectorAll(".sv-grid-row-alt").length).toBe(0);
600
+
601
+ api.setOption("zebraRows", true);
602
+ await flush();
603
+ await flush();
604
+ // Odd rows now carry the alternate-row class (view reads props.zebraRows,
605
+ // which is the effective proxy).
606
+ expect(target.querySelectorAll(".sv-grid-row-alt").length).toBeGreaterThan(0);
607
+
608
+ api.setOption("zebraRows", undefined);
609
+ await flush();
610
+ await flush();
611
+ expect(target.querySelectorAll(".sv-grid-row-alt").length).toBe(0);
612
+ } finally {
613
+ destroy();
614
+ }
615
+ });
616
+
617
+ it("resetOptions clears every override", async () => {
618
+ const { api, destroy } = await mountGrid();
619
+ try {
620
+ api.setOption("rowHeight", 60);
621
+ api.setOption("zebraRows", true);
622
+ await flush();
623
+ expect(api.getOption("rowHeight")).toBe(60);
624
+
625
+ api.resetOptions();
626
+ await flush();
627
+ expect(api.getOption("rowHeight")).toBe(36);
628
+ expect(api.getOption("zebraRows")).toBeUndefined();
629
+ } finally {
630
+ destroy();
631
+ }
632
+ });
633
+ });