@svgrid/grid 1.2.34 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) hide show
  1. package/README.md +6 -5
  2. package/dist/SvAccordion.svelte +109 -0
  3. package/dist/SvAccordion.svelte.d.ts +28 -0
  4. package/dist/SvAlert.svelte +92 -0
  5. package/dist/SvAlert.svelte.d.ts +27 -0
  6. package/dist/SvAutoComplete.svelte +47 -18
  7. package/dist/SvAutoComplete.svelte.d.ts +2 -5
  8. package/dist/SvAvatar.svelte +75 -0
  9. package/dist/SvAvatar.svelte.d.ts +14 -0
  10. package/dist/SvAvatarGroup.svelte +48 -0
  11. package/dist/SvAvatarGroup.svelte.d.ts +16 -0
  12. package/dist/SvBadge.svelte +54 -0
  13. package/dist/SvBadge.svelte.d.ts +23 -0
  14. package/dist/SvBreadcrumb.svelte +88 -0
  15. package/dist/SvBreadcrumb.svelte.d.ts +23 -0
  16. package/dist/SvButtonGroup.svelte +121 -0
  17. package/dist/SvButtonGroup.svelte.d.ts +16 -0
  18. package/dist/SvCalendar.svelte +72 -9
  19. package/dist/SvCalendar.svelte.d.ts +34 -1
  20. package/dist/SvCard.svelte +71 -0
  21. package/dist/SvCard.svelte.d.ts +28 -0
  22. package/dist/SvCarousel.svelte +134 -0
  23. package/dist/SvCarousel.svelte.d.ts +28 -0
  24. package/dist/SvCheckBox.svelte +36 -21
  25. package/dist/SvCheckBox.svelte.d.ts +2 -5
  26. package/dist/SvChip.svelte +88 -0
  27. package/dist/SvChip.svelte.d.ts +31 -0
  28. package/dist/SvCircularProgress.svelte +109 -0
  29. package/dist/SvCircularProgress.svelte.d.ts +31 -0
  30. package/dist/SvColorInput.svelte +54 -27
  31. package/dist/SvColorInput.svelte.d.ts +10 -6
  32. package/dist/SvComboBox.svelte +119 -33
  33. package/dist/SvComboBox.svelte.d.ts +18 -6
  34. package/dist/SvCommand.svelte +197 -0
  35. package/dist/SvCommand.svelte.d.ts +26 -0
  36. package/dist/SvContextMenu.svelte +96 -0
  37. package/dist/SvContextMenu.svelte.d.ts +25 -0
  38. package/dist/SvCountryInput.svelte +56 -21
  39. package/dist/SvCountryInput.svelte.d.ts +9 -5
  40. package/dist/SvDateRangeInput.svelte +256 -0
  41. package/dist/SvDateRangeInput.svelte.d.ts +37 -0
  42. package/dist/SvDateTimePicker.svelte +57 -20
  43. package/dist/SvDateTimePicker.svelte.d.ts +12 -4
  44. package/dist/SvDivider.svelte +61 -0
  45. package/dist/SvDivider.svelte.d.ts +22 -0
  46. package/dist/SvDrawer.svelte +226 -0
  47. package/dist/SvDrawer.svelte.d.ts +43 -0
  48. package/dist/SvDropDownList.svelte +114 -35
  49. package/dist/SvDropDownList.svelte.d.ts +7 -6
  50. package/dist/SvDurationInput.svelte +108 -0
  51. package/dist/SvDurationInput.svelte.d.ts +15 -0
  52. package/dist/SvEmptyState.svelte +59 -0
  53. package/dist/SvEmptyState.svelte.d.ts +25 -0
  54. package/dist/SvField.svelte +85 -0
  55. package/dist/SvField.svelte.d.ts +30 -0
  56. package/dist/SvFileUpload.svelte +169 -0
  57. package/dist/SvFileUpload.svelte.d.ts +24 -0
  58. package/dist/SvForm.svelte +7 -1
  59. package/dist/SvForm.svelte.d.ts +3 -0
  60. package/dist/SvGauge.svelte +7 -1
  61. package/dist/SvGauge.svelte.d.ts +11 -0
  62. package/dist/SvGrid.controller.svelte.d.ts +6 -0
  63. package/dist/SvGrid.controller.svelte.js +64 -9
  64. package/dist/SvGrid.css +33 -0
  65. package/dist/SvGrid.svelte +116 -3
  66. package/dist/SvGrid.types.d.ts +366 -0
  67. package/dist/SvGridBoard.svelte +2281 -0
  68. package/dist/SvGridBoard.svelte.d.ts +31 -0
  69. package/dist/SvGridDropdown.svelte +2 -1
  70. package/dist/SvGridSelect.svelte +255 -0
  71. package/dist/SvGridSelect.svelte.d.ts +32 -0
  72. package/dist/SvGroupCell.svelte +109 -0
  73. package/dist/SvGroupCell.svelte.d.ts +41 -0
  74. package/dist/SvListBox.svelte +123 -36
  75. package/dist/SvListBox.svelte.d.ts +12 -8
  76. package/dist/SvMaskedInput.svelte +53 -13
  77. package/dist/SvMaskedInput.svelte.d.ts +16 -6
  78. package/dist/SvMenu.svelte +101 -0
  79. package/dist/SvMenu.svelte.d.ts +26 -0
  80. package/dist/SvMenuList.svelte +143 -0
  81. package/dist/SvMenuList.svelte.d.ts +24 -0
  82. package/dist/SvModal.svelte +220 -0
  83. package/dist/SvModal.svelte.d.ts +31 -0
  84. package/dist/SvMultiSelect.svelte +277 -0
  85. package/dist/SvMultiSelect.svelte.d.ts +31 -0
  86. package/dist/SvNavPane.svelte +314 -0
  87. package/dist/SvNavPane.svelte.d.ts +59 -0
  88. package/dist/SvNumberInput.svelte +23 -9
  89. package/dist/SvNumberInput.svelte.d.ts +2 -0
  90. package/dist/SvOtpInput.svelte +157 -0
  91. package/dist/SvOtpInput.svelte.d.ts +16 -0
  92. package/dist/SvPagination.svelte +100 -0
  93. package/dist/SvPagination.svelte.d.ts +16 -0
  94. package/dist/SvPasswordInput.svelte +42 -12
  95. package/dist/SvPasswordInput.svelte.d.ts +13 -6
  96. package/dist/SvPhoneInput.svelte +43 -11
  97. package/dist/SvPhoneInput.svelte.d.ts +10 -11
  98. package/dist/SvPopover.svelte +127 -0
  99. package/dist/SvPopover.svelte.d.ts +35 -0
  100. package/dist/SvProgress.svelte +116 -0
  101. package/dist/SvProgress.svelte.d.ts +32 -0
  102. package/dist/SvRadioGroup.svelte +40 -22
  103. package/dist/SvRadioGroup.svelte.d.ts +2 -10
  104. package/dist/SvRating.svelte +51 -30
  105. package/dist/SvRating.svelte.d.ts +10 -7
  106. package/dist/SvRichText.svelte +192 -0
  107. package/dist/SvRichText.svelte.d.ts +16 -0
  108. package/dist/SvRowGroupPanel.svelte +147 -0
  109. package/dist/SvRowGroupPanel.svelte.d.ts +17 -0
  110. package/dist/SvScrollArea.svelte +50 -0
  111. package/dist/SvScrollArea.svelte.d.ts +22 -0
  112. package/dist/SvSkeleton.svelte +76 -0
  113. package/dist/SvSkeleton.svelte.d.ts +25 -0
  114. package/dist/SvSlider.svelte +41 -9
  115. package/dist/SvSlider.svelte.d.ts +4 -4
  116. package/dist/SvSparkline.svelte +77 -0
  117. package/dist/SvSparkline.svelte.d.ts +28 -0
  118. package/dist/SvSplitter.svelte +138 -0
  119. package/dist/SvSplitter.svelte.d.ts +32 -0
  120. package/dist/SvStat.svelte +86 -0
  121. package/dist/SvStat.svelte.d.ts +30 -0
  122. package/dist/SvStepper.svelte +91 -0
  123. package/dist/SvStepper.svelte.d.ts +24 -0
  124. package/dist/SvSwitchButton.svelte +39 -24
  125. package/dist/SvSwitchButton.svelte.d.ts +2 -5
  126. package/dist/SvTabs.svelte +147 -28
  127. package/dist/SvTabs.svelte.d.ts +16 -4
  128. package/dist/SvTagsInput.svelte +59 -22
  129. package/dist/SvTagsInput.svelte.d.ts +9 -4
  130. package/dist/SvTextArea.svelte +113 -0
  131. package/dist/SvTextArea.svelte.d.ts +18 -0
  132. package/dist/SvTextInput.svelte +115 -0
  133. package/dist/SvTextInput.svelte.d.ts +20 -0
  134. package/dist/SvTimePicker.svelte +19 -5
  135. package/dist/SvTimePicker.svelte.d.ts +12 -0
  136. package/dist/SvTimeline.svelte +75 -0
  137. package/dist/SvTimeline.svelte.d.ts +24 -0
  138. package/dist/SvToaster.svelte +124 -0
  139. package/dist/SvToaster.svelte.d.ts +10 -0
  140. package/dist/SvToggleButton.svelte +37 -12
  141. package/dist/SvToggleButton.svelte.d.ts +2 -4
  142. package/dist/SvTooltip.svelte +113 -0
  143. package/dist/SvTooltip.svelte.d.ts +22 -0
  144. package/dist/SvTour.svelte +151 -0
  145. package/dist/SvTour.svelte.d.ts +25 -0
  146. package/dist/SvTree.svelte +286 -44
  147. package/dist/SvTree.svelte.d.ts +26 -9
  148. package/dist/SvTreeSelect.svelte +222 -0
  149. package/dist/SvTreeSelect.svelte.d.ts +24 -0
  150. package/dist/a11y/dismissable.d.ts +32 -0
  151. package/dist/a11y/dismissable.js +54 -0
  152. package/dist/a11y/focus-trap.d.ts +39 -0
  153. package/dist/a11y/focus-trap.js +142 -0
  154. package/dist/a11y/live-region.d.ts +8 -0
  155. package/dist/a11y/live-region.js +60 -0
  156. package/dist/a11y/scroll-lock.d.ts +4 -0
  157. package/dist/a11y/scroll-lock.js +41 -0
  158. package/dist/a11y.d.ts +3 -1
  159. package/dist/a11y.js +1 -1
  160. package/dist/avatar.d.ts +10 -0
  161. package/dist/avatar.js +22 -0
  162. package/dist/builtin-editors.d.ts +5 -0
  163. package/dist/builtin-editors.js +55 -0
  164. package/dist/cdn/svgrid.js +16021 -8234
  165. package/dist/cdn/svgrid.svelte-external.js +14542 -6764
  166. package/dist/columns.js +3 -2
  167. package/dist/core.d.ts +7 -1
  168. package/dist/countries.d.ts +12 -0
  169. package/dist/countries.js +24 -0
  170. package/dist/createAccordion.svelte.d.ts +71 -0
  171. package/dist/createAccordion.svelte.js +99 -0
  172. package/dist/createAutocomplete.svelte.d.ts +13 -4
  173. package/dist/createAutocomplete.svelte.js +11 -1
  174. package/dist/createButtonGroup.svelte.d.ts +62 -0
  175. package/dist/createButtonGroup.svelte.js +154 -0
  176. package/dist/createCalendar.svelte.d.ts +5 -0
  177. package/dist/createCalendar.svelte.js +2 -0
  178. package/dist/createCheckbox.svelte.d.ts +9 -17
  179. package/dist/createCheckbox.svelte.js +28 -1
  180. package/dist/createColorInput.svelte.d.ts +12 -22
  181. package/dist/createColorInput.svelte.js +13 -0
  182. package/dist/createCombobox.svelte.d.ts +16 -5
  183. package/dist/createCombobox.svelte.js +13 -2
  184. package/dist/createCountryInput.svelte.d.ts +14 -3
  185. package/dist/createCountryInput.svelte.js +12 -2
  186. package/dist/createDateTimePicker.svelte.d.ts +17 -2
  187. package/dist/createDateTimePicker.svelte.js +12 -2
  188. package/dist/createDropdownList.svelte.d.ts +14 -5
  189. package/dist/createDropdownList.svelte.js +50 -1
  190. package/dist/createFileUpload.svelte.d.ts +68 -0
  191. package/dist/createFileUpload.svelte.js +122 -0
  192. package/dist/createListbox.svelte.d.ts +10 -1
  193. package/dist/createListbox.svelte.js +48 -1
  194. package/dist/createMaskedInput.svelte.d.ts +11 -2
  195. package/dist/createMaskedInput.svelte.js +11 -1
  196. package/dist/createNumberInput.svelte.d.ts +1 -0
  197. package/dist/createNumberInput.svelte.js +1 -0
  198. package/dist/createPasswordInput.svelte.d.ts +19 -21
  199. package/dist/createPasswordInput.svelte.js +16 -4
  200. package/dist/createPhoneInput.svelte.d.ts +26 -7
  201. package/dist/createPhoneInput.svelte.js +24 -3
  202. package/dist/createPopoverSelect.svelte.d.ts +86 -0
  203. package/dist/createPopoverSelect.svelte.js +196 -0
  204. package/dist/createRadioGroup.svelte.d.ts +9 -0
  205. package/dist/createRadioGroup.svelte.js +11 -1
  206. package/dist/createRating.svelte.d.ts +11 -0
  207. package/dist/createRating.svelte.js +12 -1
  208. package/dist/createSlider.svelte.d.ts +2 -0
  209. package/dist/createSlider.svelte.js +16 -5
  210. package/dist/createSplitter.svelte.d.ts +67 -0
  211. package/dist/createSplitter.svelte.js +99 -0
  212. package/dist/createSwitch.svelte.d.ts +9 -16
  213. package/dist/createSwitch.svelte.js +28 -1
  214. package/dist/createTabs.svelte.d.ts +7 -0
  215. package/dist/createTabs.svelte.js +17 -2
  216. package/dist/createTagsInput.svelte.d.ts +13 -1
  217. package/dist/createTagsInput.svelte.js +12 -3
  218. package/dist/createToggle.svelte.d.ts +9 -0
  219. package/dist/createToggle.svelte.js +12 -1
  220. package/dist/createTree.svelte.d.ts +19 -0
  221. package/dist/createTree.svelte.js +108 -15
  222. package/dist/debounce.d.ts +11 -0
  223. package/dist/debounce.js +30 -0
  224. package/dist/duration.d.ts +15 -0
  225. package/dist/duration.js +51 -0
  226. package/dist/editor-contract.d.ts +62 -7
  227. package/dist/editor-contract.js +45 -5
  228. package/dist/editor-registry.d.ts +67 -0
  229. package/dist/editor-registry.js +38 -0
  230. package/dist/editors/cell-editors.d.ts +1 -1
  231. package/dist/editors/cell-editors.js +5 -0
  232. package/dist/fuzzy.d.ts +3 -0
  233. package/dist/fuzzy.js +41 -0
  234. package/dist/grid-select.d.ts +9 -0
  235. package/dist/grid-select.js +8 -0
  236. package/dist/index.d.ts +79 -6
  237. package/dist/index.js +78 -4
  238. package/dist/keyboard-handlers.js +19 -0
  239. package/dist/list-option.d.ts +36 -0
  240. package/dist/list-option.js +68 -0
  241. package/dist/otp.d.ts +16 -0
  242. package/dist/otp.js +26 -0
  243. package/dist/paginate.d.ts +20 -0
  244. package/dist/paginate.js +40 -0
  245. package/dist/popover.d.ts +15 -1
  246. package/dist/popover.js +29 -3
  247. package/dist/recurrence.d.ts +36 -0
  248. package/dist/recurrence.js +90 -0
  249. package/dist/server-data-source.d.ts +89 -0
  250. package/dist/server-data-source.js +4 -0
  251. package/dist/server-group-model.d.ts +98 -0
  252. package/dist/server-group-model.js +263 -0
  253. package/dist/toast-store.svelte.d.ts +41 -0
  254. package/dist/toast-store.svelte.js +113 -0
  255. package/dist/tree-select.d.ts +19 -0
  256. package/dist/tree-select.js +40 -0
  257. package/dist/ui-app.types.d.ts +80 -0
  258. package/dist/ui-app.types.js +7 -0
  259. package/dist/validators.d.ts +43 -0
  260. package/dist/validators.js +53 -0
  261. package/dist/virtual.d.ts +35 -0
  262. package/dist/virtual.js +34 -0
  263. package/package.json +1 -1
  264. package/src/SvAccordion.svelte +109 -0
  265. package/src/SvAccordion.test.ts +66 -0
  266. package/src/SvAlert.svelte +92 -0
  267. package/src/SvAutoComplete.svelte +47 -18
  268. package/src/SvAvatar.svelte +75 -0
  269. package/src/SvAvatarGroup.svelte +48 -0
  270. package/src/SvBadge.svelte +54 -0
  271. package/src/SvBreadcrumb.svelte +88 -0
  272. package/src/SvButtonGroup.svelte +121 -0
  273. package/src/SvButtonGroup.test.ts +72 -0
  274. package/src/SvCalendar.svelte +72 -9
  275. package/src/SvCard.svelte +71 -0
  276. package/src/SvCarousel.svelte +134 -0
  277. package/src/SvCheckBox.svelte +36 -21
  278. package/src/SvChip.svelte +88 -0
  279. package/src/SvCircularProgress.svelte +109 -0
  280. package/src/SvColorInput.svelte +54 -27
  281. package/src/SvComboBox.svelte +119 -33
  282. package/src/SvCommand.svelte +197 -0
  283. package/src/SvContextMenu.svelte +96 -0
  284. package/src/SvCountryInput.svelte +56 -21
  285. package/src/SvDateRangeInput.svelte +256 -0
  286. package/src/SvDateRangeInput.test.ts +80 -0
  287. package/src/SvDateTimePicker.svelte +57 -20
  288. package/src/SvDivider.svelte +61 -0
  289. package/src/SvDrawer.svelte +226 -0
  290. package/src/SvDrawer.test.ts +125 -0
  291. package/src/SvDropDownList.svelte +114 -35
  292. package/src/SvDurationInput.svelte +108 -0
  293. package/src/SvEmptyState.svelte +59 -0
  294. package/src/SvField.svelte +85 -0
  295. package/src/SvFileUpload.svelte +169 -0
  296. package/src/SvFileUpload.test.ts +59 -0
  297. package/src/SvForm.svelte +7 -1
  298. package/src/SvGauge.svelte +7 -1
  299. package/src/SvGrid.controller.svelte.ts +68 -9
  300. package/src/SvGrid.css +33 -0
  301. package/src/SvGrid.svelte +116 -3
  302. package/src/SvGrid.types.ts +374 -0
  303. package/src/SvGridBoard.svelte +2281 -0
  304. package/src/SvGridDropdown.svelte +2 -1
  305. package/src/SvGridSelect.svelte +255 -0
  306. package/src/SvGridSelect.test.ts +100 -0
  307. package/src/SvGroupCell.svelte +109 -0
  308. package/src/SvListBox.svelte +123 -36
  309. package/src/SvMaskedInput.svelte +53 -13
  310. package/src/SvMenu.svelte +101 -0
  311. package/src/SvMenu.test.ts +73 -0
  312. package/src/SvMenuList.svelte +143 -0
  313. package/src/SvModal.svelte +220 -0
  314. package/src/SvMultiSelect.svelte +277 -0
  315. package/src/SvMultiSelect.test.ts +167 -0
  316. package/src/SvNavPane.svelte +314 -0
  317. package/src/SvNavPane.test.ts +70 -0
  318. package/src/SvNumberInput.svelte +23 -9
  319. package/src/SvOtpInput.svelte +157 -0
  320. package/src/SvPagination.svelte +100 -0
  321. package/src/SvPasswordInput.svelte +42 -12
  322. package/src/SvPhoneInput.svelte +43 -11
  323. package/src/SvPopover.svelte +127 -0
  324. package/src/SvProgress.svelte +116 -0
  325. package/src/SvRadioGroup.svelte +40 -22
  326. package/src/SvRating.svelte +51 -30
  327. package/src/SvRichText.svelte +192 -0
  328. package/src/SvRowGroupPanel.svelte +147 -0
  329. package/src/SvScrollArea.svelte +50 -0
  330. package/src/SvSkeleton.svelte +76 -0
  331. package/src/SvSlider.svelte +41 -9
  332. package/src/SvSparkline.svelte +77 -0
  333. package/src/SvSplitter.svelte +138 -0
  334. package/src/SvSplitter.test.ts +55 -0
  335. package/src/SvStat.svelte +86 -0
  336. package/src/SvStepper.svelte +91 -0
  337. package/src/SvSwitchButton.svelte +39 -24
  338. package/src/SvTabs.svelte +147 -28
  339. package/src/SvTagsInput.svelte +59 -22
  340. package/src/SvTextArea.svelte +113 -0
  341. package/src/SvTextInput.svelte +115 -0
  342. package/src/SvTimePicker.svelte +19 -5
  343. package/src/SvTimeline.svelte +75 -0
  344. package/src/SvToaster.svelte +124 -0
  345. package/src/SvToaster.test.ts +63 -0
  346. package/src/SvToggleButton.svelte +37 -12
  347. package/src/SvTooltip.svelte +113 -0
  348. package/src/SvTour.svelte +151 -0
  349. package/src/SvTree.svelte +286 -44
  350. package/src/SvTreeSelect.svelte +222 -0
  351. package/src/SvTreeSelect.test.ts +87 -0
  352. package/src/a11y/dismissable.test.ts +95 -0
  353. package/src/a11y/dismissable.ts +94 -0
  354. package/src/a11y/focus-trap.test.ts +110 -0
  355. package/src/a11y/focus-trap.ts +134 -0
  356. package/src/a11y/live-region.test.ts +40 -0
  357. package/src/a11y/live-region.ts +65 -0
  358. package/src/a11y/scroll-lock.test.ts +38 -0
  359. package/src/a11y/scroll-lock.ts +41 -0
  360. package/src/a11y.ts +3 -1
  361. package/src/avatar.test.ts +32 -0
  362. package/src/avatar.ts +21 -0
  363. package/src/board.test.ts +927 -0
  364. package/src/builtin-editors.grid.test.ts +85 -0
  365. package/src/builtin-editors.test.ts +58 -0
  366. package/src/builtin-editors.ts +56 -0
  367. package/src/columns.ts +3 -2
  368. package/src/core.ts +10 -0
  369. package/src/countries.ts +25 -0
  370. package/src/createAccordion.svelte.ts +126 -0
  371. package/src/createAutocomplete.svelte.ts +18 -1
  372. package/src/createButtonGroup.svelte.ts +166 -0
  373. package/src/createCalendar.svelte.ts +6 -0
  374. package/src/createCheckbox.svelte.ts +23 -1
  375. package/src/createColorInput.svelte.ts +20 -0
  376. package/src/createCombobox.svelte.ts +22 -2
  377. package/src/createCountryInput.svelte.ts +21 -2
  378. package/src/createDateTimePicker.svelte.ts +23 -2
  379. package/src/createDropdownList.svelte.ts +31 -2
  380. package/src/createFileUpload.svelte.ts +144 -0
  381. package/src/createListbox.svelte.ts +35 -3
  382. package/src/createMaskedInput.svelte.ts +18 -1
  383. package/src/createNumberInput.svelte.ts +2 -0
  384. package/src/createPasswordInput.svelte.ts +31 -5
  385. package/src/createPhoneInput.svelte.ts +38 -4
  386. package/src/createPopoverSelect.svelte.ts +208 -0
  387. package/src/createRadioGroup.svelte.ts +23 -1
  388. package/src/createRating.svelte.ts +26 -1
  389. package/src/createSlider.svelte.ts +14 -3
  390. package/src/createSplitter.svelte.ts +119 -0
  391. package/src/createSwitch.svelte.ts +26 -3
  392. package/src/createTabs.svelte.ts +20 -3
  393. package/src/createTagsInput.svelte.ts +24 -3
  394. package/src/createToggle.svelte.ts +25 -2
  395. package/src/createTree.svelte.ts +104 -14
  396. package/src/debounce.test.ts +50 -0
  397. package/src/debounce.ts +41 -0
  398. package/src/duration.test.ts +41 -0
  399. package/src/duration.ts +51 -0
  400. package/src/editor-contract.ts +87 -8
  401. package/src/editor-registry.grid.test.ts +98 -0
  402. package/src/editor-registry.test.ts +86 -0
  403. package/src/editor-registry.ts +106 -0
  404. package/src/editors/cell-editors.ts +10 -1
  405. package/src/fuzzy.test.ts +40 -0
  406. package/src/fuzzy.ts +39 -0
  407. package/src/grid-select.test.ts +28 -0
  408. package/src/grid-select.ts +20 -0
  409. package/src/index.ts +150 -5
  410. package/src/keyboard-handlers.ts +20 -0
  411. package/src/list-option.ts +74 -0
  412. package/src/list-power.test.ts +71 -0
  413. package/src/otp.test.ts +28 -0
  414. package/src/otp.ts +28 -0
  415. package/src/overlays.test.ts +85 -0
  416. package/src/paginate.test.ts +41 -0
  417. package/src/paginate.ts +61 -0
  418. package/src/phone-valid.test.ts +26 -0
  419. package/src/popover.ts +31 -3
  420. package/src/progress.test.ts +55 -0
  421. package/src/recurrence.test.ts +91 -0
  422. package/src/recurrence.ts +111 -0
  423. package/src/server-data-source.ts +102 -0
  424. package/src/server-group-model.test.ts +294 -0
  425. package/src/server-group-model.ts +370 -0
  426. package/src/svgrid.responsive.test.ts +72 -0
  427. package/src/toast-store.svelte.ts +148 -0
  428. package/src/toast-store.test.ts +86 -0
  429. package/src/tree-edit.test.ts +49 -0
  430. package/src/tree-filter.test.ts +56 -0
  431. package/src/tree-select.test.ts +48 -0
  432. package/src/tree-select.ts +62 -0
  433. package/src/ui-app.test.ts +130 -0
  434. package/src/ui-app.types.ts +88 -0
  435. package/src/ui-display.test.ts +79 -0
  436. package/src/ui-inputs.test.ts +1 -1
  437. package/src/ui-status.test.ts +141 -0
  438. package/src/ui-tier1.test.ts +142 -0
  439. package/src/ui-tier2.test.ts +124 -0
  440. package/src/ui-tier3.test.ts +139 -0
  441. package/src/validators.test.ts +58 -0
  442. package/src/validators.ts +105 -0
  443. package/src/virtual.test.ts +72 -0
  444. package/src/virtual.ts +67 -0
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Tests for the file-upload core's pure accept matching, plus SvFileUpload
3
+ * rendering: the dropzone carries the editor contract, the selected-files list
4
+ * renders, and remove emits the trimmed list.
5
+ */
6
+ import { describe, expect, it } from 'vitest'
7
+ import { mount, unmount, flushSync } from 'svelte'
8
+ import SvFileUpload from './SvFileUpload.svelte'
9
+ import { fileMatchesAccept } from './createFileUpload.svelte'
10
+
11
+ const mk = (name: string, type = '') => new File(['x'], name, { type })
12
+
13
+ describe('fileMatchesAccept', () => {
14
+ it('matches extensions, MIME globs and exact MIME (and passes when empty)', () => {
15
+ expect(fileMatchesAccept(mk('a.pdf'), '.pdf')).toBe(true)
16
+ expect(fileMatchesAccept(mk('a.png', 'image/png'), 'image/*')).toBe(true)
17
+ expect(fileMatchesAccept(mk('a.png', 'image/png'), 'image/png')).toBe(true)
18
+ expect(fileMatchesAccept(mk('a.txt', 'text/plain'), 'image/*,.pdf')).toBe(false)
19
+ expect(fileMatchesAccept(mk('anything'), undefined)).toBe(true)
20
+ })
21
+ })
22
+
23
+ function mountFu(props: Record<string, unknown>) {
24
+ const target = document.createElement('div')
25
+ document.body.appendChild(target)
26
+ const app = mount(SvFileUpload, { target, props: props as any })
27
+ flushSync()
28
+ return { target, destroy: () => { unmount(app); target.remove() } }
29
+ }
30
+
31
+ describe('SvFileUpload', () => {
32
+ it('renders a dropzone with the editor contract wired', () => {
33
+ const { target, destroy } = mountFu({ files: [], accept: 'image/*', label: 'Avatar', required: true, invalid: true, error: 'Required' })
34
+ try {
35
+ const zone = target.querySelector<HTMLElement>('.sv-file__zone')!
36
+ expect(zone.getAttribute('role')).toBe('button')
37
+ expect(zone.getAttribute('aria-invalid')).toBe('true')
38
+ expect(zone.getAttribute('aria-required')).toBe('true')
39
+ expect(target.querySelector('.sv-field__label')!.textContent).toContain('Avatar')
40
+ expect(target.querySelector('.sv-field__error')!.textContent).toBe('Required')
41
+ const input = target.querySelector<HTMLInputElement>('.sv-file__input')!
42
+ expect(input.accept).toBe('image/*')
43
+ } finally { destroy() }
44
+ })
45
+
46
+ it('lists selected files and removes one on click', () => {
47
+ let got: File[] | undefined
48
+ const files = [mk('a.png', 'image/png'), mk('b.png', 'image/png')]
49
+ const { target, destroy } = mountFu({ files, multiple: true, onChange: (f: File[]) => (got = f) })
50
+ try {
51
+ const items = target.querySelectorAll('.sv-file__item')
52
+ expect(items).toHaveLength(2)
53
+ target.querySelector<HTMLButtonElement>('.sv-file__remove')!.click()
54
+ flushSync()
55
+ expect(got).toHaveLength(1)
56
+ expect(got![0].name).toBe('b.png')
57
+ } finally { destroy() }
58
+ })
59
+ })
package/src/SvForm.svelte CHANGED
@@ -1,4 +1,6 @@
1
1
  <script lang="ts" module>
2
+ import type { Validator } from './validators'
3
+
2
4
  export type FormFieldType =
3
5
  | 'text' | 'email' | 'tel' | 'textarea' | 'number' | 'password'
4
6
  | 'select' | 'checkbox' | 'switch' | 'date' | 'color' | 'rating'
@@ -10,6 +12,8 @@
10
12
  required?: boolean
11
13
  placeholder?: string
12
14
  options?: Array<{ value: string | number; label: string }>
15
+ /** Declarative validation rules (see `rules` - email/pattern/min/compare...). */
16
+ rules?: ReadonlyArray<Validator>
13
17
  /** Return an error message, or null/undefined when valid. */
14
18
  validate?: (value: any, values: Record<string, any>) => string | null | undefined
15
19
  /** Span full width in the grid. */
@@ -32,6 +36,7 @@
32
36
  import SvColorInput from './SvColorInput.svelte'
33
37
  import SvRating from './SvRating.svelte'
34
38
  import SvButton from './SvButton.svelte'
39
+ import { runRules } from './validators'
35
40
 
36
41
  type Props = {
37
42
  fields: ReadonlyArray<FormField>
@@ -64,7 +69,8 @@
64
69
  const v = values[name]
65
70
  let err: string | null | undefined = null
66
71
  if (field.required && (v == null || v === '' || (Array.isArray(v) && !v.length))) err = `${field.label} is required`
67
- else if (field.validate) err = field.validate(v, values)
72
+ if (!err && field.rules) err = runRules(v, field.rules, values)
73
+ if (!err && field.validate) err = field.validate(v, values)
68
74
  const next = { ...errors }
69
75
  if (err) next[name] = err
70
76
  else delete next[name]
@@ -7,6 +7,7 @@
7
7
  * The arc/needle geometry + `role="meter"` ARIA live in the headless
8
8
  * `createGauge` core; this component is just one styled renderer over it.
9
9
  */
10
+ import { type EditorDir } from './editor-contract'
10
11
  import { createGauge } from './createGauge.svelte'
11
12
 
12
13
  type Band = { from: number; to: number; color: string }
@@ -28,6 +29,8 @@
28
29
  thickness?: number
29
30
  formatValue?: (v: number) => string
30
31
  ariaLabel?: string
32
+ /** Text direction for the center label / unit. */
33
+ dir?: EditorDir
31
34
  }
32
35
 
33
36
  let {
@@ -43,8 +46,11 @@
43
46
  thickness = 14,
44
47
  formatValue,
45
48
  ariaLabel,
49
+ dir,
46
50
  }: Props = $props()
47
51
 
52
+ const resolvedDir = $derived(dir === 'ltr' || dir === 'rtl' ? dir : undefined)
53
+
48
54
  const gauge = createGauge({
49
55
  value: () => value,
50
56
  min: () => min,
@@ -63,7 +69,7 @@
63
69
  const display = $derived(label ?? `${formatValue ? formatValue(clamped) : Math.round(clamped)}${unit}`)
64
70
  </script>
65
71
 
66
- <div class="sv-gauge" {...gauge.rootProps()}>
72
+ <div class="sv-gauge" dir={resolvedDir} {...gauge.rootProps()}>
67
73
  <svg viewBox={`0 0 ${size} ${size}`} width={size} height={size} class="sv-gauge__svg">
68
74
  <!-- track -->
69
75
  <path d={arcPath(min, max, r)} class="sv-gauge__track" fill="none" stroke-width={thickness} stroke-linecap="round" />
@@ -441,6 +441,28 @@ export function createSvGridController<
441
441
  viewportVersion;
442
442
  return scrollContainer ? scrollContainer.clientHeight : 0;
443
443
  });
444
+
445
+ // --- responsive (narrow-container) mode ---
446
+ const responsiveBreakpoint = $derived(
447
+ props.responsive && typeof props.responsive === "object" && props.responsive.breakpoint != null
448
+ ? props.responsive.breakpoint
449
+ : 640,
450
+ );
451
+ // Below the breakpoint: un-pin columns (pan the whole grid), suspend
452
+ // fitColumns, and hide `hideBelow` columns. Guarded on width > 0 so it never
453
+ // triggers before the grid has measured.
454
+ const isNarrowResponsive = $derived(
455
+ !!props.responsive && viewportWidth > 0 && viewportWidth < responsiveBreakpoint,
456
+ );
457
+ const EMPTY_PINNING = { left: [] as string[], right: [] as string[] };
458
+ const effectivePinning = $derived(isNarrowResponsive ? EMPTY_PINNING : columnPinning);
459
+ // A column with `hideBelow: N` is dropped while `responsive` is on and the
460
+ // grid is narrower than N px (reads viewportWidth so it re-runs on resize).
461
+ function isHiddenByResponsive(column: { columnDef?: { hideBelow?: number } }): boolean {
462
+ if (!props.responsive) return false;
463
+ const hb = column.columnDef?.hideBelow;
464
+ return hb != null && viewportWidth > 0 && viewportWidth < hb;
465
+ }
444
466
  const scrollMetrics = $derived.by(() => {
445
467
  scrollVersion;
446
468
  viewportVersion;
@@ -698,7 +720,12 @@ export function createSvGridController<
698
720
  const allColumns = $derived.by(() => {
699
721
  let raw = grid
700
722
  .getAllColumns()
701
- .filter((column) => !hiddenColumns[column.id] && !hiddenByGroupCollapse[column.id]);
723
+ .filter(
724
+ (column) =>
725
+ !hiddenColumns[column.id] &&
726
+ !hiddenByGroupCollapse[column.id] &&
727
+ !isHiddenByResponsive(column),
728
+ );
702
729
  // Apply user reorder (if any). Unknown ids in userColumnOrder are
703
730
  // skipped; columns not in userColumnOrder keep their original
704
731
  // relative order after the user-ordered ones.
@@ -715,8 +742,8 @@ export function createSvGridController<
715
742
  }
716
743
  raw = ordered;
717
744
  }
718
- const leftIds = columnPinning.left;
719
- const rightIds = columnPinning.right;
745
+ const leftIds = effectivePinning.left;
746
+ const rightIds = effectivePinning.right;
720
747
  if (!leftIds.length && !rightIds.length) return raw;
721
748
  const pinned = new Set([...leftIds, ...rightIds]);
722
749
  const findById = (id: string) => raw.find((column) => column.id === id);
@@ -907,14 +934,14 @@ export function createSvGridController<
907
934
  const selectionWidth = showRowSelectionEffective ? selectionColumnWidth : 0;
908
935
  const left: Record<string, number> = {};
909
936
  let leftAcc = rowNumberWidth + selectionWidth;
910
- for (const id of columnPinning.left) {
937
+ for (const id of effectivePinning.left) {
911
938
  left[id] = leftAcc;
912
939
  leftAcc += getColumnWidth(id);
913
940
  }
914
941
  const right: Record<string, number> = {};
915
942
  let rightAcc = 0;
916
- for (let i = columnPinning.right.length - 1; i >= 0; i -= 1) {
917
- const id = columnPinning.right[i];
943
+ for (let i = effectivePinning.right.length - 1; i >= 0; i -= 1) {
944
+ const id = effectivePinning.right[i];
918
945
  if (!id) continue;
919
946
  right[id] = rightAcc;
920
947
  rightAcc += getColumnWidth(id);
@@ -1471,8 +1498,8 @@ export function createSvGridController<
1471
1498
  // that edge and the window are also rendered; negligible for typical grids,
1472
1499
  // and correctness beats shaving a few off-screen cells.)
1473
1500
  const window = virtualColumns;
1474
- const hasLeft = columnPinning.left.length > 0;
1475
- const hasRight = columnPinning.right.length > 0;
1501
+ const hasLeft = effectivePinning.left.length > 0;
1502
+ const hasRight = effectivePinning.right.length > 0;
1476
1503
  if ((!hasLeft && !hasRight) || window.length === 0) return window;
1477
1504
 
1478
1505
  const firstIdx = window[0]!.index;
@@ -1828,7 +1855,8 @@ export function createSvGridController<
1828
1855
  // Track viewport size (not scrollVersion) so we don't recompute on
1829
1856
  // every scroll - only when the container actually resizes.
1830
1857
  viewportVersion;
1831
- if (!props.fitColumns) return null;
1858
+ // Narrow responsive mode pans instead of scaling, so skip fit scaling.
1859
+ if (!props.fitColumns || isNarrowResponsive) return null;
1832
1860
  const cols = grid.getAllColumns().filter((c) => !hiddenColumns[c.id]);
1833
1861
  if (!cols.length) return null;
1834
1862
  const rowNumberWidth = showRowNumbersEffective ? rowNumberColumnWidth : 0;
@@ -2016,11 +2044,39 @@ export function createSvGridController<
2016
2044
  return map;
2017
2045
  });
2018
2046
 
2047
+ // Server-side set-filter values: when a column's filter menu opens and the
2048
+ // consumer provides `serverFilterValues`, fetch the distinct values from the
2049
+ // server once (cached per column) instead of deriving them from the loaded
2050
+ // page - so the checklist shows every value, not just what's on screen.
2051
+ let serverFacetValues = $state<Record<string, Array<string>>>({});
2052
+ let serverFacetLoading = $state<string | null>(null);
2053
+ $effect(() => {
2054
+ const columnId = filterMenuFor ?? columnMenuFor;
2055
+ const fetcher = props.serverFilterValues;
2056
+ if (!columnId || !fetcher || serverFacetValues[columnId]) return;
2057
+ serverFacetLoading = columnId;
2058
+ let cancelled = false;
2059
+ void fetcher(columnId)
2060
+ .then((values) => {
2061
+ if (cancelled) return;
2062
+ serverFacetValues = { ...serverFacetValues, [columnId]: values };
2063
+ serverFacetLoading = null;
2064
+ })
2065
+ .catch(() => {
2066
+ if (!cancelled) serverFacetLoading = null;
2067
+ });
2068
+ return () => {
2069
+ cancelled = true;
2070
+ };
2071
+ });
2072
+
2019
2073
  const columnMenuFacetValues = $derived.by(() => {
2020
2074
  // The funnel popover drives via `filterMenuFor`; the column menu's Filter
2021
2075
  // tab drives via `columnMenuFor`. Support whichever is open.
2022
2076
  const columnId = filterMenuFor ?? columnMenuFor;
2023
2077
  if (!columnId) return [] as Array<string>;
2078
+ // Server-provided distinct values win (fetched + cached above).
2079
+ if (props.serverFilterValues) return serverFacetValues[columnId] ?? [];
2024
2080
  const column = allColumns.find((entry) => entry.id === columnId);
2025
2081
  if (!column) return [] as Array<string>;
2026
2082
  // Range-bucketed facets for numeric / date columns with many values.
@@ -2150,6 +2206,8 @@ export function createSvGridController<
2150
2206
  get MIN_COLUMN_WIDTH() { return MIN_COLUMN_WIDTH; },
2151
2207
  get columnPinning() { return columnPinning; },
2152
2208
  set columnPinning(v) { columnPinning = v as never; },
2209
+ get effectivePinning() { return effectivePinning; },
2210
+ get isNarrowResponsive() { return isNarrowResponsive; },
2153
2211
  get columnVirtualizerVersion() { return columnVirtualizerVersion; },
2154
2212
  set columnVirtualizerVersion(v) { columnVirtualizerVersion = v as never; },
2155
2213
  get gridStateVersion() { return gridStateVersion; },
@@ -2450,6 +2508,7 @@ export function createSvGridController<
2450
2508
  get buildBuckets() { return buildBuckets; },
2451
2509
  get isInBucket() { return isInBucket; },
2452
2510
  get facetBucketsByColumn() { return facetBucketsByColumn; },
2511
+ get serverFacetLoading() { return serverFacetLoading; },
2453
2512
  get columnMenuFacetValues() { return columnMenuFacetValues; },
2454
2513
  get columnMenuVisibleFacets() { return columnMenuVisibleFacets; },
2455
2514
  get isFacetChecked() { return isFacetChecked; },
package/src/SvGrid.css CHANGED
@@ -730,6 +730,13 @@
730
730
  background: var(--sg-header-bg, #f5f7fb);
731
731
  }
732
732
 
733
+ /* Responsive (narrow) mode: smooth momentum touch panning, and let touch
734
+ gestures pan the grid freely (the wheel-trap contain stays for pointer). */
735
+ .sv-grid-container.sv-grid-narrow {
736
+ -webkit-overflow-scrolling: touch;
737
+ scroll-behavior: auto;
738
+ }
739
+
733
740
  .sv-grid-container {
734
741
  scrollbar-width: auto;
735
742
  -ms-overflow-style: auto;
@@ -2341,3 +2348,29 @@ select.sv-grid-fr-editor {
2341
2348
  .sv-grid-filter-operator-btn.is-open {
2342
2349
  opacity: 1;
2343
2350
  }
2351
+
2352
+ /* Kanban board mode search box (board.searchable) */
2353
+ .sv-grid-board-search {
2354
+ display: flex;
2355
+ align-items: center;
2356
+ gap: 6px;
2357
+ margin-bottom: 8px;
2358
+ padding: 5px 9px;
2359
+ border: 1px solid var(--sg-border, #e4e7ec);
2360
+ border-radius: var(--sg-radius, 8px);
2361
+ background: var(--sg-bg, #fff);
2362
+ color: color-mix(in srgb, var(--sg-fg, #101828) 55%, transparent);
2363
+ max-width: 280px;
2364
+ }
2365
+ .sv-grid-board-search:focus-within {
2366
+ border-color: var(--sg-accent, #3b82f6);
2367
+ }
2368
+ .sv-grid-board-search input {
2369
+ flex: 1 1 auto;
2370
+ border: 0;
2371
+ outline: none;
2372
+ background: transparent;
2373
+ font: inherit;
2374
+ font-size: 0.82rem;
2375
+ color: var(--sg-fg, #101828);
2376
+ }
package/src/SvGrid.svelte CHANGED
@@ -25,6 +25,12 @@
25
25
  import { buildSparkline, toSparklineValues } from "./sparkline";
26
26
  import SvGridDropdown from "./SvGridDropdown.svelte";
27
27
  import SvDateTimePicker from "./SvDateTimePicker.svelte";
28
+ import {
29
+ hasCellEditor,
30
+ getCellEditor,
31
+ resolveEditorProps,
32
+ type CellEditorContext,
33
+ } from "./editor-registry";
28
34
  import { timeStringToDate, dateToTimeString } from "./SvGrid.helpers";
29
35
  import type {
30
36
  Props,
@@ -49,8 +55,20 @@
49
55
  import { createSvGridController } from "./SvGrid.controller.svelte";
50
56
  import GridMenus from "./GridMenus.svelte";
51
57
  import GridFooter from "./GridFooter.svelte";
58
+ import SvGridBoard from "./SvGridBoard.svelte";
52
59
  let props: Props<TFeatures, TData> = $props();
53
60
  const ctrl = createSvGridController(props);
61
+ // Kanban board mode: when `board` is set the grid renders lanes of cards
62
+ // instead of the table (see SvGridBoard). Narrowed derived so the template
63
+ // branch can pass it non-null.
64
+ const boardConfig = $derived(props.board);
65
+ // The board renders the grid's FILTERED + SORTED rows (not raw data), so the
66
+ // search box / column filters / sort all flow through to the lanes.
67
+ const boardData = $derived(
68
+ ctrl.allRowsBeforePagination
69
+ .filter((r) => !ctrl.isGroupRow(r))
70
+ .map((r) => r.original),
71
+ );
54
72
 
55
73
  // ---- View facade: re-bind the controller's reactive members as locals so the
56
74
  // markup stays identical. Assignable state + bindings + DOM refs use c.* directly.
@@ -127,6 +145,16 @@
127
145
  const hasConditionalFormats = $derived(ctrl.hasConditionalFormats);
128
146
  const cellConditionalFormat = $derived(ctrl.cellConditionalFormat);
129
147
  const isGroupRow = $derived(ctrl.isGroupRow);
148
+ // Server-side group / tree a11y: aria-level on every tree row, aria-expanded
149
+ // on the expandable ones. Undefined (attribute omitted) when serverGroup is off.
150
+ const serverGroup = $derived(props.serverGroup);
151
+ function sgAriaLevel(row: Row<TData>): number | undefined {
152
+ return serverGroup ? serverGroup.level(row.original as TData) + 1 : undefined;
153
+ }
154
+ function sgAriaExpanded(row: Row<TData>): boolean | undefined {
155
+ if (!serverGroup || !serverGroup.isGroup(row.original as TData)) return undefined;
156
+ return serverGroup.expanded?.(row.original as TData) ?? false;
157
+ }
130
158
  const sortDirectionByColumn = $derived(ctrl.sortDirectionByColumn);
131
159
  const groupingColumns = $derived(ctrl.groupingColumns);
132
160
  const paginationState = $derived(ctrl.paginationState);
@@ -202,6 +230,22 @@
202
230
  return "sv-grid-cell-flash";
203
231
  }
204
232
 
233
+ // Keyboard-accessible column resize (#79): focus a resize handle and use the
234
+ // arrow keys (Shift = fine 1px step). Complements the pointer-drag resize.
235
+ function resizeColumnByKeyboard(e: KeyboardEvent, columnId: string) {
236
+ let delta = 0;
237
+ const step = e.shiftKey ? 1 : 10;
238
+ if (e.key === "ArrowLeft") delta = -step;
239
+ else if (e.key === "ArrowRight") delta = step;
240
+ else return;
241
+ e.preventDefault();
242
+ const current = ctrl.getColumnWidth(columnId);
243
+ ctrl.columnWidths = {
244
+ ...ctrl.columnWidths,
245
+ [columnId]: Math.max(40, current + delta),
246
+ };
247
+ }
248
+
205
249
  // ---- Full-row editing -------------------------------------------------
206
250
  const fullRowEdit = $derived(ctrl.fullRowEdit);
207
251
  // Commit the whole row when the user clicks away from its editors (Excel /
@@ -282,6 +326,27 @@
282
326
  const updateEditingCellValue = $derived(ctrl.updateEditingCellValue);
283
327
  const onEditorKeyDown = $derived(ctrl.onEditorKeyDown);
284
328
  const focusOnMount = $derived(ctrl.focusOnMount);
329
+
330
+ // Build the interaction context handed to a CUSTOM cell editor registered via
331
+ // `registerCellEditor`. Maps the grid's editing lifecycle onto the uniform
332
+ // change / commit / cancel contract every registered editor speaks.
333
+ function buildRegisteredEditorContext(): CellEditorContext {
334
+ const cell = ctrl.editingCell;
335
+ return {
336
+ value: cell?.value,
337
+ rowId: cell?.rowId ?? "",
338
+ columnId: cell?.columnId ?? "",
339
+ onChange: (v: unknown) => updateEditingCellValue(v),
340
+ onCommit: (v?: unknown) => {
341
+ if (v !== undefined) updateEditingCellValue(v);
342
+ saveEditingCell();
343
+ },
344
+ onCancel: () => {
345
+ ctrl.editingCell = null;
346
+ ctrl.gridRootEl?.focus({ preventScroll: true });
347
+ },
348
+ };
349
+ }
285
350
  const onHeaderSortClick = $derived(ctrl.onHeaderSortClick);
286
351
  const onGridKeyDown = $derived(ctrl.onGridKeyDown);
287
352
  const onGridPaste = $derived(ctrl.onGridPaste);
@@ -323,6 +388,39 @@
323
388
  <div class="sv-grid-state sv-grid-state-error" role="alert">
324
389
  {props.error}
325
390
  </div>
391
+ {:else if boardConfig}
392
+ <div
393
+ class="sv-grid-root sv-grid-board-root"
394
+ class:sv-grid-root-fill={props.containerHeight === "100%"}
395
+ style={`height: ${
396
+ typeof props.containerHeight === "string"
397
+ ? props.containerHeight
398
+ : `${props.containerHeight ?? 520}px`
399
+ }; display: flex; flex-direction: column;`}
400
+ >
401
+ {#if boardConfig.searchable !== false}
402
+ <label class="sv-grid-board-search">
403
+ <svg viewBox="0 0 16 16" aria-hidden="true" width="14" height="14">
404
+ <circle cx="7" cy="7" r="4.5" fill="none" stroke="currentColor" stroke-width="1.5" />
405
+ <line x1="10.2" y1="10.2" x2="14" y2="14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
406
+ </svg>
407
+ <input
408
+ type="search"
409
+ placeholder={boardConfig.searchPlaceholder ?? "Search cards..."}
410
+ bind:value={ctrl.globalFilter}
411
+ aria-label="Search cards"
412
+ />
413
+ </label>
414
+ {/if}
415
+ <div style="flex: 1 1 auto; min-height: 0;">
416
+ <SvGridBoard
417
+ data={boardData}
418
+ columns={props.columns}
419
+ board={boardConfig}
420
+ getRowId={props.getRowId}
421
+ />
422
+ </div>
423
+ </div>
326
424
  {:else}
327
425
  {#snippet icon(name: string)}
328
426
  <svg
@@ -874,6 +972,12 @@
874
972
  onblur={() => saveEditingCell()}
875
973
  onkeydown={onEditorKeyDown}
876
974
  />
975
+ {:else if hasCellEditor(String(ctrl.editingCell?.editorType ?? ""))}
976
+ <!-- Custom editor registered via `registerCellEditor(type, Component)`:
977
+ mount it and hand it the uniform change / commit / cancel context. -->
978
+ {@const _reg = getCellEditor(String(ctrl.editingCell?.editorType))!}
979
+ {@const CustomCellEditor = _reg.component}
980
+ <CustomCellEditor {...resolveEditorProps(_reg, buildRegisteredEditorContext())} />
877
981
  {:else}
878
982
  <input
879
983
  use:focusOnMount
@@ -1246,6 +1350,7 @@
1246
1350
  <div
1247
1351
  class="sv-grid-container sv-grid-container-custom-scrollbars"
1248
1352
  class:sv-grid-has-vscroll={hasMeasured && hasVerticalOverflow}
1353
+ class:sv-grid-narrow={ctrl.isNarrowResponsive}
1249
1354
  bind:this={ctrl.scrollContainer}
1250
1355
  onscroll={onBodyScroll}
1251
1356
  style={`overflow: auto; position: relative; height: calc(100% - ${hasMeasured && hasHorizontalOverflow ? 16 : 0}px);`}
@@ -1258,6 +1363,7 @@
1258
1363
  activeDescendantId,
1259
1364
  rowCount: allRows.length,
1260
1365
  colCount: allColumns.length,
1366
+ treegrid: !!props.serverGroup,
1261
1367
  })}
1262
1368
  onkeydown={onGridKeyDown}
1263
1369
  onpaste={onGridPaste}
@@ -1544,7 +1650,7 @@
1544
1650
  class:is-active={isColumnFiltered(
1545
1651
  header.column.id,
1546
1652
  )}
1547
- aria-label="Filter"
1653
+ aria-label={`Filter ${toolPanelHeaderLabel(header.column)}`}
1548
1654
  aria-haspopup="menu"
1549
1655
  onclick={(event) =>
1550
1656
  openFilterMenu(event, header.column.id)}
@@ -1556,7 +1662,7 @@
1556
1662
  type="button"
1557
1663
  class="sv-grid-col-menu-btn"
1558
1664
  class:is-open={columnMenuFor === header.column.id}
1559
- aria-label="Column menu"
1665
+ aria-label={`${toolPanelHeaderLabel(header.column)} column menu`}
1560
1666
  aria-haspopup="menu"
1561
1667
  onclick={(event) =>
1562
1668
  openColumnMenu(event, header.column.id)}
@@ -1595,9 +1701,12 @@
1595
1701
  header.column.id}
1596
1702
  role="separator"
1597
1703
  aria-orientation="vertical"
1598
- aria-label="Resize column"
1704
+ aria-label={`Resize ${toolPanelHeaderLabel(header.column)}`}
1705
+ tabindex="0"
1599
1706
  onpointerdown={(event) =>
1600
1707
  startColumnResize(event, header.column.id)}
1708
+ onkeydown={(event) =>
1709
+ resizeColumnByKeyboard(event, header.column.id)}
1601
1710
  ondblclick={(event) => event.stopPropagation()}
1602
1711
  ></div>
1603
1712
  {/if}
@@ -1789,6 +1898,8 @@
1789
1898
  rowIndex % 2 === 1}
1790
1899
  class:sv-grid-row-draggable={rowDragManagedEffective}
1791
1900
  {...getGridRowA11yProps(rowIndex + 1)}
1901
+ aria-level={sgAriaLevel(row)}
1902
+ aria-expanded={sgAriaExpanded(row)}
1792
1903
  {...rowDragAttrs(rowIndex)}
1793
1904
  style={`height: ${rowItem.size}px;`}
1794
1905
  >
@@ -2038,6 +2149,8 @@
2038
2149
  rowIndex % 2 === 1}
2039
2150
  class:sv-grid-row-draggable={rowDragManagedEffective}
2040
2151
  {...getGridRowA11yProps(rowIndex + 1)}
2152
+ aria-level={sgAriaLevel(row)}
2153
+ aria-expanded={sgAriaExpanded(row)}
2041
2154
  {...rowDragAttrs(rowIndex)}
2042
2155
  >
2043
2156
  {#if showRowNumbersEffective}