@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,8 +1,6 @@
1
1
  import type { FindOptions } from '@furystack/core'
2
2
  import type { ChildrenList } from '@furystack/shades'
3
3
  import { createComponent, Shade } from '@furystack/shades'
4
- import type { ObservableValue } from '@furystack/utils'
5
- import { ClickAwayService } from '../../services/click-away-service.js'
6
4
  import type { CollectionService } from '../../services/collection-service.js'
7
5
  import { cssVariableTheme } from '../../services/css-variable-theme.js'
8
6
  import type { GridProps } from '../grid.js'
@@ -10,6 +8,8 @@ import { DataGridBody } from './body.js'
10
8
  import { DataGridFooter } from './footer.js'
11
9
  import { DataGridHeader } from './header.js'
12
10
 
11
+ let nextDataGridId = 0
12
+
13
13
  export type StringFilterConfig = { type: 'string' }
14
14
  export type NumberFilterConfig = { type: 'number' }
15
15
  export type BooleanFilterConfig = { type: 'boolean' }
@@ -62,7 +62,12 @@ export interface DataGridProps<T, Column extends string> {
62
62
  /**
63
63
  * The query settings to use for the data source
64
64
  */
65
- findOptions: ObservableValue<FindOptions<T, Array<keyof T>>>
65
+ findOptions: FindOptions<T, Array<keyof T>>
66
+
67
+ /**
68
+ * Callback invoked when find options change (e.g. pagination, sorting, filtering)
69
+ */
70
+ onFindOptionsChange: (options: FindOptions<T, Array<keyof T>>) => void
66
71
 
67
72
  /**
68
73
  * A list of custom header components to use
@@ -115,13 +120,21 @@ export interface DataGridProps<T, Column extends string> {
115
120
  * @default dataGridItemsPerPage ([10, 20, 25, 50, 100, Infinity])
116
121
  */
117
122
  paginationOptions?: number[]
123
+
124
+ /**
125
+ * Section name for spatial navigation scoping.
126
+ * Sets `data-nav-section` on the grid wrapper so that SpatialNavigationService
127
+ * constrains arrow-key navigation within the grid.
128
+ * Auto-generated per instance when not provided.
129
+ */
130
+ navSection?: string
118
131
  }
119
132
 
120
133
  export const DataGrid: <T, Column extends string>(
121
134
  props: DataGridProps<T, Column>,
122
135
  children: ChildrenList,
123
136
  ) => JSX.Element<any> = Shade({
124
- shadowDomName: 'shade-data-grid',
137
+ customElementName: 'shade-data-grid',
125
138
  css: {
126
139
  display: 'block',
127
140
  fontFamily: cssVariableTheme.typography.fontFamily,
@@ -153,22 +166,43 @@ export const DataGrid: <T, Column extends string>(
153
166
  borderRight: `1px solid ${cssVariableTheme.action.subtleBorder}`,
154
167
  },
155
168
  },
156
- render: ({ props, useDisposable, useRef, useHostProps }) => {
169
+ render: ({ props, useDisposable, useRef, useHostProps, useState }) => {
157
170
  const wrapperRef = useRef<HTMLDivElement>('gridWrapper')
171
+ const [navSectionId] = useState('navSectionId', String(nextDataGridId++))
172
+
173
+ const headerFindOptions = props.findOptions as FilterableFindOptions
174
+ const handleHeaderChange = props.onFindOptionsChange as (options: FilterableFindOptions) => void
158
175
 
159
176
  useDisposable('keydown-handler', () => {
160
177
  const listener = (ev: KeyboardEvent) => props.collectionService.handleKeyDown(ev)
161
- window.addEventListener('keydown', listener)
162
- return { [Symbol.dispose]: () => window.removeEventListener('keydown', listener) }
178
+ window.addEventListener('keydown', listener, true)
179
+ return { [Symbol.dispose]: () => window.removeEventListener('keydown', listener, true) }
163
180
  })
164
181
 
165
- useDisposable(
166
- 'clickAway',
167
- () =>
168
- new ClickAwayService(wrapperRef, () => {
182
+ useDisposable('focus-coordination', () => {
183
+ const handleFocusOut = (ev: FocusEvent) => {
184
+ const wrapper = wrapperRef.current
185
+ if (wrapper && (!ev.relatedTarget || !wrapper.contains(ev.relatedTarget as Node))) {
169
186
  props.collectionService.hasFocus.setValue(false)
170
- }),
171
- )
187
+ }
188
+ }
189
+
190
+ queueMicrotask(() => {
191
+ const wrapper = wrapperRef.current
192
+ if (wrapper) {
193
+ wrapper.addEventListener('focusout', handleFocusOut)
194
+ }
195
+ })
196
+
197
+ return {
198
+ [Symbol.dispose]: () => {
199
+ const wrapper = wrapperRef.current
200
+ if (wrapper) {
201
+ wrapper.removeEventListener('focusout', handleFocusOut)
202
+ }
203
+ },
204
+ }
205
+ })
172
206
 
173
207
  if (props.styles?.wrapper) {
174
208
  useHostProps({ style: props.styles.wrapper as Record<string, string> })
@@ -178,9 +212,7 @@ export const DataGrid: <T, Column extends string>(
178
212
  <div
179
213
  ref={wrapperRef}
180
214
  className="shade-grid-wrapper"
181
- onclick={() => {
182
- props.collectionService.hasFocus.setValue(true)
183
- }}
215
+ data-nav-section={props.navSection ?? `data-grid-${navSectionId}`}
184
216
  ariaMultiSelectable="true"
185
217
  >
186
218
  <table>
@@ -190,12 +222,10 @@ export const DataGrid: <T, Column extends string>(
190
222
  return (
191
223
  <th style={props.styles?.header}>
192
224
  {props.headerComponents?.[column]?.(column) || props.headerComponents?.default?.(column) || (
193
- <DataGridHeader<
194
- ReturnType<typeof props.collectionService.data.getValue>['entries'][number],
195
- typeof column
196
- >
225
+ <DataGridHeader<typeof column>
197
226
  field={column}
198
- findOptions={props.findOptions}
227
+ findOptions={headerFindOptions}
228
+ onFindOptionsChange={handleHeaderChange}
199
229
  filterConfig={props.columnFilters?.[column]}
200
230
  />
201
231
  )}
@@ -222,6 +252,7 @@ export const DataGrid: <T, Column extends string>(
222
252
  <DataGridFooter
223
253
  service={props.collectionService}
224
254
  findOptions={props.findOptions}
255
+ onFindOptionsChange={props.onFindOptionsChange}
225
256
  paginationOptions={props.paginationOptions}
226
257
  />
227
258
  </div>
@@ -1,6 +1,6 @@
1
1
  import { Injector } from '@furystack/inject'
2
2
  import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
3
- import { ObservableValue, usingAsync } from '@furystack/utils'
3
+ import { usingAsync } from '@furystack/utils'
4
4
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
5
5
  import type { FilterableFindOptions } from '../data-grid.js'
6
6
  import { BooleanFilter } from './boolean-filter.js'
@@ -14,24 +14,32 @@ describe('BooleanFilter', () => {
14
14
  document.body.innerHTML = ''
15
15
  })
16
16
 
17
- const createFindOptions = (options: Partial<FilterableFindOptions> = {}): ObservableValue<FilterableFindOptions> => {
18
- return new ObservableValue<FilterableFindOptions>(options)
17
+ const createFindOptions = (options: Partial<FilterableFindOptions> = {}): FilterableFindOptions => {
18
+ return options as FilterableFindOptions
19
19
  }
20
20
 
21
21
  const renderBooleanFilter = async (
22
- findOptions: ObservableValue<FilterableFindOptions>,
22
+ findOptions: FilterableFindOptions,
23
23
  field = 'isActive',
24
24
  onClose = vi.fn(),
25
+ onFindOptionsChange = vi.fn(),
25
26
  ) => {
26
27
  const injector = new Injector()
27
28
  const rootElement = document.getElementById('root')!
28
29
  initializeShadeRoot({
29
30
  injector,
30
31
  rootElement,
31
- jsxElement: <BooleanFilter field={field} findOptions={findOptions} onClose={onClose} />,
32
+ jsxElement: (
33
+ <BooleanFilter
34
+ field={field}
35
+ findOptions={findOptions}
36
+ onFindOptionsChange={onFindOptionsChange}
37
+ onClose={onClose}
38
+ />
39
+ ),
32
40
  })
33
41
  await flushUpdates()
34
- return { injector, onClose }
42
+ return { injector, onClose, onFindOptionsChange }
35
43
  }
36
44
 
37
45
  it('should render three options: True, False, Any', async () => {
@@ -70,7 +78,7 @@ describe('BooleanFilter', () => {
70
78
 
71
79
  it('should set filter to $eq: true when "True" is clicked', async () => {
72
80
  const findOptions = createFindOptions()
73
- const { injector, onClose } = await renderBooleanFilter(findOptions)
81
+ const { injector, onClose, onFindOptionsChange } = await renderBooleanFilter(findOptions)
74
82
  await usingAsync(injector, async () => {
75
83
  const trueButton = document.querySelector(
76
84
  'shade-segmented-control button[data-value="true"]',
@@ -78,14 +86,14 @@ describe('BooleanFilter', () => {
78
86
  trueButton?.click()
79
87
  await flushUpdates()
80
88
 
81
- expect(findOptions.getValue().filter).toEqual({ isActive: { $eq: true } })
89
+ expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ filter: { isActive: { $eq: true } } }))
82
90
  expect(onClose).toHaveBeenCalled()
83
91
  })
84
92
  })
85
93
 
86
94
  it('should set filter to $eq: false when "False" is clicked', async () => {
87
95
  const findOptions = createFindOptions()
88
- const { injector, onClose } = await renderBooleanFilter(findOptions)
96
+ const { injector, onClose, onFindOptionsChange } = await renderBooleanFilter(findOptions)
89
97
  await usingAsync(injector, async () => {
90
98
  const falseButton = document.querySelector(
91
99
  'shade-segmented-control button[data-value="false"]',
@@ -93,42 +101,45 @@ describe('BooleanFilter', () => {
93
101
  falseButton?.click()
94
102
  await flushUpdates()
95
103
 
96
- expect(findOptions.getValue().filter).toEqual({ isActive: { $eq: false } })
104
+ expect(onFindOptionsChange).toHaveBeenCalledWith(
105
+ expect.objectContaining({ filter: { isActive: { $eq: false } } }),
106
+ )
97
107
  expect(onClose).toHaveBeenCalled()
98
108
  })
99
109
  })
100
110
 
101
111
  it('should remove filter when "Any" is clicked', async () => {
102
112
  const findOptions = createFindOptions({ filter: { isActive: { $eq: true } } })
103
- const { injector, onClose } = await renderBooleanFilter(findOptions)
113
+ const { injector, onClose, onFindOptionsChange } = await renderBooleanFilter(findOptions)
104
114
  await usingAsync(injector, async () => {
105
115
  const anyButton = document.querySelector('shade-segmented-control button[data-value="any"]') as HTMLButtonElement
106
116
  anyButton?.click()
107
117
  await flushUpdates()
108
118
 
109
- expect(findOptions.getValue().filter?.isActive).toBeUndefined()
119
+ const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
120
+ expect(updatedOptions.filter?.isActive).toBeUndefined()
110
121
  expect(onClose).toHaveBeenCalled()
111
122
  })
112
123
  })
113
124
 
114
125
  it('should preserve filters on other fields', async () => {
115
126
  const findOptions = createFindOptions({ filter: { isActive: { $eq: true }, name: { $regex: 'test' } } })
116
- const { injector, onClose } = await renderBooleanFilter(findOptions)
127
+ const { injector, onClose, onFindOptionsChange } = await renderBooleanFilter(findOptions)
117
128
  await usingAsync(injector, async () => {
118
129
  const anyButton = document.querySelector('shade-segmented-control button[data-value="any"]') as HTMLButtonElement
119
130
  anyButton?.click()
120
131
  await flushUpdates()
121
132
 
122
- const updatedFilter = findOptions.getValue().filter
123
- expect(updatedFilter?.isActive).toBeUndefined()
124
- expect(updatedFilter?.name).toEqual({ $regex: 'test' })
133
+ const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
134
+ expect(updatedOptions.filter?.isActive).toBeUndefined()
135
+ expect(updatedOptions.filter?.name).toEqual({ $regex: 'test' })
125
136
  expect(onClose).toHaveBeenCalled()
126
137
  })
127
138
  })
128
139
 
129
140
  it('should reset skip to 0 when applying filter', async () => {
130
141
  const findOptions = createFindOptions({ skip: 20 })
131
- const { injector } = await renderBooleanFilter(findOptions)
142
+ const { injector, onFindOptionsChange } = await renderBooleanFilter(findOptions)
132
143
  await usingAsync(injector, async () => {
133
144
  const trueButton = document.querySelector(
134
145
  'shade-segmented-control button[data-value="true"]',
@@ -136,7 +147,7 @@ describe('BooleanFilter', () => {
136
147
  trueButton?.click()
137
148
  await flushUpdates()
138
149
 
139
- expect(findOptions.getValue().skip).toBe(0)
150
+ expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ skip: 0 }))
140
151
  })
141
152
  })
142
153
  })
@@ -1,5 +1,4 @@
1
1
  import { createComponent, Shade } from '@furystack/shades'
2
- import type { ObservableValue } from '@furystack/utils'
3
2
  import { SegmentedControl } from '../../button-group.js'
4
3
  import { cssVariableTheme } from '../../../services/css-variable-theme.js'
5
4
  import type { FilterableFindOptions } from '../data-grid.js'
@@ -8,13 +7,14 @@ type BooleanFilterValue = 'true' | 'false' | 'any'
8
7
 
9
8
  export const BooleanFilter = Shade<{
10
9
  field: string
11
- findOptions: ObservableValue<FilterableFindOptions>
10
+ findOptions: FilterableFindOptions
11
+ onFindOptionsChange: (options: FilterableFindOptions) => void
12
12
  onClose: () => void
13
13
  }>({
14
- shadowDomName: 'data-grid-boolean-filter',
14
+ customElementName: 'data-grid-boolean-filter',
15
15
  css: { fontFamily: cssVariableTheme.typography.fontFamily },
16
- render: ({ props, useObservable }) => {
17
- const [findOptions, setFindOptions] = useObservable('findOptions', props.findOptions)
16
+ render: ({ props }) => {
17
+ const { findOptions } = props
18
18
 
19
19
  const currentFilter = findOptions.filter?.[props.field] as { $eq?: boolean } | undefined
20
20
  const currentValue: BooleanFilterValue =
@@ -27,7 +27,7 @@ export const BooleanFilter = Shade<{
27
27
  } else {
28
28
  filter[props.field] = { $eq: value === 'true' }
29
29
  }
30
- setFindOptions({ ...findOptions, filter, skip: 0 })
30
+ props.onFindOptionsChange({ ...findOptions, filter, skip: 0 })
31
31
  props.onClose()
32
32
  }
33
33
 
@@ -1,6 +1,6 @@
1
1
  import { Injector } from '@furystack/inject'
2
2
  import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
3
- import { ObservableValue, usingAsync } from '@furystack/utils'
3
+ import { usingAsync } from '@furystack/utils'
4
4
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
5
5
  import type { FilterableFindOptions } from '../data-grid.js'
6
6
  import { DateFilter } from './date-filter.js'
@@ -14,24 +14,32 @@ describe('DateFilter', () => {
14
14
  document.body.innerHTML = ''
15
15
  })
16
16
 
17
- const createFindOptions = (options: Partial<FilterableFindOptions> = {}): ObservableValue<FilterableFindOptions> => {
18
- return new ObservableValue<FilterableFindOptions>(options)
17
+ const createFindOptions = (options: Partial<FilterableFindOptions> = {}): FilterableFindOptions => {
18
+ return options as FilterableFindOptions
19
19
  }
20
20
 
21
21
  const renderDateFilter = async (
22
- findOptions: ObservableValue<FilterableFindOptions>,
22
+ findOptions: FilterableFindOptions,
23
23
  field = 'createdAt',
24
24
  onClose = vi.fn(),
25
+ onFindOptionsChange = vi.fn(),
25
26
  ) => {
26
27
  const injector = new Injector()
27
28
  const rootElement = document.getElementById('root')!
28
29
  initializeShadeRoot({
29
30
  injector,
30
31
  rootElement,
31
- jsxElement: <DateFilter field={field} findOptions={findOptions} onClose={onClose} />,
32
+ jsxElement: (
33
+ <DateFilter
34
+ field={field}
35
+ findOptions={findOptions}
36
+ onFindOptionsChange={onFindOptionsChange}
37
+ onClose={onClose}
38
+ />
39
+ ),
32
40
  })
33
41
  await flushUpdates()
34
- return { injector, onClose }
42
+ return { injector, onClose, onFindOptionsChange }
35
43
  }
36
44
 
37
45
  it('should render mode segmented control and date input', async () => {
@@ -47,7 +55,7 @@ describe('DateFilter', () => {
47
55
 
48
56
  it('should apply "before" filter on submit', async () => {
49
57
  const findOptions = createFindOptions()
50
- const { injector, onClose } = await renderDateFilter(findOptions)
58
+ const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions)
51
59
  await usingAsync(injector, async () => {
52
60
  const input = document.querySelector('[data-testid="date-filter-value"]') as HTMLInputElement
53
61
  input.value = '2025-06-15T10:30'
@@ -57,7 +65,8 @@ describe('DateFilter', () => {
57
65
  form.dispatchEvent(new Event('submit', { bubbles: true }))
58
66
  await flushUpdates()
59
67
 
60
- const filter = findOptions.getValue().filter?.createdAt as Record<string, Date>
68
+ const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
69
+ const filter = updatedOptions.filter?.createdAt as Record<string, Date>
61
70
  expect(filter.$lt).toBeInstanceOf(Date)
62
71
  expect(filter.$lt.toISOString()).toBe(new Date('2025-06-15T10:30').toISOString())
63
72
  expect(onClose).toHaveBeenCalled()
@@ -66,7 +75,7 @@ describe('DateFilter', () => {
66
75
 
67
76
  it('should apply "after" filter when mode is changed', async () => {
68
77
  const findOptions = createFindOptions()
69
- const { injector, onClose } = await renderDateFilter(findOptions)
78
+ const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions)
70
79
  await usingAsync(injector, async () => {
71
80
  const afterButton = document.querySelector(
72
81
  'shade-segmented-control button[data-value="after"]',
@@ -82,7 +91,8 @@ describe('DateFilter', () => {
82
91
  form.dispatchEvent(new Event('submit', { bubbles: true }))
83
92
  await flushUpdates()
84
93
 
85
- const filter = findOptions.getValue().filter?.createdAt as Record<string, Date>
94
+ const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
95
+ const filter = updatedOptions.filter?.createdAt as Record<string, Date>
86
96
  expect(filter.$gt).toBeInstanceOf(Date)
87
97
  expect(onClose).toHaveBeenCalled()
88
98
  })
@@ -90,7 +100,7 @@ describe('DateFilter', () => {
90
100
 
91
101
  it('should apply "between" filter with both dates', async () => {
92
102
  const findOptions = createFindOptions()
93
- const { injector, onClose } = await renderDateFilter(findOptions)
103
+ const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions)
94
104
  await usingAsync(injector, async () => {
95
105
  const betweenButton = document.querySelector(
96
106
  'shade-segmented-control button[data-value="between"]',
@@ -110,7 +120,8 @@ describe('DateFilter', () => {
110
120
  form.dispatchEvent(new Event('submit', { bubbles: true }))
111
121
  await flushUpdates()
112
122
 
113
- const filter = findOptions.getValue().filter?.createdAt as Record<string, Date>
123
+ const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
124
+ const filter = updatedOptions.filter?.createdAt as Record<string, Date>
114
125
  expect(filter.$gte).toBeInstanceOf(Date)
115
126
  expect(filter.$lte).toBeInstanceOf(Date)
116
127
  expect(onClose).toHaveBeenCalled()
@@ -119,20 +130,21 @@ describe('DateFilter', () => {
119
130
 
120
131
  it('should clear filter when Clear button is clicked', async () => {
121
132
  const findOptions = createFindOptions({ filter: { createdAt: { $lt: new Date() } } })
122
- const { injector, onClose } = await renderDateFilter(findOptions)
133
+ const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions)
123
134
  await usingAsync(injector, async () => {
124
135
  const clearButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Clear')
125
136
  clearButton?.click()
126
137
  await flushUpdates()
127
138
 
128
- expect(findOptions.getValue().filter?.createdAt).toBeUndefined()
139
+ const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
140
+ expect(updatedOptions.filter?.createdAt).toBeUndefined()
129
141
  expect(onClose).toHaveBeenCalled()
130
142
  })
131
143
  })
132
144
 
133
145
  it('should remove filter when submitting empty date', async () => {
134
146
  const findOptions = createFindOptions({ filter: { createdAt: { $lt: new Date() } } })
135
- const { injector, onClose } = await renderDateFilter(findOptions)
147
+ const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions)
136
148
  await usingAsync(injector, async () => {
137
149
  const input = document.querySelector('[data-testid="date-filter-value"]') as HTMLInputElement
138
150
  input.value = ''
@@ -142,7 +154,8 @@ describe('DateFilter', () => {
142
154
  form.dispatchEvent(new Event('submit', { bubbles: true }))
143
155
  await flushUpdates()
144
156
 
145
- expect(findOptions.getValue().filter?.createdAt).toBeUndefined()
157
+ const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
158
+ expect(updatedOptions.filter?.createdAt).toBeUndefined()
146
159
  expect(onClose).toHaveBeenCalled()
147
160
  })
148
161
  })
@@ -151,21 +164,21 @@ describe('DateFilter', () => {
151
164
  const findOptions = createFindOptions({
152
165
  filter: { createdAt: { $lt: new Date() }, name: { $regex: 'keep' } },
153
166
  })
154
- const { injector } = await renderDateFilter(findOptions)
167
+ const { injector, onFindOptionsChange } = await renderDateFilter(findOptions)
155
168
  await usingAsync(injector, async () => {
156
169
  const clearButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Clear')
157
170
  clearButton?.click()
158
171
  await flushUpdates()
159
172
 
160
- const updatedFilter = findOptions.getValue().filter
161
- expect(updatedFilter?.createdAt).toBeUndefined()
162
- expect(updatedFilter?.name).toEqual({ $regex: 'keep' })
173
+ const updatedOptions = onFindOptionsChange.mock.lastCall?.[0] as FilterableFindOptions
174
+ expect(updatedOptions.filter?.createdAt).toBeUndefined()
175
+ expect(updatedOptions.filter?.name).toEqual({ $regex: 'keep' })
163
176
  })
164
177
  })
165
178
 
166
179
  it('should reset skip to 0 when applying filter', async () => {
167
180
  const findOptions = createFindOptions({ skip: 20 })
168
- const { injector } = await renderDateFilter(findOptions)
181
+ const { injector, onFindOptionsChange } = await renderDateFilter(findOptions)
169
182
  await usingAsync(injector, async () => {
170
183
  const input = document.querySelector('[data-testid="date-filter-value"]') as HTMLInputElement
171
184
  input.value = '2025-06-15T10:30'
@@ -175,7 +188,7 @@ describe('DateFilter', () => {
175
188
  form.dispatchEvent(new Event('submit', { bubbles: true }))
176
189
  await flushUpdates()
177
190
 
178
- expect(findOptions.getValue().skip).toBe(0)
191
+ expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ skip: 0 }))
179
192
  })
180
193
  })
181
194
  })
@@ -1,5 +1,4 @@
1
1
  import { createComponent, Shade } from '@furystack/shades'
2
- import type { ObservableValue } from '@furystack/utils'
3
2
  import { SegmentedControl } from '../../button-group.js'
4
3
  import { Button } from '../../button.js'
5
4
  import { close as closeIcon, search as searchIcon } from '../../icons/icon-definitions.js'
@@ -12,17 +11,18 @@ type DateMode = 'before' | 'after' | 'between'
12
11
 
13
12
  export const DateFilter = Shade<{
14
13
  field: string
15
- findOptions: ObservableValue<FilterableFindOptions>
14
+ findOptions: FilterableFindOptions
15
+ onFindOptionsChange: (options: FilterableFindOptions) => void
16
16
  onClose: () => void
17
17
  }>({
18
- shadowDomName: 'data-grid-date-filter',
18
+ customElementName: 'data-grid-date-filter',
19
19
  css: {
20
20
  ...filterBaseCss,
21
21
  fontFamily: cssVariableTheme.typography.fontFamily,
22
22
  '& input[type="datetime-local"]': filterInputCss,
23
23
  },
24
- render: ({ props, useObservable, useState }) => {
25
- const [findOptions, setFindOptions] = useObservable('findOptions', props.findOptions)
24
+ render: ({ props, useState }) => {
25
+ const { findOptions } = props
26
26
 
27
27
  const currentFilter = findOptions.filter?.[props.field] as
28
28
  | { $lt?: Date; $gt?: Date; $gte?: Date; $lte?: Date }
@@ -63,7 +63,7 @@ export const DateFilter = Shade<{
63
63
  const filter = { ...findOptions.filter }
64
64
  if (!dateValue) {
65
65
  delete filter[props.field]
66
- setFindOptions({ ...findOptions, filter, skip: 0 })
66
+ props.onFindOptionsChange({ ...findOptions, filter, skip: 0 })
67
67
  props.onClose()
68
68
  return
69
69
  }
@@ -87,14 +87,14 @@ export const DateFilter = Shade<{
87
87
  }
88
88
 
89
89
  filter[props.field] = filterValue
90
- setFindOptions({ ...findOptions, filter, skip: 0 })
90
+ props.onFindOptionsChange({ ...findOptions, filter, skip: 0 })
91
91
  props.onClose()
92
92
  }
93
93
 
94
94
  const clearFilter = () => {
95
95
  const filter = { ...findOptions.filter }
96
96
  delete filter[props.field]
97
- setFindOptions({ ...findOptions, filter, skip: 0 })
97
+ props.onFindOptionsChange({ ...findOptions, filter, skip: 0 })
98
98
  props.onClose()
99
99
  }
100
100