@furystack/shades-common-components 13.5.0 → 15.0.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 (540) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/README.md +3 -3
  3. package/esm/components/accordion/accordion-item.d.ts.map +1 -1
  4. package/esm/components/accordion/accordion-item.js +7 -10
  5. package/esm/components/accordion/accordion-item.js.map +1 -1
  6. package/esm/components/accordion/accordion.d.ts +7 -0
  7. package/esm/components/accordion/accordion.d.ts.map +1 -1
  8. package/esm/components/accordion/accordion.js +5 -2
  9. package/esm/components/accordion/accordion.js.map +1 -1
  10. package/esm/components/accordion/accordion.spec.js +91 -50
  11. package/esm/components/accordion/accordion.spec.js.map +1 -1
  12. package/esm/components/alert.js +1 -1
  13. package/esm/components/alert.js.map +1 -1
  14. package/esm/components/app-bar-link.js +1 -1
  15. package/esm/components/app-bar-link.js.map +1 -1
  16. package/esm/components/app-bar.js +1 -1
  17. package/esm/components/app-bar.js.map +1 -1
  18. package/esm/components/avatar.js +1 -1
  19. package/esm/components/avatar.js.map +1 -1
  20. package/esm/components/badge.js +1 -1
  21. package/esm/components/badge.js.map +1 -1
  22. package/esm/components/breadcrumb.js +1 -1
  23. package/esm/components/breadcrumb.js.map +1 -1
  24. package/esm/components/breadcrumb.spec.js +3 -3
  25. package/esm/components/breadcrumb.spec.js.map +1 -1
  26. package/esm/components/button-group.js +4 -4
  27. package/esm/components/button-group.js.map +1 -1
  28. package/esm/components/button.js +1 -1
  29. package/esm/components/button.js.map +1 -1
  30. package/esm/components/button.spec.js +1 -1
  31. package/esm/components/button.spec.js.map +1 -1
  32. package/esm/components/cache-view.js +1 -1
  33. package/esm/components/cache-view.js.map +1 -1
  34. package/esm/components/cache-view.spec.js +2 -2
  35. package/esm/components/cache-view.spec.js.map +1 -1
  36. package/esm/components/card.js +5 -5
  37. package/esm/components/card.js.map +1 -1
  38. package/esm/components/carousel.js +2 -2
  39. package/esm/components/carousel.js.map +1 -1
  40. package/esm/components/chip.d.ts.map +1 -1
  41. package/esm/components/chip.js +5 -3
  42. package/esm/components/chip.js.map +1 -1
  43. package/esm/components/chip.spec.js +42 -0
  44. package/esm/components/chip.spec.js.map +1 -1
  45. package/esm/components/circular-progress.d.ts +2 -4
  46. package/esm/components/circular-progress.d.ts.map +1 -1
  47. package/esm/components/circular-progress.js +3 -6
  48. package/esm/components/circular-progress.js.map +1 -1
  49. package/esm/components/circular-progress.spec.js +19 -14
  50. package/esm/components/circular-progress.spec.js.map +1 -1
  51. package/esm/components/command-palette/command-palette-input.js +1 -1
  52. package/esm/components/command-palette/command-palette-input.js.map +1 -1
  53. package/esm/components/command-palette/command-palette-suggestion-list.js +1 -1
  54. package/esm/components/command-palette/command-palette-suggestion-list.js.map +1 -1
  55. package/esm/components/command-palette/command-palette-suggestion-list.spec.js +1 -1
  56. package/esm/components/command-palette/command-palette-suggestion-list.spec.js.map +1 -1
  57. package/esm/components/command-palette/index.d.ts.map +1 -1
  58. package/esm/components/command-palette/index.js +15 -2
  59. package/esm/components/command-palette/index.js.map +1 -1
  60. package/esm/components/command-palette/index.spec.js +78 -33
  61. package/esm/components/command-palette/index.spec.js.map +1 -1
  62. package/esm/components/context-menu/context-menu-item.js +1 -1
  63. package/esm/components/context-menu/context-menu-item.js.map +1 -1
  64. package/esm/components/context-menu/context-menu.js +1 -1
  65. package/esm/components/context-menu/context-menu.js.map +1 -1
  66. package/esm/components/data-grid/body.js +1 -1
  67. package/esm/components/data-grid/body.js.map +1 -1
  68. package/esm/components/data-grid/data-grid-row.d.ts.map +1 -1
  69. package/esm/components/data-grid/data-grid-row.js +19 -3
  70. package/esm/components/data-grid/data-grid-row.js.map +1 -1
  71. package/esm/components/data-grid/data-grid.d.ts +12 -2
  72. package/esm/components/data-grid/data-grid.d.ts.map +1 -1
  73. package/esm/components/data-grid/data-grid.js +33 -13
  74. package/esm/components/data-grid/data-grid.js.map +1 -1
  75. package/esm/components/data-grid/data-grid.spec.js +170 -90
  76. package/esm/components/data-grid/data-grid.spec.js.map +1 -1
  77. package/esm/components/data-grid/filters/boolean-filter.d.ts +2 -2
  78. package/esm/components/data-grid/filters/boolean-filter.d.ts.map +1 -1
  79. package/esm/components/data-grid/filters/boolean-filter.js +4 -4
  80. package/esm/components/data-grid/filters/boolean-filter.js.map +1 -1
  81. package/esm/components/data-grid/filters/boolean-filter.spec.js +18 -17
  82. package/esm/components/data-grid/filters/boolean-filter.spec.js.map +1 -1
  83. package/esm/components/data-grid/filters/date-filter.d.ts +2 -2
  84. package/esm/components/data-grid/filters/date-filter.d.ts.map +1 -1
  85. package/esm/components/data-grid/filters/date-filter.js +6 -6
  86. package/esm/components/data-grid/filters/date-filter.js.map +1 -1
  87. package/esm/components/data-grid/filters/date-filter.spec.js +26 -21
  88. package/esm/components/data-grid/filters/date-filter.spec.js.map +1 -1
  89. package/esm/components/data-grid/filters/enum-filter.d.ts +2 -2
  90. package/esm/components/data-grid/filters/enum-filter.d.ts.map +1 -1
  91. package/esm/components/data-grid/filters/enum-filter.js +5 -5
  92. package/esm/components/data-grid/filters/enum-filter.js.map +1 -1
  93. package/esm/components/data-grid/filters/enum-filter.spec.js +21 -19
  94. package/esm/components/data-grid/filters/enum-filter.spec.js.map +1 -1
  95. package/esm/components/data-grid/filters/filter-dropdown.js +1 -1
  96. package/esm/components/data-grid/filters/filter-dropdown.js.map +1 -1
  97. package/esm/components/data-grid/filters/number-filter.d.ts +2 -2
  98. package/esm/components/data-grid/filters/number-filter.d.ts.map +1 -1
  99. package/esm/components/data-grid/filters/number-filter.js +5 -5
  100. package/esm/components/data-grid/filters/number-filter.js.map +1 -1
  101. package/esm/components/data-grid/filters/number-filter.spec.js +23 -21
  102. package/esm/components/data-grid/filters/number-filter.spec.js.map +1 -1
  103. package/esm/components/data-grid/filters/string-filter.d.ts +2 -2
  104. package/esm/components/data-grid/filters/string-filter.d.ts.map +1 -1
  105. package/esm/components/data-grid/filters/string-filter.js +5 -5
  106. package/esm/components/data-grid/filters/string-filter.js.map +1 -1
  107. package/esm/components/data-grid/filters/string-filter.spec.js +21 -19
  108. package/esm/components/data-grid/filters/string-filter.spec.js.map +1 -1
  109. package/esm/components/data-grid/footer.d.ts +2 -2
  110. package/esm/components/data-grid/footer.d.ts.map +1 -1
  111. package/esm/components/data-grid/footer.js +8 -13
  112. package/esm/components/data-grid/footer.js.map +1 -1
  113. package/esm/components/data-grid/footer.spec.js +38 -27
  114. package/esm/components/data-grid/footer.spec.js.map +1 -1
  115. package/esm/components/data-grid/header.d.ts +6 -6
  116. package/esm/components/data-grid/header.d.ts.map +1 -1
  117. package/esm/components/data-grid/header.js +16 -17
  118. package/esm/components/data-grid/header.js.map +1 -1
  119. package/esm/components/data-grid/header.spec.js +66 -60
  120. package/esm/components/data-grid/header.spec.js.map +1 -1
  121. package/esm/components/data-grid/selection-cell.d.ts.map +1 -1
  122. package/esm/components/data-grid/selection-cell.js +2 -2
  123. package/esm/components/data-grid/selection-cell.js.map +1 -1
  124. package/esm/components/dialog.d.ts +11 -0
  125. package/esm/components/dialog.d.ts.map +1 -1
  126. package/esm/components/dialog.js +3 -3
  127. package/esm/components/dialog.js.map +1 -1
  128. package/esm/components/dialog.spec.js +54 -2
  129. package/esm/components/dialog.spec.js.map +1 -1
  130. package/esm/components/divider.js +1 -1
  131. package/esm/components/divider.js.map +1 -1
  132. package/esm/components/drawer/drawer-toggle-button.js +1 -1
  133. package/esm/components/drawer/drawer-toggle-button.js.map +1 -1
  134. package/esm/components/drawer/index.js +1 -1
  135. package/esm/components/drawer/index.js.map +1 -1
  136. package/esm/components/dropdown.d.ts.map +1 -1
  137. package/esm/components/dropdown.js +2 -2
  138. package/esm/components/dropdown.js.map +1 -1
  139. package/esm/components/dropdown.spec.js +8 -0
  140. package/esm/components/dropdown.spec.js.map +1 -1
  141. package/esm/components/fab.js +1 -1
  142. package/esm/components/fab.js.map +1 -1
  143. package/esm/components/form.js +1 -1
  144. package/esm/components/form.js.map +1 -1
  145. package/esm/components/grid.js +1 -1
  146. package/esm/components/grid.js.map +1 -1
  147. package/esm/components/icons/icon.js +1 -1
  148. package/esm/components/icons/icon.js.map +1 -1
  149. package/esm/components/image.d.ts.map +1 -1
  150. package/esm/components/image.js +17 -8
  151. package/esm/components/image.js.map +1 -1
  152. package/esm/components/image.spec.js +60 -0
  153. package/esm/components/image.spec.js.map +1 -1
  154. package/esm/components/inputs/autocomplete.js +1 -1
  155. package/esm/components/inputs/autocomplete.js.map +1 -1
  156. package/esm/components/inputs/checkbox.d.ts.map +1 -1
  157. package/esm/components/inputs/checkbox.js +2 -1
  158. package/esm/components/inputs/checkbox.js.map +1 -1
  159. package/esm/components/inputs/checkbox.spec.js +1 -1
  160. package/esm/components/inputs/checkbox.spec.js.map +1 -1
  161. package/esm/components/inputs/input-number.js +1 -1
  162. package/esm/components/inputs/input-number.js.map +1 -1
  163. package/esm/components/inputs/input-number.spec.js +1 -1
  164. package/esm/components/inputs/input-number.spec.js.map +1 -1
  165. package/esm/components/inputs/input.js +1 -1
  166. package/esm/components/inputs/input.js.map +1 -1
  167. package/esm/components/inputs/input.spec.js +1 -1
  168. package/esm/components/inputs/input.spec.js.map +1 -1
  169. package/esm/components/inputs/radio-group.js +1 -1
  170. package/esm/components/inputs/radio-group.js.map +1 -1
  171. package/esm/components/inputs/radio-group.spec.js +1 -1
  172. package/esm/components/inputs/radio-group.spec.js.map +1 -1
  173. package/esm/components/inputs/radio.d.ts.map +1 -1
  174. package/esm/components/inputs/radio.js +2 -1
  175. package/esm/components/inputs/radio.js.map +1 -1
  176. package/esm/components/inputs/radio.spec.js +1 -1
  177. package/esm/components/inputs/radio.spec.js.map +1 -1
  178. package/esm/components/inputs/select.js +1 -1
  179. package/esm/components/inputs/select.js.map +1 -1
  180. package/esm/components/inputs/slider.d.ts.map +1 -1
  181. package/esm/components/inputs/slider.js +2 -1
  182. package/esm/components/inputs/slider.js.map +1 -1
  183. package/esm/components/inputs/switch.d.ts.map +1 -1
  184. package/esm/components/inputs/switch.js +2 -1
  185. package/esm/components/inputs/switch.js.map +1 -1
  186. package/esm/components/inputs/switch.spec.js +1 -1
  187. package/esm/components/inputs/switch.spec.js.map +1 -1
  188. package/esm/components/inputs/text-area.js +1 -1
  189. package/esm/components/inputs/text-area.js.map +1 -1
  190. package/esm/components/inputs/text-area.spec.js +1 -1
  191. package/esm/components/inputs/text-area.spec.js.map +1 -1
  192. package/esm/components/linear-progress.d.ts +2 -4
  193. package/esm/components/linear-progress.d.ts.map +1 -1
  194. package/esm/components/linear-progress.js +3 -6
  195. package/esm/components/linear-progress.js.map +1 -1
  196. package/esm/components/linear-progress.spec.js +21 -18
  197. package/esm/components/linear-progress.spec.js.map +1 -1
  198. package/esm/components/list/list-item.d.ts.map +1 -1
  199. package/esm/components/list/list-item.js +22 -6
  200. package/esm/components/list/list-item.js.map +1 -1
  201. package/esm/components/list/list.d.ts +7 -0
  202. package/esm/components/list/list.d.ts.map +1 -1
  203. package/esm/components/list/list.js +29 -9
  204. package/esm/components/list/list.js.map +1 -1
  205. package/esm/components/list/list.spec.js +117 -23
  206. package/esm/components/list/list.spec.js.map +1 -1
  207. package/esm/components/loader.js +1 -1
  208. package/esm/components/loader.js.map +1 -1
  209. package/esm/components/loader.spec.js +1 -1
  210. package/esm/components/loader.spec.js.map +1 -1
  211. package/esm/components/markdown/markdown-display.d.ts.map +1 -1
  212. package/esm/components/markdown/markdown-display.js +12 -2
  213. package/esm/components/markdown/markdown-display.js.map +1 -1
  214. package/esm/components/markdown/markdown-display.spec.js +98 -1
  215. package/esm/components/markdown/markdown-display.spec.js.map +1 -1
  216. package/esm/components/markdown/markdown-editor.js +1 -1
  217. package/esm/components/markdown/markdown-editor.js.map +1 -1
  218. package/esm/components/markdown/markdown-editor.spec.js +88 -1
  219. package/esm/components/markdown/markdown-editor.spec.js.map +1 -1
  220. package/esm/components/markdown/markdown-input.js +1 -1
  221. package/esm/components/markdown/markdown-input.js.map +1 -1
  222. package/esm/components/markdown/markdown-input.spec.js +1 -1
  223. package/esm/components/markdown/markdown-input.spec.js.map +1 -1
  224. package/esm/components/menu/menu.js +2 -2
  225. package/esm/components/menu/menu.js.map +1 -1
  226. package/esm/components/modal.d.ts +10 -0
  227. package/esm/components/modal.d.ts.map +1 -1
  228. package/esm/components/modal.js +25 -5
  229. package/esm/components/modal.js.map +1 -1
  230. package/esm/components/modal.spec.js +89 -4
  231. package/esm/components/modal.spec.js.map +1 -1
  232. package/esm/components/noty-list.js +2 -2
  233. package/esm/components/noty-list.js.map +1 -1
  234. package/esm/components/page-container/index.js +1 -1
  235. package/esm/components/page-container/index.js.map +1 -1
  236. package/esm/components/page-container/page-header.js +1 -1
  237. package/esm/components/page-container/page-header.js.map +1 -1
  238. package/esm/components/page-layout/index.js +2 -2
  239. package/esm/components/page-layout/index.js.map +1 -1
  240. package/esm/components/page-layout/index.spec.js +14 -0
  241. package/esm/components/page-layout/index.spec.js.map +1 -1
  242. package/esm/components/pagination.js +1 -1
  243. package/esm/components/pagination.js.map +1 -1
  244. package/esm/components/paper.js +1 -1
  245. package/esm/components/paper.js.map +1 -1
  246. package/esm/components/rating.d.ts.map +1 -1
  247. package/esm/components/rating.js +29 -22
  248. package/esm/components/rating.js.map +1 -1
  249. package/esm/components/rating.spec.js +152 -5
  250. package/esm/components/rating.spec.js.map +1 -1
  251. package/esm/components/result.js +1 -1
  252. package/esm/components/result.js.map +1 -1
  253. package/esm/components/skeleton.js +1 -1
  254. package/esm/components/skeleton.js.map +1 -1
  255. package/esm/components/suggest/index.d.ts.map +1 -1
  256. package/esm/components/suggest/index.js +15 -2
  257. package/esm/components/suggest/index.js.map +1 -1
  258. package/esm/components/suggest/index.spec.js +99 -44
  259. package/esm/components/suggest/index.spec.js.map +1 -1
  260. package/esm/components/suggest/suggest-input.js +1 -1
  261. package/esm/components/suggest/suggest-input.js.map +1 -1
  262. package/esm/components/suggest/suggest-input.spec.js +1 -1
  263. package/esm/components/suggest/suggest-input.spec.js.map +1 -1
  264. package/esm/components/suggest/suggestion-list.js +1 -1
  265. package/esm/components/suggest/suggestion-list.js.map +1 -1
  266. package/esm/components/suggest/suggestion-list.spec.js +1 -1
  267. package/esm/components/suggest/suggestion-list.spec.js.map +1 -1
  268. package/esm/components/tabs.d.ts.map +1 -1
  269. package/esm/components/tabs.js +6 -2
  270. package/esm/components/tabs.js.map +1 -1
  271. package/esm/components/timeline.js +2 -2
  272. package/esm/components/timeline.js.map +1 -1
  273. package/esm/components/tooltip.js +1 -1
  274. package/esm/components/tooltip.js.map +1 -1
  275. package/esm/components/tree/tree-item.d.ts.map +1 -1
  276. package/esm/components/tree/tree-item.js +19 -6
  277. package/esm/components/tree/tree-item.js.map +1 -1
  278. package/esm/components/tree/tree.d.ts +7 -0
  279. package/esm/components/tree/tree.d.ts.map +1 -1
  280. package/esm/components/tree/tree.js +13 -4
  281. package/esm/components/tree/tree.js.map +1 -1
  282. package/esm/components/tree/tree.spec.js +64 -2
  283. package/esm/components/tree/tree.spec.js.map +1 -1
  284. package/esm/components/typography.js +1 -1
  285. package/esm/components/typography.js.map +1 -1
  286. package/esm/components/wizard/index.js +1 -1
  287. package/esm/components/wizard/index.js.map +1 -1
  288. package/esm/components/wizard/index.spec.js +3 -3
  289. package/esm/components/wizard/index.spec.js.map +1 -1
  290. package/esm/services/collection-service.d.ts +9 -0
  291. package/esm/services/collection-service.d.ts.map +1 -1
  292. package/esm/services/collection-service.js +33 -11
  293. package/esm/services/collection-service.js.map +1 -1
  294. package/esm/services/collection-service.spec.js +33 -24
  295. package/esm/services/collection-service.spec.js.map +1 -1
  296. package/esm/services/css-variable-theme.d.ts +7 -0
  297. package/esm/services/css-variable-theme.d.ts.map +1 -1
  298. package/esm/services/css-variable-theme.js +23 -0
  299. package/esm/services/css-variable-theme.js.map +1 -1
  300. package/esm/services/css-variable-theme.spec.js +1 -0
  301. package/esm/services/css-variable-theme.spec.js.map +1 -1
  302. package/esm/services/list-service.d.ts +9 -0
  303. package/esm/services/list-service.d.ts.map +1 -1
  304. package/esm/services/list-service.js +13 -13
  305. package/esm/services/list-service.js.map +1 -1
  306. package/esm/services/list-service.spec.js +13 -33
  307. package/esm/services/list-service.spec.js.map +1 -1
  308. package/esm/services/theme-provider-service.d.ts +3 -0
  309. package/esm/services/theme-provider-service.d.ts.map +1 -1
  310. package/esm/services/theme-provider-service.js.map +1 -1
  311. package/esm/services/tree-service.d.ts.map +1 -1
  312. package/esm/services/tree-service.js +5 -9
  313. package/esm/services/tree-service.js.map +1 -1
  314. package/esm/services/tree-service.spec.js +12 -9
  315. package/esm/services/tree-service.spec.js.map +1 -1
  316. package/esm/themes/architect-theme.d.ts +1 -0
  317. package/esm/themes/architect-theme.d.ts.map +1 -1
  318. package/esm/themes/architect-theme.js +1 -0
  319. package/esm/themes/architect-theme.js.map +1 -1
  320. package/esm/themes/auditore-theme.d.ts +1 -0
  321. package/esm/themes/auditore-theme.d.ts.map +1 -1
  322. package/esm/themes/auditore-theme.js +1 -0
  323. package/esm/themes/auditore-theme.js.map +1 -1
  324. package/esm/themes/black-mesa-theme.d.ts +1 -0
  325. package/esm/themes/black-mesa-theme.d.ts.map +1 -1
  326. package/esm/themes/black-mesa-theme.js +1 -0
  327. package/esm/themes/black-mesa-theme.js.map +1 -1
  328. package/esm/themes/chieftain-theme.d.ts +1 -0
  329. package/esm/themes/chieftain-theme.d.ts.map +1 -1
  330. package/esm/themes/chieftain-theme.js +1 -0
  331. package/esm/themes/chieftain-theme.js.map +1 -1
  332. package/esm/themes/default-dark-theme.d.ts +1 -0
  333. package/esm/themes/default-dark-theme.d.ts.map +1 -1
  334. package/esm/themes/default-dark-theme.js +1 -0
  335. package/esm/themes/default-dark-theme.js.map +1 -1
  336. package/esm/themes/default-light-theme.d.ts +1 -0
  337. package/esm/themes/default-light-theme.d.ts.map +1 -1
  338. package/esm/themes/default-light-theme.js +1 -0
  339. package/esm/themes/default-light-theme.js.map +1 -1
  340. package/esm/themes/dragonborn-theme.d.ts +1 -0
  341. package/esm/themes/dragonborn-theme.d.ts.map +1 -1
  342. package/esm/themes/dragonborn-theme.js +1 -0
  343. package/esm/themes/dragonborn-theme.js.map +1 -1
  344. package/esm/themes/hawkins-theme.d.ts +1 -0
  345. package/esm/themes/hawkins-theme.d.ts.map +1 -1
  346. package/esm/themes/hawkins-theme.js +1 -0
  347. package/esm/themes/hawkins-theme.js.map +1 -1
  348. package/esm/themes/jedi-theme.d.ts +1 -0
  349. package/esm/themes/jedi-theme.d.ts.map +1 -1
  350. package/esm/themes/jedi-theme.js +1 -0
  351. package/esm/themes/jedi-theme.js.map +1 -1
  352. package/esm/themes/neon-runner-theme.d.ts +1 -0
  353. package/esm/themes/neon-runner-theme.d.ts.map +1 -1
  354. package/esm/themes/neon-runner-theme.js +1 -0
  355. package/esm/themes/neon-runner-theme.js.map +1 -1
  356. package/esm/themes/paladin-theme.d.ts +1 -0
  357. package/esm/themes/paladin-theme.d.ts.map +1 -1
  358. package/esm/themes/paladin-theme.js +1 -0
  359. package/esm/themes/paladin-theme.js.map +1 -1
  360. package/esm/themes/plumber-theme.d.ts +1 -0
  361. package/esm/themes/plumber-theme.d.ts.map +1 -1
  362. package/esm/themes/plumber-theme.js +1 -0
  363. package/esm/themes/plumber-theme.js.map +1 -1
  364. package/esm/themes/replicant-theme.d.ts +1 -0
  365. package/esm/themes/replicant-theme.d.ts.map +1 -1
  366. package/esm/themes/replicant-theme.js +1 -0
  367. package/esm/themes/replicant-theme.js.map +1 -1
  368. package/esm/themes/sandworm-theme.d.ts +1 -0
  369. package/esm/themes/sandworm-theme.d.ts.map +1 -1
  370. package/esm/themes/sandworm-theme.js +1 -0
  371. package/esm/themes/sandworm-theme.js.map +1 -1
  372. package/esm/themes/shadow-broker-theme.d.ts +1 -0
  373. package/esm/themes/shadow-broker-theme.d.ts.map +1 -1
  374. package/esm/themes/shadow-broker-theme.js +1 -0
  375. package/esm/themes/shadow-broker-theme.js.map +1 -1
  376. package/esm/themes/sith-theme.d.ts +1 -0
  377. package/esm/themes/sith-theme.d.ts.map +1 -1
  378. package/esm/themes/sith-theme.js +1 -0
  379. package/esm/themes/sith-theme.js.map +1 -1
  380. package/esm/themes/vault-dweller-theme.d.ts +1 -0
  381. package/esm/themes/vault-dweller-theme.d.ts.map +1 -1
  382. package/esm/themes/vault-dweller-theme.js +1 -0
  383. package/esm/themes/vault-dweller-theme.js.map +1 -1
  384. package/esm/themes/wild-hunt-theme.d.ts +1 -0
  385. package/esm/themes/wild-hunt-theme.d.ts.map +1 -1
  386. package/esm/themes/wild-hunt-theme.js +1 -0
  387. package/esm/themes/wild-hunt-theme.js.map +1 -1
  388. package/esm/themes/xenomorph-theme.d.ts +1 -0
  389. package/esm/themes/xenomorph-theme.d.ts.map +1 -1
  390. package/esm/themes/xenomorph-theme.js +1 -0
  391. package/esm/themes/xenomorph-theme.js.map +1 -1
  392. package/package.json +3 -3
  393. package/src/components/accordion/accordion-item.tsx +10 -15
  394. package/src/components/accordion/accordion.spec.tsx +134 -79
  395. package/src/components/accordion/accordion.tsx +14 -2
  396. package/src/components/alert.tsx +1 -1
  397. package/src/components/app-bar-link.tsx +1 -1
  398. package/src/components/app-bar.tsx +1 -1
  399. package/src/components/avatar.tsx +1 -1
  400. package/src/components/badge.tsx +1 -1
  401. package/src/components/breadcrumb.spec.tsx +3 -3
  402. package/src/components/breadcrumb.tsx +1 -1
  403. package/src/components/button-group.tsx +4 -4
  404. package/src/components/button.spec.tsx +1 -1
  405. package/src/components/button.tsx +1 -1
  406. package/src/components/cache-view.spec.tsx +2 -2
  407. package/src/components/cache-view.tsx +3 -3
  408. package/src/components/card.tsx +5 -5
  409. package/src/components/carousel.tsx +2 -2
  410. package/src/components/chip.spec.tsx +64 -0
  411. package/src/components/chip.tsx +5 -2
  412. package/src/components/circular-progress.spec.tsx +20 -14
  413. package/src/components/circular-progress.tsx +5 -11
  414. package/src/components/command-palette/command-palette-input.tsx +1 -1
  415. package/src/components/command-palette/command-palette-suggestion-list.spec.tsx +1 -1
  416. package/src/components/command-palette/command-palette-suggestion-list.tsx +1 -1
  417. package/src/components/command-palette/index.spec.tsx +95 -33
  418. package/src/components/command-palette/index.tsx +16 -4
  419. package/src/components/context-menu/context-menu-item.tsx +1 -1
  420. package/src/components/context-menu/context-menu.tsx +1 -1
  421. package/src/components/data-grid/body.tsx +1 -1
  422. package/src/components/data-grid/data-grid-row.tsx +21 -3
  423. package/src/components/data-grid/data-grid.spec.tsx +246 -92
  424. package/src/components/data-grid/data-grid.tsx +52 -21
  425. package/src/components/data-grid/filters/boolean-filter.spec.tsx +29 -18
  426. package/src/components/data-grid/filters/boolean-filter.tsx +6 -6
  427. package/src/components/data-grid/filters/date-filter.spec.tsx +35 -22
  428. package/src/components/data-grid/filters/date-filter.tsx +8 -8
  429. package/src/components/data-grid/filters/enum-filter.spec.tsx +35 -20
  430. package/src/components/data-grid/filters/enum-filter.tsx +7 -7
  431. package/src/components/data-grid/filters/filter-dropdown.tsx +1 -1
  432. package/src/components/data-grid/filters/number-filter.spec.tsx +32 -22
  433. package/src/components/data-grid/filters/number-filter.tsx +7 -7
  434. package/src/components/data-grid/filters/string-filter.spec.tsx +32 -20
  435. package/src/components/data-grid/filters/string-filter.tsx +7 -7
  436. package/src/components/data-grid/footer.spec.tsx +79 -31
  437. package/src/components/data-grid/footer.tsx +10 -15
  438. package/src/components/data-grid/header.spec.tsx +152 -68
  439. package/src/components/data-grid/header.tsx +64 -27
  440. package/src/components/data-grid/selection-cell.tsx +2 -1
  441. package/src/components/dialog.spec.tsx +77 -2
  442. package/src/components/dialog.tsx +15 -2
  443. package/src/components/divider.tsx +1 -1
  444. package/src/components/drawer/drawer-toggle-button.tsx +1 -1
  445. package/src/components/drawer/index.tsx +1 -1
  446. package/src/components/dropdown.spec.tsx +9 -0
  447. package/src/components/dropdown.tsx +2 -1
  448. package/src/components/fab.tsx +1 -1
  449. package/src/components/form.tsx +1 -1
  450. package/src/components/grid.tsx +1 -1
  451. package/src/components/icons/icon.tsx +1 -1
  452. package/src/components/image.spec.tsx +82 -0
  453. package/src/components/image.tsx +18 -9
  454. package/src/components/inputs/autocomplete.tsx +1 -1
  455. package/src/components/inputs/checkbox.spec.tsx +1 -1
  456. package/src/components/inputs/checkbox.tsx +2 -1
  457. package/src/components/inputs/input-number.spec.tsx +1 -1
  458. package/src/components/inputs/input-number.tsx +1 -1
  459. package/src/components/inputs/input.spec.tsx +1 -1
  460. package/src/components/inputs/input.tsx +1 -1
  461. package/src/components/inputs/radio-group.spec.tsx +1 -1
  462. package/src/components/inputs/radio-group.tsx +1 -1
  463. package/src/components/inputs/radio.spec.tsx +1 -1
  464. package/src/components/inputs/radio.tsx +2 -1
  465. package/src/components/inputs/select.tsx +1 -1
  466. package/src/components/inputs/slider.tsx +2 -1
  467. package/src/components/inputs/switch.spec.tsx +1 -1
  468. package/src/components/inputs/switch.tsx +2 -1
  469. package/src/components/inputs/text-area.spec.tsx +1 -1
  470. package/src/components/inputs/text-area.tsx +1 -1
  471. package/src/components/linear-progress.spec.tsx +22 -18
  472. package/src/components/linear-progress.tsx +5 -11
  473. package/src/components/list/list-item.tsx +23 -5
  474. package/src/components/list/list.spec.tsx +165 -32
  475. package/src/components/list/list.tsx +38 -11
  476. package/src/components/loader.spec.tsx +1 -1
  477. package/src/components/loader.tsx +1 -1
  478. package/src/components/markdown/markdown-display.spec.tsx +133 -1
  479. package/src/components/markdown/markdown-display.tsx +13 -2
  480. package/src/components/markdown/markdown-editor.spec.tsx +124 -1
  481. package/src/components/markdown/markdown-editor.tsx +1 -1
  482. package/src/components/markdown/markdown-input.spec.tsx +1 -1
  483. package/src/components/markdown/markdown-input.tsx +1 -1
  484. package/src/components/menu/menu.tsx +2 -2
  485. package/src/components/modal.spec.tsx +127 -4
  486. package/src/components/modal.tsx +42 -4
  487. package/src/components/noty-list.tsx +2 -2
  488. package/src/components/page-container/index.tsx +1 -1
  489. package/src/components/page-container/page-header.tsx +1 -1
  490. package/src/components/page-layout/index.spec.tsx +20 -0
  491. package/src/components/page-layout/index.tsx +2 -2
  492. package/src/components/pagination.tsx +1 -1
  493. package/src/components/paper.tsx +1 -1
  494. package/src/components/rating.spec.tsx +200 -5
  495. package/src/components/rating.tsx +29 -23
  496. package/src/components/result.tsx +1 -1
  497. package/src/components/skeleton.tsx +1 -1
  498. package/src/components/suggest/index.spec.tsx +148 -44
  499. package/src/components/suggest/index.tsx +16 -3
  500. package/src/components/suggest/suggest-input.spec.tsx +1 -1
  501. package/src/components/suggest/suggest-input.tsx +1 -1
  502. package/src/components/suggest/suggestion-list.spec.tsx +1 -1
  503. package/src/components/suggest/suggestion-list.tsx +1 -1
  504. package/src/components/tabs.tsx +6 -2
  505. package/src/components/timeline.tsx +2 -2
  506. package/src/components/tooltip.tsx +1 -1
  507. package/src/components/tree/tree-item.tsx +20 -5
  508. package/src/components/tree/tree.spec.tsx +101 -2
  509. package/src/components/tree/tree.tsx +22 -4
  510. package/src/components/typography.tsx +1 -1
  511. package/src/components/wizard/index.spec.tsx +3 -3
  512. package/src/components/wizard/index.tsx +1 -1
  513. package/src/services/collection-service.spec.ts +33 -24
  514. package/src/services/collection-service.ts +35 -13
  515. package/src/services/css-variable-theme.spec.ts +1 -0
  516. package/src/services/css-variable-theme.ts +25 -0
  517. package/src/services/list-service.spec.ts +13 -42
  518. package/src/services/list-service.ts +15 -13
  519. package/src/services/theme-provider-service.ts +2 -0
  520. package/src/services/tree-service.spec.ts +12 -9
  521. package/src/services/tree-service.ts +5 -8
  522. package/src/themes/architect-theme.ts +1 -0
  523. package/src/themes/auditore-theme.ts +1 -0
  524. package/src/themes/black-mesa-theme.ts +1 -0
  525. package/src/themes/chieftain-theme.ts +1 -0
  526. package/src/themes/default-dark-theme.ts +1 -0
  527. package/src/themes/default-light-theme.ts +1 -0
  528. package/src/themes/dragonborn-theme.ts +1 -0
  529. package/src/themes/hawkins-theme.ts +1 -0
  530. package/src/themes/jedi-theme.ts +1 -0
  531. package/src/themes/neon-runner-theme.ts +1 -0
  532. package/src/themes/paladin-theme.ts +1 -0
  533. package/src/themes/plumber-theme.ts +1 -0
  534. package/src/themes/replicant-theme.ts +1 -0
  535. package/src/themes/sandworm-theme.ts +1 -0
  536. package/src/themes/shadow-broker-theme.ts +1 -0
  537. package/src/themes/sith-theme.ts +1 -0
  538. package/src/themes/vault-dweller-theme.ts +1 -0
  539. package/src/themes/wild-hunt-theme.ts +1 -0
  540. package/src/themes/xenomorph-theme.ts +1 -0
@@ -1,7 +1,7 @@
1
1
  import type { FindOptions } from '@furystack/core'
2
2
  import { Injector } from '@furystack/inject'
3
3
  import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
4
- import { ObservableValue, usingAsync } from '@furystack/utils'
4
+ import { usingAsync } from '@furystack/utils'
5
5
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
6
6
  import { CollectionService } from '../../services/collection-service.js'
7
7
  import { DataGrid } from './data-grid.js'
@@ -34,25 +34,23 @@ describe('DataGrid', () => {
34
34
  fn: (ctx: {
35
35
  injector: Injector
36
36
  service: CollectionService<TestEntry>
37
- findOptions: ObservableValue<FindOptions<TestEntry, Array<keyof TestEntry>>>
37
+ findOptions: FindOptions<TestEntry, Array<keyof TestEntry>>
38
+ onFindOptionsChange: (options: FindOptions<TestEntry, Array<keyof TestEntry>>) => void
38
39
  }) => Promise<void>,
39
40
  opts?: { createService?: () => CollectionService<TestEntry> },
40
41
  ) => {
41
42
  await usingAsync(new Injector(), async (injector) => {
42
43
  await usingAsync(opts?.createService?.() ?? createTestService(), async (service) => {
43
- await usingAsync(
44
- new ObservableValue<FindOptions<TestEntry, Array<keyof TestEntry>>>({}),
45
- async (findOptions) => {
46
- await fn({ injector, service, findOptions })
47
- },
48
- )
44
+ const findOptions: FindOptions<TestEntry, Array<keyof TestEntry>> = {}
45
+ const onFindOptionsChange = vi.fn<(options: FindOptions<TestEntry, Array<keyof TestEntry>>) => void>()
46
+ await fn({ injector, service, findOptions, onFindOptionsChange })
49
47
  })
50
48
  })
51
49
  }
52
50
 
53
51
  describe('rendering', () => {
54
52
  it('should render with columns', async () => {
55
- await withTestGrid(async ({ injector, service, findOptions }) => {
53
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
56
54
  const rootElement = document.getElementById('root') as HTMLDivElement
57
55
 
58
56
  initializeShadeRoot({
@@ -63,6 +61,7 @@ describe('DataGrid', () => {
63
61
  columns={['id', 'name']}
64
62
  collectionService={service}
65
63
  findOptions={findOptions}
64
+ onFindOptionsChange={onFindOptionsChange}
66
65
  styles={{}}
67
66
  headerComponents={{}}
68
67
  rowComponents={{}}
@@ -81,7 +80,7 @@ describe('DataGrid', () => {
81
80
  })
82
81
 
83
82
  it('should render table structure', async () => {
84
- await withTestGrid(async ({ injector, service, findOptions }) => {
83
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
85
84
  const rootElement = document.getElementById('root') as HTMLDivElement
86
85
 
87
86
  initializeShadeRoot({
@@ -92,6 +91,7 @@ describe('DataGrid', () => {
92
91
  columns={['id', 'name']}
93
92
  collectionService={service}
94
93
  findOptions={findOptions}
94
+ onFindOptionsChange={onFindOptionsChange}
95
95
  styles={{}}
96
96
  headerComponents={{}}
97
97
  rowComponents={{}}
@@ -113,7 +113,7 @@ describe('DataGrid', () => {
113
113
  })
114
114
 
115
115
  it('should render custom header components when provided', async () => {
116
- await withTestGrid(async ({ injector, service, findOptions }) => {
116
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
117
117
  const rootElement = document.getElementById('root') as HTMLDivElement
118
118
 
119
119
  initializeShadeRoot({
@@ -124,6 +124,7 @@ describe('DataGrid', () => {
124
124
  columns={['id', 'name']}
125
125
  collectionService={service}
126
126
  findOptions={findOptions}
127
+ onFindOptionsChange={onFindOptionsChange}
127
128
  styles={{}}
128
129
  headerComponents={{
129
130
  id: () => <span data-testid="custom-header-id">Custom ID Header</span>,
@@ -143,7 +144,7 @@ describe('DataGrid', () => {
143
144
  })
144
145
 
145
146
  it('should render default header components from headerComponents.default', async () => {
146
- await withTestGrid(async ({ injector, service, findOptions }) => {
147
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
147
148
  const rootElement = document.getElementById('root') as HTMLDivElement
148
149
 
149
150
  initializeShadeRoot({
@@ -154,6 +155,7 @@ describe('DataGrid', () => {
154
155
  columns={['id', 'name']}
155
156
  collectionService={service}
156
157
  findOptions={findOptions}
158
+ onFindOptionsChange={onFindOptionsChange}
157
159
  styles={{}}
158
160
  headerComponents={{
159
161
  default: (name) => <span data-testid={`default-header-${name}`}>Default: {name}</span>,
@@ -175,7 +177,7 @@ describe('DataGrid', () => {
175
177
  })
176
178
 
177
179
  it('should render DataGridHeader when no custom header is provided', async () => {
178
- await withTestGrid(async ({ injector, service, findOptions }) => {
180
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
179
181
  const rootElement = document.getElementById('root') as HTMLDivElement
180
182
 
181
183
  initializeShadeRoot({
@@ -186,6 +188,7 @@ describe('DataGrid', () => {
186
188
  columns={['id', 'name']}
187
189
  collectionService={service}
188
190
  findOptions={findOptions}
191
+ onFindOptionsChange={onFindOptionsChange}
189
192
  styles={{}}
190
193
  headerComponents={{}}
191
194
  rowComponents={{}}
@@ -202,7 +205,7 @@ describe('DataGrid', () => {
202
205
  })
203
206
 
204
207
  it('should render filter buttons when columnFilters are provided', async () => {
205
- await withTestGrid(async ({ injector, service, findOptions }) => {
208
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
206
209
  const rootElement = document.getElementById('root') as HTMLDivElement
207
210
 
208
211
  initializeShadeRoot({
@@ -213,6 +216,7 @@ describe('DataGrid', () => {
213
216
  columns={['id', 'name']}
214
217
  collectionService={service}
215
218
  findOptions={findOptions}
219
+ onFindOptionsChange={onFindOptionsChange}
216
220
  styles={{}}
217
221
  columnFilters={{ name: { type: 'string' } }}
218
222
  />
@@ -228,7 +232,7 @@ describe('DataGrid', () => {
228
232
  })
229
233
 
230
234
  it('should not render filter buttons when columnFilters is not provided', async () => {
231
- await withTestGrid(async ({ injector, service, findOptions }) => {
235
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
232
236
  const rootElement = document.getElementById('root') as HTMLDivElement
233
237
 
234
238
  initializeShadeRoot({
@@ -239,6 +243,7 @@ describe('DataGrid', () => {
239
243
  columns={['id', 'name']}
240
244
  collectionService={service}
241
245
  findOptions={findOptions}
246
+ onFindOptionsChange={onFindOptionsChange}
242
247
  styles={{}}
243
248
  />
244
249
  ),
@@ -253,7 +258,7 @@ describe('DataGrid', () => {
253
258
  })
254
259
 
255
260
  it('should render without headerComponents and rowComponents', async () => {
256
- await withTestGrid(async ({ injector, service, findOptions }) => {
261
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
257
262
  const rootElement = document.getElementById('root') as HTMLDivElement
258
263
 
259
264
  initializeShadeRoot({
@@ -264,6 +269,7 @@ describe('DataGrid', () => {
264
269
  columns={['id', 'name']}
265
270
  collectionService={service}
266
271
  findOptions={findOptions}
272
+ onFindOptionsChange={onFindOptionsChange}
267
273
  styles={{}}
268
274
  />
269
275
  ),
@@ -278,15 +284,11 @@ describe('DataGrid', () => {
278
284
  expect(headers?.length).toBe(2)
279
285
  })
280
286
  })
281
- })
282
287
 
283
- describe('focus management', () => {
284
- it('should set focus on click', async () => {
285
- await withTestGrid(async ({ injector, service, findOptions }) => {
288
+ it('should render with auto-generated data-nav-section attribute', async () => {
289
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
286
290
  const rootElement = document.getElementById('root') as HTMLDivElement
287
291
 
288
- expect(service.hasFocus.getValue()).toBe(false)
289
-
290
292
  initializeShadeRoot({
291
293
  injector,
292
294
  rootElement,
@@ -295,69 +297,116 @@ describe('DataGrid', () => {
295
297
  columns={['id', 'name']}
296
298
  collectionService={service}
297
299
  findOptions={findOptions}
298
- styles={{}}
299
- headerComponents={{}}
300
- rowComponents={{}}
300
+ onFindOptionsChange={onFindOptionsChange}
301
301
  />
302
302
  ),
303
303
  })
304
304
 
305
305
  await flushUpdates()
306
306
 
307
- const grid = document.querySelector('shade-data-grid')
308
- const wrapper = grid?.querySelector('.shade-grid-wrapper') as HTMLElement
307
+ const wrapper = document.querySelector('.shade-grid-wrapper')
308
+ const navSection = wrapper?.getAttribute('data-nav-section')
309
+ expect(navSection).toBeTruthy()
310
+ expect(navSection).toMatch(/^data-grid-/)
311
+ })
312
+ })
309
313
 
310
- wrapper?.click()
314
+ it('should render with custom navSection', async () => {
315
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
316
+ const rootElement = document.getElementById('root') as HTMLDivElement
311
317
 
312
- expect(service.hasFocus.getValue()).toBe(true)
318
+ initializeShadeRoot({
319
+ injector,
320
+ rootElement,
321
+ jsxElement: (
322
+ <DataGrid<TestEntry, 'id' | 'name'>
323
+ columns={['id', 'name']}
324
+ collectionService={service}
325
+ findOptions={findOptions}
326
+ onFindOptionsChange={onFindOptionsChange}
327
+ navSection="my-grid"
328
+ />
329
+ ),
330
+ })
331
+
332
+ await flushUpdates()
333
+
334
+ const wrapper = document.querySelector('.shade-grid-wrapper')
335
+ expect(wrapper?.getAttribute('data-nav-section')).toBe('my-grid')
313
336
  })
314
337
  })
338
+ })
315
339
 
316
- it('should lose focus on click outside', async () => {
317
- await withTestGrid(async ({ injector, service, findOptions }) => {
340
+ describe('focus management', () => {
341
+ it('should clear hasFocus on focusout when focus leaves the grid', async () => {
342
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
318
343
  const rootElement = document.getElementById('root') as HTMLDivElement
344
+ const outsideBtn = document.createElement('button')
345
+ document.body.appendChild(outsideBtn)
319
346
 
320
347
  initializeShadeRoot({
321
348
  injector,
322
349
  rootElement,
323
350
  jsxElement: (
324
- <>
325
- <div data-testid="outside">Outside</div>
326
- <DataGrid<TestEntry, 'id' | 'name'>
327
- columns={['id', 'name']}
328
- collectionService={service}
329
- findOptions={findOptions}
330
- styles={{}}
331
- headerComponents={{}}
332
- rowComponents={{}}
333
- />
334
- </>
351
+ <DataGrid<TestEntry, 'id' | 'name'>
352
+ columns={['id', 'name']}
353
+ collectionService={service}
354
+ findOptions={findOptions}
355
+ onFindOptionsChange={onFindOptionsChange}
356
+ />
335
357
  ),
336
358
  })
337
359
 
338
360
  await flushUpdates()
361
+ await new Promise((r) => setTimeout(r, 0))
339
362
 
340
- const grid = document.querySelector('shade-data-grid')
341
- const wrapper = grid?.querySelector('.shade-grid-wrapper') as HTMLElement
342
- wrapper?.click()
343
-
344
- expect(service.hasFocus.getValue()).toBe(true)
363
+ service.hasFocus.setValue(true)
345
364
 
346
- const outside = document.querySelector('[data-testid="outside"]') as HTMLElement
347
- outside?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
365
+ const wrapper = document.querySelector('.shade-grid-wrapper') as HTMLElement
366
+ wrapper?.dispatchEvent(new FocusEvent('focusout', { bubbles: true, relatedTarget: outsideBtn }))
348
367
 
349
368
  expect(service.hasFocus.getValue()).toBe(false)
369
+ outsideBtn.remove()
350
370
  })
351
371
  })
352
- })
353
372
 
354
- describe('keyboard navigation', () => {
355
- it('should handle ArrowDown to move focus to next entry', async () => {
356
- await withTestGrid(async ({ injector, service, findOptions }) => {
373
+ it('should clear hasFocus on focusout when focus moves outside', async () => {
374
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
357
375
  const rootElement = document.getElementById('root') as HTMLDivElement
376
+ const outsideEl = document.createElement('button')
377
+ outsideEl.textContent = 'Outside'
378
+ document.body.appendChild(outsideEl)
379
+
380
+ initializeShadeRoot({
381
+ injector,
382
+ rootElement,
383
+ jsxElement: (
384
+ <DataGrid<TestEntry, 'id' | 'name'>
385
+ columns={['id', 'name']}
386
+ collectionService={service}
387
+ findOptions={findOptions}
388
+ onFindOptionsChange={onFindOptionsChange}
389
+ />
390
+ ),
391
+ })
392
+
393
+ await flushUpdates()
394
+ await new Promise((r) => setTimeout(r, 0))
358
395
 
359
396
  service.hasFocus.setValue(true)
360
- service.focusedEntry.setValue(service.data.getValue().entries[0])
397
+
398
+ const wrapper = document.querySelector('.shade-grid-wrapper') as HTMLElement
399
+ wrapper?.dispatchEvent(new FocusEvent('focusout', { bubbles: true, relatedTarget: outsideEl }))
400
+
401
+ expect(service.hasFocus.getValue()).toBe(false)
402
+
403
+ outsideEl.remove()
404
+ })
405
+ })
406
+
407
+ it('should clear hasFocus on focusout when relatedTarget is null', async () => {
408
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
409
+ const rootElement = document.getElementById('root') as HTMLDivElement
361
410
 
362
411
  initializeShadeRoot({
363
412
  injector,
@@ -367,28 +416,31 @@ describe('DataGrid', () => {
367
416
  columns={['id', 'name']}
368
417
  collectionService={service}
369
418
  findOptions={findOptions}
370
- styles={{}}
371
- headerComponents={{}}
372
- rowComponents={{}}
419
+ onFindOptionsChange={onFindOptionsChange}
373
420
  />
374
421
  ),
375
422
  })
376
423
 
377
424
  await flushUpdates()
425
+ await new Promise((r) => setTimeout(r, 0))
378
426
 
379
- const keydownEvent = new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })
380
- window.dispatchEvent(keydownEvent)
427
+ service.hasFocus.setValue(true)
381
428
 
382
- expect(service.focusedEntry.getValue()).toEqual({ id: 2, name: 'Second' })
429
+ const wrapper = document.querySelector('.shade-grid-wrapper') as HTMLElement
430
+ wrapper?.dispatchEvent(new FocusEvent('focusout', { bubbles: true, relatedTarget: null }))
431
+
432
+ expect(service.hasFocus.getValue()).toBe(false)
383
433
  })
384
434
  })
435
+ })
385
436
 
386
- it('should handle ArrowUp to move focus to previous entry', async () => {
387
- await withTestGrid(async ({ injector, service, findOptions }) => {
437
+ describe('keyboard navigation', () => {
438
+ it('should move focus to next entry on ArrowDown', async () => {
439
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
388
440
  const rootElement = document.getElementById('root') as HTMLDivElement
389
441
 
390
442
  service.hasFocus.setValue(true)
391
- service.focusedEntry.setValue(service.data.getValue().entries[1])
443
+ service.focusedEntry.setValue(service.data.getValue().entries[0])
392
444
 
393
445
  initializeShadeRoot({
394
446
  injector,
@@ -398,6 +450,7 @@ describe('DataGrid', () => {
398
450
  columns={['id', 'name']}
399
451
  collectionService={service}
400
452
  findOptions={findOptions}
453
+ onFindOptionsChange={onFindOptionsChange}
401
454
  styles={{}}
402
455
  headerComponents={{}}
403
456
  rowComponents={{}}
@@ -407,19 +460,19 @@ describe('DataGrid', () => {
407
460
 
408
461
  await flushUpdates()
409
462
 
410
- const keydownEvent = new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true })
463
+ const keydownEvent = new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })
411
464
  window.dispatchEvent(keydownEvent)
412
465
 
413
- expect(service.focusedEntry.getValue()).toEqual({ id: 1, name: 'First' })
466
+ expect(service.focusedEntry.getValue()).toEqual({ id: 2, name: 'Second' })
414
467
  })
415
468
  })
416
469
 
417
- it('should handle Home to move focus to first entry', async () => {
418
- await withTestGrid(async ({ injector, service, findOptions }) => {
470
+ it('should move focus to previous entry on ArrowUp', async () => {
471
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
419
472
  const rootElement = document.getElementById('root') as HTMLDivElement
420
473
 
421
474
  service.hasFocus.setValue(true)
422
- service.focusedEntry.setValue(service.data.getValue().entries[2])
475
+ service.focusedEntry.setValue(service.data.getValue().entries[1])
423
476
 
424
477
  initializeShadeRoot({
425
478
  injector,
@@ -429,6 +482,7 @@ describe('DataGrid', () => {
429
482
  columns={['id', 'name']}
430
483
  collectionService={service}
431
484
  findOptions={findOptions}
485
+ onFindOptionsChange={onFindOptionsChange}
432
486
  styles={{}}
433
487
  headerComponents={{}}
434
488
  rowComponents={{}}
@@ -438,19 +492,19 @@ describe('DataGrid', () => {
438
492
 
439
493
  await flushUpdates()
440
494
 
441
- const keydownEvent = new KeyboardEvent('keydown', { key: 'Home', bubbles: true })
495
+ const keydownEvent = new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true })
442
496
  window.dispatchEvent(keydownEvent)
443
497
 
444
498
  expect(service.focusedEntry.getValue()).toEqual({ id: 1, name: 'First' })
445
499
  })
446
500
  })
447
501
 
448
- it('should handle End to move focus to last entry', async () => {
449
- await withTestGrid(async ({ injector, service, findOptions }) => {
502
+ it('should handle Home to move focus to first entry', async () => {
503
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
450
504
  const rootElement = document.getElementById('root') as HTMLDivElement
451
505
 
452
506
  service.hasFocus.setValue(true)
453
- service.focusedEntry.setValue(service.data.getValue().entries[0])
507
+ service.focusedEntry.setValue(service.data.getValue().entries[2])
454
508
 
455
509
  initializeShadeRoot({
456
510
  injector,
@@ -460,6 +514,7 @@ describe('DataGrid', () => {
460
514
  columns={['id', 'name']}
461
515
  collectionService={service}
462
516
  findOptions={findOptions}
517
+ onFindOptionsChange={onFindOptionsChange}
463
518
  styles={{}}
464
519
  headerComponents={{}}
465
520
  rowComponents={{}}
@@ -469,18 +524,19 @@ describe('DataGrid', () => {
469
524
 
470
525
  await flushUpdates()
471
526
 
472
- const keydownEvent = new KeyboardEvent('keydown', { key: 'End', bubbles: true })
527
+ const keydownEvent = new KeyboardEvent('keydown', { key: 'Home', bubbles: true })
473
528
  window.dispatchEvent(keydownEvent)
474
529
 
475
- expect(service.focusedEntry.getValue()).toEqual({ id: 3, name: 'Third' })
530
+ expect(service.focusedEntry.getValue()).toEqual({ id: 1, name: 'First' })
476
531
  })
477
532
  })
478
533
 
479
- it('should handle Tab to toggle focus', async () => {
480
- await withTestGrid(async ({ injector, service, findOptions }) => {
534
+ it('should handle End to move focus to last entry', async () => {
535
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
481
536
  const rootElement = document.getElementById('root') as HTMLDivElement
482
537
 
483
538
  service.hasFocus.setValue(true)
539
+ service.focusedEntry.setValue(service.data.getValue().entries[0])
484
540
 
485
541
  initializeShadeRoot({
486
542
  injector,
@@ -490,6 +546,7 @@ describe('DataGrid', () => {
490
546
  columns={['id', 'name']}
491
547
  collectionService={service}
492
548
  findOptions={findOptions}
549
+ onFindOptionsChange={onFindOptionsChange}
493
550
  styles={{}}
494
551
  headerComponents={{}}
495
552
  rowComponents={{}}
@@ -499,15 +556,15 @@ describe('DataGrid', () => {
499
556
 
500
557
  await flushUpdates()
501
558
 
502
- const keydownEvent = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })
559
+ const keydownEvent = new KeyboardEvent('keydown', { key: 'End', bubbles: true })
503
560
  window.dispatchEvent(keydownEvent)
504
561
 
505
- expect(service.hasFocus.getValue()).toBe(false)
562
+ expect(service.focusedEntry.getValue()).toEqual({ id: 3, name: 'Third' })
506
563
  })
507
564
  })
508
565
 
509
566
  it('should handle Escape to clear selection and search', async () => {
510
- await withTestGrid(async ({ injector, service, findOptions }) => {
567
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
511
568
  const rootElement = document.getElementById('root') as HTMLDivElement
512
569
 
513
570
  const { entries } = service.data.getValue()
@@ -523,6 +580,7 @@ describe('DataGrid', () => {
523
580
  columns={['id', 'name']}
524
581
  collectionService={service}
525
582
  findOptions={findOptions}
583
+ onFindOptionsChange={onFindOptionsChange}
526
584
  styles={{}}
527
585
  headerComponents={{}}
528
586
  rowComponents={{}}
@@ -541,7 +599,7 @@ describe('DataGrid', () => {
541
599
  })
542
600
 
543
601
  it('should handle Space to toggle selection of focused entry', async () => {
544
- await withTestGrid(async ({ injector, service, findOptions }) => {
602
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
545
603
  const rootElement = document.getElementById('root') as HTMLDivElement
546
604
 
547
605
  const { entries } = service.data.getValue()
@@ -556,6 +614,7 @@ describe('DataGrid', () => {
556
614
  columns={['id', 'name']}
557
615
  collectionService={service}
558
616
  findOptions={findOptions}
617
+ onFindOptionsChange={onFindOptionsChange}
559
618
  styles={{}}
560
619
  headerComponents={{}}
561
620
  rowComponents={{}}
@@ -576,7 +635,7 @@ describe('DataGrid', () => {
576
635
  })
577
636
 
578
637
  it('should handle + to select all entries', async () => {
579
- await withTestGrid(async ({ injector, service, findOptions }) => {
638
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
580
639
  const rootElement = document.getElementById('root') as HTMLDivElement
581
640
 
582
641
  service.hasFocus.setValue(true)
@@ -589,6 +648,7 @@ describe('DataGrid', () => {
589
648
  columns={['id', 'name']}
590
649
  collectionService={service}
591
650
  findOptions={findOptions}
651
+ onFindOptionsChange={onFindOptionsChange}
592
652
  styles={{}}
593
653
  headerComponents={{}}
594
654
  rowComponents={{}}
@@ -606,7 +666,7 @@ describe('DataGrid', () => {
606
666
  })
607
667
 
608
668
  it('should handle - to deselect all entries', async () => {
609
- await withTestGrid(async ({ injector, service, findOptions }) => {
669
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
610
670
  const rootElement = document.getElementById('root') as HTMLDivElement
611
671
 
612
672
  const { entries } = service.data.getValue()
@@ -621,6 +681,7 @@ describe('DataGrid', () => {
621
681
  columns={['id', 'name']}
622
682
  collectionService={service}
623
683
  findOptions={findOptions}
684
+ onFindOptionsChange={onFindOptionsChange}
624
685
  styles={{}}
625
686
  headerComponents={{}}
626
687
  rowComponents={{}}
@@ -638,7 +699,7 @@ describe('DataGrid', () => {
638
699
  })
639
700
 
640
701
  it('should handle * to invert selection', async () => {
641
- await withTestGrid(async ({ injector, service, findOptions }) => {
702
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
642
703
  const rootElement = document.getElementById('root') as HTMLDivElement
643
704
 
644
705
  const { entries } = service.data.getValue()
@@ -653,6 +714,7 @@ describe('DataGrid', () => {
653
714
  columns={['id', 'name']}
654
715
  collectionService={service}
655
716
  findOptions={findOptions}
717
+ onFindOptionsChange={onFindOptionsChange}
656
718
  styles={{}}
657
719
  headerComponents={{}}
658
720
  rowComponents={{}}
@@ -673,10 +735,9 @@ describe('DataGrid', () => {
673
735
  })
674
736
 
675
737
  it('should not handle keyboard when not focused', async () => {
676
- await withTestGrid(async ({ injector, service, findOptions }) => {
738
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
677
739
  const rootElement = document.getElementById('root') as HTMLDivElement
678
740
 
679
- service.hasFocus.setValue(false)
680
741
  service.focusedEntry.setValue(service.data.getValue().entries[0])
681
742
 
682
743
  initializeShadeRoot({
@@ -687,6 +748,7 @@ describe('DataGrid', () => {
687
748
  columns={['id', 'name']}
688
749
  collectionService={service}
689
750
  findOptions={findOptions}
751
+ onFindOptionsChange={onFindOptionsChange}
690
752
  styles={{}}
691
753
  headerComponents={{}}
692
754
  rowComponents={{}}
@@ -696,6 +758,8 @@ describe('DataGrid', () => {
696
758
 
697
759
  await flushUpdates()
698
760
 
761
+ service.hasFocus.setValue(false)
762
+
699
763
  const keydownEvent = new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })
700
764
  window.dispatchEvent(keydownEvent)
701
765
 
@@ -704,7 +768,7 @@ describe('DataGrid', () => {
704
768
  })
705
769
 
706
770
  it('should handle Insert to toggle selection and move to next', async () => {
707
- await withTestGrid(async ({ injector, service, findOptions }) => {
771
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
708
772
  const rootElement = document.getElementById('root') as HTMLDivElement
709
773
 
710
774
  const { entries } = service.data.getValue()
@@ -719,6 +783,7 @@ describe('DataGrid', () => {
719
783
  columns={['id', 'name']}
720
784
  collectionService={service}
721
785
  findOptions={findOptions}
786
+ onFindOptionsChange={onFindOptionsChange}
722
787
  styles={{}}
723
788
  headerComponents={{}}
724
789
  rowComponents={{}}
@@ -739,7 +804,7 @@ describe('DataGrid', () => {
739
804
 
740
805
  describe('styles', () => {
741
806
  it('should apply wrapper styles when provided', async () => {
742
- await withTestGrid(async ({ injector, service, findOptions }) => {
807
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
743
808
  const rootElement = document.getElementById('root') as HTMLDivElement
744
809
 
745
810
  initializeShadeRoot({
@@ -750,6 +815,7 @@ describe('DataGrid', () => {
750
815
  columns={['id', 'name']}
751
816
  collectionService={service}
752
817
  findOptions={findOptions}
818
+ onFindOptionsChange={onFindOptionsChange}
753
819
  styles={{
754
820
  wrapper: { backgroundColor: 'red' },
755
821
  }}
@@ -767,7 +833,7 @@ describe('DataGrid', () => {
767
833
  })
768
834
 
769
835
  it('should apply header styles when provided', async () => {
770
- await withTestGrid(async ({ injector, service, findOptions }) => {
836
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
771
837
  const rootElement = document.getElementById('root') as HTMLDivElement
772
838
 
773
839
  initializeShadeRoot({
@@ -778,6 +844,7 @@ describe('DataGrid', () => {
778
844
  columns={['id', 'name']}
779
845
  collectionService={service}
780
846
  findOptions={findOptions}
847
+ onFindOptionsChange={onFindOptionsChange}
781
848
  styles={{
782
849
  header: { color: 'blue' },
783
850
  }}
@@ -799,7 +866,7 @@ describe('DataGrid', () => {
799
866
  describe('empty and loading states', () => {
800
867
  it('should show empty component when no data', async () => {
801
868
  await withTestGrid(
802
- async ({ injector, service, findOptions }) => {
869
+ async ({ injector, service, findOptions, onFindOptionsChange }) => {
803
870
  const rootElement = document.getElementById('root') as HTMLDivElement
804
871
 
805
872
  initializeShadeRoot({
@@ -810,6 +877,7 @@ describe('DataGrid', () => {
810
877
  columns={['id', 'name']}
811
878
  collectionService={service}
812
879
  findOptions={findOptions}
880
+ onFindOptionsChange={onFindOptionsChange}
813
881
  styles={{}}
814
882
  headerComponents={{}}
815
883
  rowComponents={{}}
@@ -834,7 +902,7 @@ describe('DataGrid', () => {
834
902
  it('should pass row click to collectionService', async () => {
835
903
  const onRowClick = vi.fn()
836
904
  await withTestGrid(
837
- async ({ injector, service, findOptions }) => {
905
+ async ({ injector, service, findOptions, onFindOptionsChange }) => {
838
906
  const rootElement = document.getElementById('root') as HTMLDivElement
839
907
 
840
908
  service.data.setValue({
@@ -850,6 +918,7 @@ describe('DataGrid', () => {
850
918
  columns={['id', 'name']}
851
919
  collectionService={service}
852
920
  findOptions={findOptions}
921
+ onFindOptionsChange={onFindOptionsChange}
853
922
  styles={{}}
854
923
  headerComponents={{}}
855
924
  rowComponents={{}}
@@ -872,7 +941,7 @@ describe('DataGrid', () => {
872
941
  it('should pass row double click to collectionService', async () => {
873
942
  const onRowDoubleClick = vi.fn()
874
943
  await withTestGrid(
875
- async ({ injector, service, findOptions }) => {
944
+ async ({ injector, service, findOptions, onFindOptionsChange }) => {
876
945
  const rootElement = document.getElementById('root') as HTMLDivElement
877
946
 
878
947
  service.data.setValue({
@@ -888,6 +957,7 @@ describe('DataGrid', () => {
888
957
  columns={['id', 'name']}
889
958
  collectionService={service}
890
959
  findOptions={findOptions}
960
+ onFindOptionsChange={onFindOptionsChange}
891
961
  styles={{}}
892
962
  headerComponents={{}}
893
963
  rowComponents={{}}
@@ -909,9 +979,92 @@ describe('DataGrid', () => {
909
979
  })
910
980
  })
911
981
 
982
+ describe('row spatial navigation attributes', () => {
983
+ it('should set data-spatial-nav-target on rows', async () => {
984
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
985
+ const rootElement = document.getElementById('root') as HTMLDivElement
986
+
987
+ initializeShadeRoot({
988
+ injector,
989
+ rootElement,
990
+ jsxElement: (
991
+ <DataGrid<TestEntry, 'id' | 'name'>
992
+ columns={['id', 'name']}
993
+ collectionService={service}
994
+ findOptions={findOptions}
995
+ onFindOptionsChange={onFindOptionsChange}
996
+ />
997
+ ),
998
+ })
999
+
1000
+ await flushUpdates()
1001
+
1002
+ const rows = document.querySelectorAll('shades-data-grid-row')
1003
+ for (const row of rows) {
1004
+ expect(row.hasAttribute('data-spatial-nav-target')).toBe(true)
1005
+ }
1006
+ })
1007
+ })
1008
+
1009
+ it('should set tabIndex 0 on focused row and -1 on others', async () => {
1010
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
1011
+ const rootElement = document.getElementById('root') as HTMLDivElement
1012
+
1013
+ service.focusedEntry.setValue(service.data.getValue().entries[1])
1014
+
1015
+ initializeShadeRoot({
1016
+ injector,
1017
+ rootElement,
1018
+ jsxElement: (
1019
+ <DataGrid<TestEntry, 'id' | 'name'>
1020
+ columns={['id', 'name']}
1021
+ collectionService={service}
1022
+ findOptions={findOptions}
1023
+ onFindOptionsChange={onFindOptionsChange}
1024
+ />
1025
+ ),
1026
+ })
1027
+
1028
+ await flushUpdates()
1029
+
1030
+ const rows = document.querySelectorAll<HTMLTableRowElement>('shades-data-grid-row')
1031
+ expect(rows[0]?.tabIndex).toBe(-1)
1032
+ expect(rows[1]?.tabIndex).toBe(0)
1033
+ expect(rows[2]?.tabIndex).toBe(-1)
1034
+ })
1035
+ })
1036
+
1037
+ it('should sync focusedEntry on row onfocus', async () => {
1038
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
1039
+ const rootElement = document.getElementById('root') as HTMLDivElement
1040
+
1041
+ initializeShadeRoot({
1042
+ injector,
1043
+ rootElement,
1044
+ jsxElement: (
1045
+ <DataGrid<TestEntry, 'id' | 'name'>
1046
+ columns={['id', 'name']}
1047
+ collectionService={service}
1048
+ findOptions={findOptions}
1049
+ onFindOptionsChange={onFindOptionsChange}
1050
+ />
1051
+ ),
1052
+ })
1053
+
1054
+ await flushUpdates()
1055
+
1056
+ const rows = document.querySelectorAll('shades-data-grid-row')
1057
+ rows[2]?.dispatchEvent(new FocusEvent('focus'))
1058
+
1059
+ expect(service.focusedEntry.getValue()).toEqual({ id: 3, name: 'Third' })
1060
+ expect(service.hasFocus.getValue()).toBe(true)
1061
+ })
1062
+ })
1063
+ })
1064
+
912
1065
  describe('keyboard listener cleanup', () => {
913
1066
  it('should remove keyboard listener when component is disconnected', async () => {
914
- await withTestGrid(async ({ injector, service, findOptions }) => {
1067
+ await withTestGrid(async ({ injector, service, findOptions, onFindOptionsChange }) => {
915
1068
  const rootElement = document.getElementById('root') as HTMLDivElement
916
1069
 
917
1070
  service.hasFocus.setValue(true)
@@ -925,6 +1078,7 @@ describe('DataGrid', () => {
925
1078
  columns={['id', 'name']}
926
1079
  collectionService={service}
927
1080
  findOptions={findOptions}
1081
+ onFindOptionsChange={onFindOptionsChange}
928
1082
  styles={{}}
929
1083
  headerComponents={{}}
930
1084
  rowComponents={{}}