@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,88 @@
1
+ /**
2
+ * Shared item shapes for the app-UI components that have no headless core
3
+ * (SvBreadcrumb, SvStepper). Kept in a plain .ts so they can be exported from a
4
+ * component's module script by re-export - a bare `export type` DECLARATION in a
5
+ * `<script module>` trips the Svelte/Vite parser, but a re-export is fine.
6
+ */
7
+
8
+ /** One crumb in a breadcrumb trail. `href` renders a link; `onClick` a button. */
9
+ export type BreadcrumbItem = {
10
+ label: string
11
+ href?: string
12
+ onClick?: () => void
13
+ /** Optional leading icon (any string: emoji, char, or a font-icon class glyph). */
14
+ icon?: string
15
+ }
16
+
17
+ /** One step in a stepper. */
18
+ export type StepItem = {
19
+ label: string
20
+ description?: string
21
+ /** Marks the step skippable (shown as "Optional"). */
22
+ optional?: boolean
23
+ }
24
+
25
+ /** One option in a multi-select. */
26
+ export type MultiSelectOption = {
27
+ value: string | number
28
+ label: string
29
+ disabled?: boolean
30
+ }
31
+
32
+ /** A node in a tree-select. */
33
+ export type TreeSelectNode = {
34
+ value: string | number
35
+ label: string
36
+ children?: TreeSelectNode[]
37
+ disabled?: boolean
38
+ }
39
+
40
+ /** A column shown in a grid-select dropdown. */
41
+ export type GridSelectColumn = {
42
+ /** Key into each option row. */
43
+ field: string
44
+ header: string
45
+ /** Any CSS grid track size (e.g. '1fr', '80px'). Default '1fr'. */
46
+ width?: string
47
+ }
48
+
49
+ /** One action in a command palette (SvCommand). */
50
+ export type CommandItem = {
51
+ id: string
52
+ label: string
53
+ /** Right-aligned hint / description. */
54
+ hint?: string
55
+ /** Section header this command groups under. */
56
+ group?: string
57
+ /** Leading glyph (emoji / char). */
58
+ icon?: string
59
+ /** Right-aligned keyboard shortcut hint, e.g. "⌘S". */
60
+ shortcut?: string
61
+ /** Extra searchable terms beyond the label. */
62
+ keywords?: string
63
+ disabled?: boolean
64
+ /** Run when chosen. */
65
+ onRun?: () => void
66
+ }
67
+
68
+ /** One step in a guided tour. */
69
+ export type TourStep = {
70
+ /** Element to spotlight: a CSS selector or the element itself. Omit for a
71
+ * centered, target-less step (intro / outro). */
72
+ target?: string | HTMLElement
73
+ title?: string
74
+ content: string
75
+ }
76
+
77
+ /** One entry in a timeline. */
78
+ export type TimelineItem = {
79
+ id?: string | number
80
+ title: string
81
+ description?: string
82
+ /** Right-aligned timestamp/label. */
83
+ time?: string
84
+ /** Marker colour (any CSS colour). Defaults to the accent. */
85
+ color?: string
86
+ /** Optional leading glyph inside the marker (emoji / char). */
87
+ icon?: string
88
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Rendering tests for the presentational display trio: SvBadge, SvSkeleton,
3
+ * SvCard - variant/prop-driven classes, a11y roles, and conditional regions.
4
+ */
5
+ import { describe, expect, it } from 'vitest'
6
+ import { mount, unmount, flushSync } from 'svelte'
7
+ import SvBadge from './SvBadge.svelte'
8
+ import SvSkeleton from './SvSkeleton.svelte'
9
+ import SvCard from './SvCard.svelte'
10
+
11
+ function mountOn<T extends Record<string, unknown>>(Comp: any, props: T) {
12
+ const target = document.createElement('div')
13
+ document.body.appendChild(target)
14
+ const app = mount(Comp, { target, props: props as any })
15
+ flushSync()
16
+ return { target, destroy: () => { unmount(app); target.remove() } }
17
+ }
18
+
19
+ describe('SvBadge', () => {
20
+ it('applies variant + size classes and pill by default', () => {
21
+ const { target, destroy } = mountOn(SvBadge, { variant: 'success', size: 'sm' })
22
+ try {
23
+ const el = target.querySelector('.sv-badge')!
24
+ expect(el.classList.contains('sv-badge--success')).toBe(true)
25
+ expect(el.classList.contains('sv-badge--sm')).toBe(true)
26
+ expect(el.classList.contains('is-pill')).toBe(true)
27
+ } finally { destroy() }
28
+ })
29
+
30
+ it('renders a status dot when dot is set', () => {
31
+ const { target, destroy } = mountOn(SvBadge, { variant: 'danger', dot: true })
32
+ try {
33
+ expect(target.querySelector('.sv-badge__dot')).not.toBeNull()
34
+ } finally { destroy() }
35
+ })
36
+ })
37
+
38
+ describe('SvSkeleton', () => {
39
+ it('renders one box per line for text variant with a shorter last line', () => {
40
+ const { target, destroy } = mountOn(SvSkeleton, { variant: 'text', lines: 3 })
41
+ try {
42
+ const boxes = target.querySelectorAll('.sv-skel__box')
43
+ expect(boxes).toHaveLength(3)
44
+ expect(boxes[2]!.classList.contains('is-last')).toBe(true)
45
+ expect(target.querySelector('.sv-skel')!.getAttribute('aria-busy')).toBe('true')
46
+ } finally { destroy() }
47
+ })
48
+
49
+ it('renders a single circle box for circle variant', () => {
50
+ const { target, destroy } = mountOn(SvSkeleton, { variant: 'circle' })
51
+ try {
52
+ const boxes = target.querySelectorAll('.sv-skel__box')
53
+ expect(boxes).toHaveLength(1)
54
+ expect(boxes[0]!.classList.contains('sv-skel__box--circle')).toBe(true)
55
+ } finally { destroy() }
56
+ })
57
+ })
58
+
59
+ describe('SvCard', () => {
60
+ it('renders a header only when title/subtitle/header provided', () => {
61
+ const bare = mountOn(SvCard, {})
62
+ try {
63
+ expect(bare.target.querySelector('.sv-card__header')).toBeNull()
64
+ } finally { bare.destroy() }
65
+
66
+ const titled = mountOn(SvCard, { title: 'Revenue', subtitle: 'Last 30 days' })
67
+ try {
68
+ expect(titled.target.querySelector('.sv-card__title')!.textContent).toBe('Revenue')
69
+ expect(titled.target.querySelector('.sv-card__subtitle')!.textContent).toBe('Last 30 days')
70
+ } finally { titled.destroy() }
71
+ })
72
+
73
+ it('flush removes body padding via a modifier class', () => {
74
+ const { target, destroy } = mountOn(SvCard, { flush: true })
75
+ try {
76
+ expect(target.querySelector('.sv-card__body')!.classList.contains('is-flush')).toBe(true)
77
+ } finally { destroy() }
78
+ })
79
+ })
@@ -93,7 +93,7 @@ describe('SvMaskedInput', () => {
93
93
  onChange: (m: string, r: string) => { masked = m; raw = r },
94
94
  })
95
95
  try {
96
- const input = target.querySelector<HTMLInputElement>('.sv-masked')!
96
+ const input = target.querySelector<HTMLInputElement>('.sv-masked__input')!
97
97
  input.value = '1234567890'
98
98
  input.dispatchEvent(new Event('input', { bubbles: true }))
99
99
  flushSync()
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Component tests for the Tier-1 status/display batch: SvAlert, SvEmptyState,
3
+ * SvDivider, SvChip, SvStat, SvTimeline.
4
+ */
5
+ import { describe, expect, it, vi } from 'vitest'
6
+ import { mount, unmount, flushSync } from 'svelte'
7
+ import SvAlert from './SvAlert.svelte'
8
+ import SvEmptyState from './SvEmptyState.svelte'
9
+ import SvDivider from './SvDivider.svelte'
10
+ import SvChip from './SvChip.svelte'
11
+ import SvStat from './SvStat.svelte'
12
+ import SvTimeline from './SvTimeline.svelte'
13
+
14
+ function mountOn(Comp: any, props: Record<string, unknown>) {
15
+ const target = document.createElement('div')
16
+ document.body.appendChild(target)
17
+ const app = mount(Comp, { target, props: props as any })
18
+ flushSync()
19
+ return { target, destroy: () => { unmount(app); target.remove() } }
20
+ }
21
+
22
+ describe('SvAlert', () => {
23
+ it('applies the variant class and uses role=alert for danger', () => {
24
+ const { target, destroy } = mountOn(SvAlert, { variant: 'danger', title: 'Failed' })
25
+ try {
26
+ const el = target.querySelector('.sv-alert')!
27
+ expect(el.classList.contains('sv-alert--danger')).toBe(true)
28
+ expect(el.getAttribute('role')).toBe('alert')
29
+ expect(target.querySelector('.sv-alert__title')!.textContent).toBe('Failed')
30
+ } finally { destroy() }
31
+ })
32
+
33
+ it('dismissible: the x removes the alert and fires onDismiss', () => {
34
+ const onDismiss = vi.fn()
35
+ const { target, destroy } = mountOn(SvAlert, { dismissible: true, onDismiss })
36
+ try {
37
+ target.querySelector<HTMLButtonElement>('.sv-alert__x')!.click()
38
+ flushSync()
39
+ expect(onDismiss).toHaveBeenCalled()
40
+ expect(target.querySelector('.sv-alert')).toBeNull()
41
+ } finally { destroy() }
42
+ })
43
+ })
44
+
45
+ describe('SvEmptyState', () => {
46
+ it('renders title, description and a default icon', () => {
47
+ const { target, destroy } = mountOn(SvEmptyState, { title: 'Nothing here', description: 'Add one.' })
48
+ try {
49
+ expect(target.querySelector('.sv-empty__title')!.textContent).toBe('Nothing here')
50
+ expect(target.querySelector('.sv-empty__desc')!.textContent).toBe('Add one.')
51
+ expect(target.querySelector('.sv-empty__icon svg')).not.toBeNull()
52
+ } finally { destroy() }
53
+ })
54
+ })
55
+
56
+ describe('SvDivider', () => {
57
+ it('is a horizontal separator by default', () => {
58
+ const { target, destroy } = mountOn(SvDivider, {})
59
+ try {
60
+ const el = target.querySelector('.sv-divider')!
61
+ expect(el.getAttribute('role')).toBe('separator')
62
+ expect(el.classList.contains('sv-divider--h')).toBe(true)
63
+ } finally { destroy() }
64
+ })
65
+
66
+ it('renders a label and the has-label class', () => {
67
+ const { target, destroy } = mountOn(SvDivider, { label: 'OR' })
68
+ try {
69
+ const el = target.querySelector('.sv-divider')!
70
+ expect(el.classList.contains('has-label')).toBe(true)
71
+ expect(target.querySelector('.sv-divider__label')!.textContent).toBe('OR')
72
+ } finally { destroy() }
73
+ })
74
+
75
+ it('vertical orientation sets aria-orientation', () => {
76
+ const { target, destroy } = mountOn(SvDivider, { orientation: 'vertical' })
77
+ try {
78
+ const el = target.querySelector('.sv-divider')!
79
+ expect(el.classList.contains('sv-divider--v')).toBe(true)
80
+ expect(el.getAttribute('aria-orientation')).toBe('vertical')
81
+ } finally { destroy() }
82
+ })
83
+ })
84
+
85
+ describe('SvChip', () => {
86
+ it('removable: the x fires onRemove', () => {
87
+ const onRemove = vi.fn()
88
+ const { target, destroy } = mountOn(SvChip, { removable: true, onRemove, variant: 'accent' })
89
+ try {
90
+ expect(target.querySelector('.sv-chip')!.classList.contains('sv-chip--accent')).toBe(true)
91
+ target.querySelector<HTMLButtonElement>('.sv-chip__x')!.click()
92
+ expect(onRemove).toHaveBeenCalled()
93
+ } finally { destroy() }
94
+ })
95
+
96
+ it('onClick makes the label a button', () => {
97
+ const onClick = vi.fn()
98
+ const { target, destroy } = mountOn(SvChip, { onClick })
99
+ try {
100
+ const btn = target.querySelector<HTMLButtonElement>('.sv-chip__label--btn')!
101
+ expect(btn).not.toBeNull()
102
+ btn.click()
103
+ expect(onClick).toHaveBeenCalled()
104
+ } finally { destroy() }
105
+ })
106
+ })
107
+
108
+ describe('SvStat', () => {
109
+ it('renders the value and infers an up/good trend from a positive delta', () => {
110
+ const { target, destroy } = mountOn(SvStat, { label: 'Revenue', value: '$48k', delta: 12.4 })
111
+ try {
112
+ expect(target.querySelector('.sv-stat__value')!.textContent).toBe('$48k')
113
+ const delta = target.querySelector('.sv-stat__delta')!
114
+ expect(delta.textContent).toContain('+12.4%')
115
+ expect(delta.classList.contains('is-good')).toBe(true)
116
+ } finally { destroy() }
117
+ })
118
+
119
+ it('invert makes a downward delta good (e.g. error rate)', () => {
120
+ const { target, destroy } = mountOn(SvStat, { label: 'Errors', value: '0.4%', delta: -20, invert: true })
121
+ try {
122
+ const delta = target.querySelector('.sv-stat__delta')!
123
+ expect(delta.classList.contains('is-good')).toBe(true)
124
+ } finally { destroy() }
125
+ })
126
+ })
127
+
128
+ describe('SvTimeline', () => {
129
+ it('renders an entry per item with title/time/description', () => {
130
+ const items = [
131
+ { title: 'Placed', time: '09:12' },
132
+ { title: 'Shipped', time: '14:40', description: 'Left the warehouse' },
133
+ ]
134
+ const { target, destroy } = mountOn(SvTimeline, { items })
135
+ try {
136
+ expect(target.querySelectorAll('.sv-timeline__item')).toHaveLength(2)
137
+ expect([...target.querySelectorAll('.sv-timeline__title')].map((t) => t.textContent)).toEqual(['Placed', 'Shipped'])
138
+ expect(target.querySelector('.sv-timeline__desc')!.textContent).toBe('Left the warehouse')
139
+ } finally { destroy() }
140
+ })
141
+ })
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Component tests for the Tier-1 text editors: SvTextInput, SvTextArea and
3
+ * SvOtpInput - value emit, the commit/cancel interaction contract, and OTP
4
+ * auto-advance / paste distribution.
5
+ */
6
+ import { describe, expect, it, vi } from 'vitest'
7
+ import { mount, unmount, flushSync } from 'svelte'
8
+ import SvTextInput from './SvTextInput.svelte'
9
+ import SvTextArea from './SvTextArea.svelte'
10
+ import SvOtpInput from './SvOtpInput.svelte'
11
+ import SvDurationInput from './SvDurationInput.svelte'
12
+
13
+ function mountOn(Comp: any, props: Record<string, unknown>) {
14
+ const target = document.createElement('div')
15
+ document.body.appendChild(target)
16
+ const app = mount(Comp, { target, props: props as any })
17
+ flushSync()
18
+ return { target, destroy: () => { unmount(app); target.remove() } }
19
+ }
20
+
21
+ describe('SvTextInput', () => {
22
+ it('emits onChange on input', () => {
23
+ const onChange = vi.fn()
24
+ const { target, destroy } = mountOn(SvTextInput, { value: '', onChange })
25
+ try {
26
+ const input = target.querySelector<HTMLInputElement>('.sv-text__input')!
27
+ input.value = 'hello'
28
+ input.dispatchEvent(new Event('input', { bubbles: true }))
29
+ expect(onChange).toHaveBeenCalledWith('hello')
30
+ } finally { destroy() }
31
+ })
32
+
33
+ it('Enter commits and Escape cancels', () => {
34
+ const onCommit = vi.fn(), onCancel = vi.fn()
35
+ const { target, destroy } = mountOn(SvTextInput, { value: 'abc', onCommit, onCancel })
36
+ try {
37
+ const input = target.querySelector<HTMLInputElement>('.sv-text__input')!
38
+ input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
39
+ expect(onCommit).toHaveBeenCalledWith('abc')
40
+ input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
41
+ expect(onCancel).toHaveBeenCalled()
42
+ } finally { destroy() }
43
+ })
44
+
45
+ it('clearable shows a clear button that empties the value', () => {
46
+ const onChange = vi.fn()
47
+ const { target, destroy } = mountOn(SvTextInput, { value: 'x', clearable: true, onChange })
48
+ try {
49
+ const clear = target.querySelector<HTMLButtonElement>('.sv-text__clear')!
50
+ expect(clear).not.toBeNull()
51
+ clear.click()
52
+ expect(onChange).toHaveBeenCalledWith('')
53
+ } finally { destroy() }
54
+ })
55
+ })
56
+
57
+ describe('SvTextArea', () => {
58
+ it('Ctrl+Enter commits, Escape cancels, Enter alone does not commit', () => {
59
+ const onCommit = vi.fn(), onCancel = vi.fn()
60
+ const { target, destroy } = mountOn(SvTextArea, { value: 'note', onCommit, onCancel })
61
+ try {
62
+ const ta = target.querySelector<HTMLTextAreaElement>('.sv-ta__input')!
63
+ ta.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
64
+ expect(onCommit).not.toHaveBeenCalled()
65
+ ta.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', ctrlKey: true, bubbles: true }))
66
+ expect(onCommit).toHaveBeenCalledWith('note')
67
+ ta.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
68
+ expect(onCancel).toHaveBeenCalled()
69
+ } finally { destroy() }
70
+ })
71
+ })
72
+
73
+ describe('SvOtpInput', () => {
74
+ it('renders one cell per length', () => {
75
+ const { target, destroy } = mountOn(SvOtpInput, { length: 4 })
76
+ try {
77
+ expect(target.querySelectorAll('.sv-otp__cell')).toHaveLength(4)
78
+ } finally { destroy() }
79
+ })
80
+
81
+ it('typing a digit emits onChange and advances focus', () => {
82
+ const onChange = vi.fn()
83
+ const { target, destroy } = mountOn(SvOtpInput, { length: 4, value: '', onChange })
84
+ try {
85
+ const cells = target.querySelectorAll<HTMLInputElement>('.sv-otp__cell')
86
+ cells[0]!.value = '7'
87
+ cells[0]!.dispatchEvent(new Event('input', { bubbles: true }))
88
+ expect(onChange).toHaveBeenCalledWith('7')
89
+ expect(document.activeElement).toBe(cells[1])
90
+ } finally { destroy() }
91
+ })
92
+
93
+ it('paste distributes across cells and fires onComplete when full', () => {
94
+ const onChange = vi.fn(), onComplete = vi.fn()
95
+ const { target, destroy } = mountOn(SvOtpInput, { length: 4, value: '', onChange, onComplete })
96
+ try {
97
+ const cells = target.querySelectorAll<HTMLInputElement>('.sv-otp__cell')
98
+ const e = new Event('paste', { bubbles: true, cancelable: true })
99
+ Object.defineProperty(e, 'clipboardData', { value: { getData: () => '12ab34' } })
100
+ cells[0]!.dispatchEvent(e)
101
+ // numeric mode strips letters -> '1234'
102
+ expect(onChange).toHaveBeenCalledWith('1234')
103
+ expect(onComplete).toHaveBeenCalledWith('1234')
104
+ } finally { destroy() }
105
+ })
106
+ })
107
+
108
+ describe('SvDurationInput', () => {
109
+ it('parses human input to minutes on blur', () => {
110
+ const onChange = vi.fn()
111
+ const { target, destroy } = mountOn(SvDurationInput, { value: null, onChange })
112
+ try {
113
+ const input = target.querySelector<HTMLInputElement>('.sv-dur__input')!
114
+ input.dispatchEvent(new Event('focus', { bubbles: true }))
115
+ input.value = '1h 30m'
116
+ input.dispatchEvent(new Event('input', { bubbles: true }))
117
+ input.dispatchEvent(new Event('blur', { bubbles: true }))
118
+ expect(onChange).toHaveBeenCalledWith(90)
119
+ } finally { destroy() }
120
+ })
121
+
122
+ it('formats the external value as h:mm when unfocused', () => {
123
+ const { target, destroy } = mountOn(SvDurationInput, { value: 125 })
124
+ try {
125
+ const input = target.querySelector<HTMLInputElement>('.sv-dur__input')!
126
+ expect(input.value).toBe('2:05')
127
+ } finally { destroy() }
128
+ })
129
+
130
+ it('Enter commits the parsed value', () => {
131
+ const onCommit = vi.fn()
132
+ const { target, destroy } = mountOn(SvDurationInput, { value: null, onCommit })
133
+ try {
134
+ const input = target.querySelector<HTMLInputElement>('.sv-dur__input')!
135
+ input.dispatchEvent(new Event('focus', { bubbles: true }))
136
+ input.value = '45m'
137
+ input.dispatchEvent(new Event('input', { bubbles: true }))
138
+ input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
139
+ expect(onCommit).toHaveBeenCalledWith(45)
140
+ } finally { destroy() }
141
+ })
142
+ })
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Component tests for the Tier-2 batch: SvCommand (palette), SvAvatarGroup,
3
+ * SvSparkline, SvScrollArea.
4
+ */
5
+ import { afterEach, describe, expect, it, vi } from 'vitest'
6
+ import { mount, unmount, flushSync } from 'svelte'
7
+ import SvCommand from './SvCommand.svelte'
8
+ import SvAvatarGroup from './SvAvatarGroup.svelte'
9
+ import SvSparkline from './SvSparkline.svelte'
10
+ import SvScrollArea from './SvScrollArea.svelte'
11
+
12
+ function mountOn(Comp: any, props: Record<string, unknown>) {
13
+ const target = document.createElement('div')
14
+ document.body.appendChild(target)
15
+ const app = mount(Comp, { target, props: props as any })
16
+ flushSync()
17
+ return { target, destroy: () => { unmount(app); target.remove() } }
18
+ }
19
+
20
+ afterEach(() => { document.body.innerHTML = '' })
21
+
22
+ const commands = [
23
+ { id: 'new', label: 'New invoice', group: 'Create', icon: '+' },
24
+ { id: 'export', label: 'Export CSV', group: 'Data', shortcut: '⌘E' },
25
+ { id: 'settings', label: 'Open settings', group: 'App' },
26
+ ]
27
+
28
+ describe('SvCommand', () => {
29
+ it('opens a portalled palette listing the commands', () => {
30
+ const { destroy } = mountOn(SvCommand, { open: true, commands, hotkey: false })
31
+ try {
32
+ expect(document.body.querySelector('.sv-cmd')).not.toBeNull()
33
+ expect(document.body.querySelectorAll('.sv-cmd__opt')).toHaveLength(3)
34
+ } finally { destroy() }
35
+ })
36
+
37
+ it('fuzzy-filters as you type', () => {
38
+ const { destroy } = mountOn(SvCommand, { open: true, commands, hotkey: false })
39
+ try {
40
+ const input = document.body.querySelector<HTMLInputElement>('.sv-cmd__input')!
41
+ input.value = 'exp'
42
+ input.dispatchEvent(new Event('input', { bubbles: true }))
43
+ flushSync()
44
+ const opts = [...document.body.querySelectorAll('.sv-cmd__opt')].map((o) => o.textContent)
45
+ expect(opts).toHaveLength(1)
46
+ expect(opts[0]).toContain('Export CSV')
47
+ } finally { destroy() }
48
+ })
49
+
50
+ it('ArrowDown + Enter runs the active command and closes', () => {
51
+ const onRun = vi.fn()
52
+ const cmdRun = vi.fn()
53
+ const cmds = [{ id: 'a', label: 'Alpha', onRun: cmdRun }, { id: 'b', label: 'Beta' }]
54
+ const { destroy } = mountOn(SvCommand, { open: true, commands: cmds, onRun, hotkey: false })
55
+ try {
56
+ const panel = document.body.querySelector('.sv-cmd')!
57
+ panel.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }))
58
+ panel.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
59
+ flushSync()
60
+ expect(onRun).toHaveBeenCalledWith(cmds[1]) // moved to Beta
61
+ expect(document.body.querySelector('.sv-cmd')).toBeNull()
62
+ } finally { destroy() }
63
+ })
64
+
65
+ it('clicking an option runs it', () => {
66
+ const onRun = vi.fn()
67
+ const { destroy } = mountOn(SvCommand, { open: true, commands, hotkey: false })
68
+ try {
69
+ // (onRun set via a separate mount would be cleaner; here just assert close)
70
+ const opt = document.body.querySelector<HTMLElement>('.sv-cmd__opt')!
71
+ opt.click()
72
+ flushSync()
73
+ expect(document.body.querySelector('.sv-cmd')).toBeNull()
74
+ void onRun
75
+ } finally { destroy() }
76
+ })
77
+ })
78
+
79
+ describe('SvAvatarGroup', () => {
80
+ it('shows up to max avatars and a +N overflow pill', () => {
81
+ const avatars = [{ name: 'Ada' }, { name: 'Alan' }, { name: 'Grace' }, { name: 'Ken' }, { name: 'Lin' }]
82
+ const { target, destroy } = mountOn(SvAvatarGroup, { avatars, max: 3 })
83
+ try {
84
+ expect(target.querySelectorAll('.sv-avgroup__it')).toHaveLength(3)
85
+ expect(target.querySelector('.sv-avgroup__more')!.textContent).toBe('+2')
86
+ } finally { destroy() }
87
+ })
88
+
89
+ it('no overflow pill when under max', () => {
90
+ const { target, destroy } = mountOn(SvAvatarGroup, { avatars: [{ name: 'Ada' }], max: 4 })
91
+ try {
92
+ expect(target.querySelector('.sv-avgroup__more')).toBeNull()
93
+ } finally { destroy() }
94
+ })
95
+ })
96
+
97
+ describe('SvSparkline', () => {
98
+ it('renders an svg with a line path for line data', () => {
99
+ const { target, destroy } = mountOn(SvSparkline, { data: [3, 7, 4, 9, 6, 11, 8], type: 'line' })
100
+ try {
101
+ const svg = target.querySelector('svg.sv-spark')!
102
+ expect(svg).not.toBeNull()
103
+ expect(svg.querySelector('path')).not.toBeNull()
104
+ } finally { destroy() }
105
+ })
106
+
107
+ it('renders rects for bar data', () => {
108
+ const { target, destroy } = mountOn(SvSparkline, { data: [1, -2, 3, -1, 2], type: 'bar' })
109
+ try {
110
+ expect(target.querySelectorAll('svg.sv-spark rect').length).toBe(5)
111
+ } finally { destroy() }
112
+ })
113
+ })
114
+
115
+ describe('SvScrollArea', () => {
116
+ it('renders a themed scroll container with the given max-height', () => {
117
+ const { target, destroy } = mountOn(SvScrollArea, { maxHeight: '200px' })
118
+ try {
119
+ const el = target.querySelector<HTMLElement>('.sv-scroll')!
120
+ expect(el).not.toBeNull()
121
+ expect(el.style.maxHeight).toBe('200px')
122
+ } finally { destroy() }
123
+ })
124
+ })