@furystack/shades-common-components 10.0.35 → 12.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 (862) hide show
  1. package/CHANGELOG.md +496 -0
  2. package/esm/components/accordion/accordion-item.d.ts +31 -0
  3. package/esm/components/accordion/accordion-item.d.ts.map +1 -0
  4. package/esm/components/accordion/accordion-item.js +147 -0
  5. package/esm/components/accordion/accordion-item.js.map +1 -0
  6. package/esm/components/accordion/accordion.d.ts +27 -0
  7. package/esm/components/accordion/accordion.d.ts.map +1 -0
  8. package/esm/components/accordion/accordion.js +39 -0
  9. package/esm/components/accordion/accordion.js.map +1 -0
  10. package/esm/components/accordion/accordion.spec.d.ts +2 -0
  11. package/esm/components/accordion/accordion.spec.d.ts.map +1 -0
  12. package/esm/components/accordion/accordion.spec.js +284 -0
  13. package/esm/components/accordion/accordion.spec.js.map +1 -0
  14. package/esm/components/accordion/index.d.ts +3 -0
  15. package/esm/components/accordion/index.d.ts.map +1 -0
  16. package/esm/components/accordion/index.js +3 -0
  17. package/esm/components/accordion/index.js.map +1 -0
  18. package/esm/components/alert.d.ts +21 -0
  19. package/esm/components/alert.d.ts.map +1 -0
  20. package/esm/components/alert.js +131 -0
  21. package/esm/components/alert.js.map +1 -0
  22. package/esm/components/alert.spec.d.ts +2 -0
  23. package/esm/components/alert.spec.d.ts.map +1 -0
  24. package/esm/components/alert.spec.js +177 -0
  25. package/esm/components/alert.spec.js.map +1 -0
  26. package/esm/components/animations.spec.d.ts +2 -0
  27. package/esm/components/animations.spec.d.ts.map +1 -0
  28. package/esm/components/animations.spec.js +201 -0
  29. package/esm/components/animations.spec.js.map +1 -0
  30. package/esm/components/app-bar-link.d.ts +22 -2
  31. package/esm/components/app-bar-link.d.ts.map +1 -1
  32. package/esm/components/app-bar-link.js +36 -22
  33. package/esm/components/app-bar-link.js.map +1 -1
  34. package/esm/components/app-bar-link.spec.d.ts +2 -0
  35. package/esm/components/app-bar-link.spec.d.ts.map +1 -0
  36. package/esm/components/app-bar-link.spec.js +255 -0
  37. package/esm/components/app-bar-link.spec.js.map +1 -0
  38. package/esm/components/app-bar.d.ts +2 -0
  39. package/esm/components/app-bar.d.ts.map +1 -1
  40. package/esm/components/app-bar.js +28 -23
  41. package/esm/components/app-bar.js.map +1 -1
  42. package/esm/components/app-bar.spec.d.ts +2 -0
  43. package/esm/components/app-bar.spec.d.ts.map +1 -0
  44. package/esm/components/app-bar.spec.js +132 -0
  45. package/esm/components/app-bar.spec.js.map +1 -0
  46. package/esm/components/avatar.d.ts +2 -0
  47. package/esm/components/avatar.d.ts.map +1 -1
  48. package/esm/components/avatar.js +50 -51
  49. package/esm/components/avatar.js.map +1 -1
  50. package/esm/components/avatar.spec.d.ts +2 -0
  51. package/esm/components/avatar.spec.d.ts.map +1 -0
  52. package/esm/components/avatar.spec.js +114 -0
  53. package/esm/components/avatar.spec.js.map +1 -0
  54. package/esm/components/badge.d.ts +35 -0
  55. package/esm/components/badge.d.ts.map +1 -0
  56. package/esm/components/badge.js +68 -0
  57. package/esm/components/badge.js.map +1 -0
  58. package/esm/components/badge.spec.d.ts +2 -0
  59. package/esm/components/badge.spec.d.ts.map +1 -0
  60. package/esm/components/badge.spec.js +157 -0
  61. package/esm/components/badge.spec.js.map +1 -0
  62. package/esm/components/breadcrumb.d.ts +103 -0
  63. package/esm/components/breadcrumb.d.ts.map +1 -0
  64. package/esm/components/breadcrumb.js +121 -0
  65. package/esm/components/breadcrumb.js.map +1 -0
  66. package/esm/components/breadcrumb.spec.d.ts +2 -0
  67. package/esm/components/breadcrumb.spec.d.ts.map +1 -0
  68. package/esm/components/breadcrumb.spec.js +251 -0
  69. package/esm/components/breadcrumb.spec.js.map +1 -0
  70. package/esm/components/button-group.d.ts +85 -0
  71. package/esm/components/button-group.d.ts.map +1 -0
  72. package/esm/components/button-group.js +290 -0
  73. package/esm/components/button-group.js.map +1 -0
  74. package/esm/components/button-group.spec.d.ts +2 -0
  75. package/esm/components/button-group.spec.d.ts.map +1 -0
  76. package/esm/components/button-group.spec.js +502 -0
  77. package/esm/components/button-group.spec.js.map +1 -0
  78. package/esm/components/button.d.ts +44 -2
  79. package/esm/components/button.d.ts.map +1 -1
  80. package/esm/components/button.js +151 -153
  81. package/esm/components/button.js.map +1 -1
  82. package/esm/components/button.spec.d.ts +2 -0
  83. package/esm/components/button.spec.d.ts.map +1 -0
  84. package/esm/components/button.spec.js +310 -0
  85. package/esm/components/button.spec.js.map +1 -0
  86. package/esm/components/card.d.ts +117 -0
  87. package/esm/components/card.d.ts.map +1 -0
  88. package/esm/components/card.js +181 -0
  89. package/esm/components/card.js.map +1 -0
  90. package/esm/components/card.spec.d.ts +2 -0
  91. package/esm/components/card.spec.d.ts.map +1 -0
  92. package/esm/components/card.spec.js +278 -0
  93. package/esm/components/card.spec.js.map +1 -0
  94. package/esm/components/carousel.d.ts +50 -0
  95. package/esm/components/carousel.d.ts.map +1 -0
  96. package/esm/components/carousel.js +263 -0
  97. package/esm/components/carousel.js.map +1 -0
  98. package/esm/components/carousel.spec.d.ts +2 -0
  99. package/esm/components/carousel.spec.d.ts.map +1 -0
  100. package/esm/components/carousel.spec.js +677 -0
  101. package/esm/components/carousel.spec.js.map +1 -0
  102. package/esm/components/chip.d.ts +23 -0
  103. package/esm/components/chip.d.ts.map +1 -0
  104. package/esm/components/chip.js +139 -0
  105. package/esm/components/chip.js.map +1 -0
  106. package/esm/components/chip.spec.d.ts +2 -0
  107. package/esm/components/chip.spec.d.ts.map +1 -0
  108. package/esm/components/chip.spec.js +142 -0
  109. package/esm/components/chip.spec.js.map +1 -0
  110. package/esm/components/circular-progress.d.ts +37 -0
  111. package/esm/components/circular-progress.d.ts.map +1 -0
  112. package/esm/components/circular-progress.js +84 -0
  113. package/esm/components/circular-progress.js.map +1 -0
  114. package/esm/components/circular-progress.spec.d.ts +2 -0
  115. package/esm/components/circular-progress.spec.d.ts.map +1 -0
  116. package/esm/components/circular-progress.spec.js +228 -0
  117. package/esm/components/circular-progress.spec.js.map +1 -0
  118. package/esm/components/command-palette/command-palette-input.d.ts +3 -0
  119. package/esm/components/command-palette/command-palette-input.d.ts.map +1 -1
  120. package/esm/components/command-palette/command-palette-input.js +33 -23
  121. package/esm/components/command-palette/command-palette-input.js.map +1 -1
  122. package/esm/components/command-palette/command-palette-input.spec.d.ts +2 -0
  123. package/esm/components/command-palette/command-palette-input.spec.d.ts.map +1 -0
  124. package/esm/components/command-palette/command-palette-input.spec.js +244 -0
  125. package/esm/components/command-palette/command-palette-input.spec.js.map +1 -0
  126. package/esm/components/command-palette/command-palette-manager.spec.d.ts +2 -0
  127. package/esm/components/command-palette/command-palette-manager.spec.d.ts.map +1 -0
  128. package/esm/components/command-palette/command-palette-manager.spec.js +378 -0
  129. package/esm/components/command-palette/command-palette-manager.spec.js.map +1 -0
  130. package/esm/components/command-palette/command-palette-suggestion-list.d.ts +2 -0
  131. package/esm/components/command-palette/command-palette-suggestion-list.d.ts.map +1 -1
  132. package/esm/components/command-palette/command-palette-suggestion-list.js +53 -57
  133. package/esm/components/command-palette/command-palette-suggestion-list.js.map +1 -1
  134. package/esm/components/command-palette/command-palette-suggestion-list.spec.d.ts +2 -0
  135. package/esm/components/command-palette/command-palette-suggestion-list.spec.d.ts.map +1 -0
  136. package/esm/components/command-palette/command-palette-suggestion-list.spec.js +394 -0
  137. package/esm/components/command-palette/command-palette-suggestion-list.spec.js.map +1 -0
  138. package/esm/components/command-palette/index.d.ts +2 -0
  139. package/esm/components/command-palette/index.d.ts.map +1 -1
  140. package/esm/components/command-palette/index.js +41 -120
  141. package/esm/components/command-palette/index.js.map +1 -1
  142. package/esm/components/command-palette/index.spec.d.ts +2 -0
  143. package/esm/components/command-palette/index.spec.d.ts.map +1 -0
  144. package/esm/components/command-palette/index.spec.js +509 -0
  145. package/esm/components/command-palette/index.spec.js.map +1 -0
  146. package/esm/components/context-menu/context-menu-item.d.ts +9 -0
  147. package/esm/components/context-menu/context-menu-item.d.ts.map +1 -0
  148. package/esm/components/context-menu/context-menu-item.js +56 -0
  149. package/esm/components/context-menu/context-menu-item.js.map +1 -0
  150. package/esm/components/context-menu/context-menu-manager.d.ts +52 -0
  151. package/esm/components/context-menu/context-menu-manager.d.ts.map +1 -0
  152. package/esm/components/context-menu/context-menu-manager.js +128 -0
  153. package/esm/components/context-menu/context-menu-manager.js.map +1 -0
  154. package/esm/components/context-menu/context-menu-manager.spec.d.ts +2 -0
  155. package/esm/components/context-menu/context-menu-manager.spec.d.ts.map +1 -0
  156. package/esm/components/context-menu/context-menu-manager.spec.js +332 -0
  157. package/esm/components/context-menu/context-menu-manager.spec.js.map +1 -0
  158. package/esm/components/context-menu/context-menu.d.ts +8 -0
  159. package/esm/components/context-menu/context-menu.d.ts.map +1 -0
  160. package/esm/components/context-menu/context-menu.js +79 -0
  161. package/esm/components/context-menu/context-menu.js.map +1 -0
  162. package/esm/components/context-menu/context-menu.spec.d.ts +2 -0
  163. package/esm/components/context-menu/context-menu.spec.d.ts.map +1 -0
  164. package/esm/components/context-menu/context-menu.spec.js +282 -0
  165. package/esm/components/context-menu/context-menu.spec.js.map +1 -0
  166. package/esm/components/context-menu/index.d.ts +4 -0
  167. package/esm/components/context-menu/index.d.ts.map +1 -0
  168. package/esm/components/context-menu/index.js +4 -0
  169. package/esm/components/context-menu/index.js.map +1 -0
  170. package/esm/components/data-grid/body.js +1 -1
  171. package/esm/components/data-grid/body.js.map +1 -1
  172. package/esm/components/data-grid/body.spec.d.ts +2 -0
  173. package/esm/components/data-grid/body.spec.d.ts.map +1 -0
  174. package/esm/components/data-grid/body.spec.js +238 -0
  175. package/esm/components/data-grid/body.spec.js.map +1 -0
  176. package/esm/components/data-grid/data-grid-row.d.ts.map +1 -1
  177. package/esm/components/data-grid/data-grid-row.js +84 -96
  178. package/esm/components/data-grid/data-grid-row.js.map +1 -1
  179. package/esm/components/data-grid/data-grid-row.spec.d.ts +2 -0
  180. package/esm/components/data-grid/data-grid-row.spec.d.ts.map +1 -0
  181. package/esm/components/data-grid/data-grid-row.spec.js +328 -0
  182. package/esm/components/data-grid/data-grid-row.spec.js.map +1 -0
  183. package/esm/components/data-grid/data-grid.d.ts.map +1 -1
  184. package/esm/components/data-grid/data-grid.js +39 -31
  185. package/esm/components/data-grid/data-grid.js.map +1 -1
  186. package/esm/components/data-grid/data-grid.spec.d.ts +2 -0
  187. package/esm/components/data-grid/data-grid.spec.d.ts.map +1 -0
  188. package/esm/components/data-grid/data-grid.spec.js +569 -0
  189. package/esm/components/data-grid/data-grid.spec.js.map +1 -0
  190. package/esm/components/data-grid/footer.js +21 -15
  191. package/esm/components/data-grid/footer.js.map +1 -1
  192. package/esm/components/data-grid/footer.spec.d.ts +2 -0
  193. package/esm/components/data-grid/footer.spec.d.ts.map +1 -0
  194. package/esm/components/data-grid/footer.spec.js +276 -0
  195. package/esm/components/data-grid/footer.spec.js.map +1 -0
  196. package/esm/components/data-grid/header.d.ts +3 -1
  197. package/esm/components/data-grid/header.d.ts.map +1 -1
  198. package/esm/components/data-grid/header.js +94 -60
  199. package/esm/components/data-grid/header.js.map +1 -1
  200. package/esm/components/data-grid/header.spec.d.ts +2 -0
  201. package/esm/components/data-grid/header.spec.d.ts.map +1 -0
  202. package/esm/components/data-grid/header.spec.js +444 -0
  203. package/esm/components/data-grid/header.spec.js.map +1 -0
  204. package/esm/components/data-grid/selection-cell.d.ts +2 -0
  205. package/esm/components/data-grid/selection-cell.d.ts.map +1 -1
  206. package/esm/components/data-grid/selection-cell.js +15 -13
  207. package/esm/components/data-grid/selection-cell.js.map +1 -1
  208. package/esm/components/data-grid/selection-cell.spec.d.ts +2 -0
  209. package/esm/components/data-grid/selection-cell.spec.d.ts.map +1 -0
  210. package/esm/components/data-grid/selection-cell.spec.js +127 -0
  211. package/esm/components/data-grid/selection-cell.spec.js.map +1 -0
  212. package/esm/components/dialog.d.ts +46 -0
  213. package/esm/components/dialog.d.ts.map +1 -0
  214. package/esm/components/dialog.js +178 -0
  215. package/esm/components/dialog.js.map +1 -0
  216. package/esm/components/dialog.spec.d.ts +2 -0
  217. package/esm/components/dialog.spec.d.ts.map +1 -0
  218. package/esm/components/dialog.spec.js +113 -0
  219. package/esm/components/dialog.spec.js.map +1 -0
  220. package/esm/components/divider.d.ts +22 -0
  221. package/esm/components/divider.d.ts.map +1 -0
  222. package/esm/components/divider.js +113 -0
  223. package/esm/components/divider.js.map +1 -0
  224. package/esm/components/divider.spec.d.ts +2 -0
  225. package/esm/components/divider.spec.d.ts.map +1 -0
  226. package/esm/components/divider.spec.js +136 -0
  227. package/esm/components/divider.spec.js.map +1 -0
  228. package/esm/components/drawer/drawer-toggle-button.d.ts +36 -0
  229. package/esm/components/drawer/drawer-toggle-button.d.ts.map +1 -0
  230. package/esm/components/drawer/drawer-toggle-button.js +94 -0
  231. package/esm/components/drawer/drawer-toggle-button.js.map +1 -0
  232. package/esm/components/drawer/drawer-toggle-button.spec.d.ts +2 -0
  233. package/esm/components/drawer/drawer-toggle-button.spec.d.ts.map +1 -0
  234. package/esm/components/drawer/drawer-toggle-button.spec.js +306 -0
  235. package/esm/components/drawer/drawer-toggle-button.spec.js.map +1 -0
  236. package/esm/components/drawer/index.d.ts +56 -0
  237. package/esm/components/drawer/index.d.ts.map +1 -0
  238. package/esm/components/drawer/index.js +172 -0
  239. package/esm/components/drawer/index.js.map +1 -0
  240. package/esm/components/drawer/index.spec.d.ts +2 -0
  241. package/esm/components/drawer/index.spec.d.ts.map +1 -0
  242. package/esm/components/drawer/index.spec.js +538 -0
  243. package/esm/components/drawer/index.spec.js.map +1 -0
  244. package/esm/components/dropdown.d.ts +15 -0
  245. package/esm/components/dropdown.d.ts.map +1 -0
  246. package/esm/components/dropdown.js +262 -0
  247. package/esm/components/dropdown.js.map +1 -0
  248. package/esm/components/dropdown.spec.d.ts +2 -0
  249. package/esm/components/dropdown.spec.d.ts.map +1 -0
  250. package/esm/components/dropdown.spec.js +372 -0
  251. package/esm/components/dropdown.spec.js.map +1 -0
  252. package/esm/components/fab.d.ts +10 -1
  253. package/esm/components/fab.d.ts.map +1 -1
  254. package/esm/components/fab.js +32 -7
  255. package/esm/components/fab.js.map +1 -1
  256. package/esm/components/fab.spec.d.ts +2 -0
  257. package/esm/components/fab.spec.d.ts.map +1 -0
  258. package/esm/components/fab.spec.js +106 -0
  259. package/esm/components/fab.spec.js.map +1 -0
  260. package/esm/components/form.d.ts.map +1 -1
  261. package/esm/components/form.js +9 -7
  262. package/esm/components/form.js.map +1 -1
  263. package/esm/components/form.spec.d.ts +2 -0
  264. package/esm/components/form.spec.d.ts.map +1 -0
  265. package/esm/components/form.spec.js +324 -0
  266. package/esm/components/form.spec.js.map +1 -0
  267. package/esm/components/grid.d.ts.map +1 -1
  268. package/esm/components/grid.js +43 -40
  269. package/esm/components/grid.js.map +1 -1
  270. package/esm/components/grid.spec.d.ts +2 -0
  271. package/esm/components/grid.spec.d.ts.map +1 -0
  272. package/esm/components/grid.spec.js +340 -0
  273. package/esm/components/grid.spec.js.map +1 -0
  274. package/esm/components/icons/icon-definitions.d.ts +140 -0
  275. package/esm/components/icons/icon-definitions.d.ts.map +1 -0
  276. package/esm/components/icons/icon-definitions.js +432 -0
  277. package/esm/components/icons/icon-definitions.js.map +1 -0
  278. package/esm/components/icons/icon-definitions.spec.d.ts +2 -0
  279. package/esm/components/icons/icon-definitions.spec.d.ts.map +1 -0
  280. package/esm/components/icons/icon-definitions.spec.js +59 -0
  281. package/esm/components/icons/icon-definitions.spec.js.map +1 -0
  282. package/esm/components/icons/icon-types.d.ts +48 -0
  283. package/esm/components/icons/icon-types.d.ts.map +1 -0
  284. package/esm/components/icons/icon-types.js +2 -0
  285. package/esm/components/icons/icon-types.js.map +1 -0
  286. package/esm/components/icons/icon.d.ts +56 -0
  287. package/esm/components/icons/icon.d.ts.map +1 -0
  288. package/esm/components/icons/icon.js +61 -0
  289. package/esm/components/icons/icon.js.map +1 -0
  290. package/esm/components/icons/icon.spec.d.ts +2 -0
  291. package/esm/components/icons/icon.spec.d.ts.map +1 -0
  292. package/esm/components/icons/icon.spec.js +224 -0
  293. package/esm/components/icons/icon.spec.js.map +1 -0
  294. package/esm/components/icons/index.d.ts +5 -0
  295. package/esm/components/icons/index.d.ts.map +1 -0
  296. package/esm/components/icons/index.js +3 -0
  297. package/esm/components/icons/index.js.map +1 -0
  298. package/esm/components/image.d.ts +62 -0
  299. package/esm/components/image.d.ts.map +1 -0
  300. package/esm/components/image.js +348 -0
  301. package/esm/components/image.js.map +1 -0
  302. package/esm/components/image.spec.d.ts +2 -0
  303. package/esm/components/image.spec.d.ts.map +1 -0
  304. package/esm/components/image.spec.js +542 -0
  305. package/esm/components/image.spec.js.map +1 -0
  306. package/esm/components/index.d.ts +32 -4
  307. package/esm/components/index.d.ts.map +1 -1
  308. package/esm/components/index.js +32 -4
  309. package/esm/components/index.js.map +1 -1
  310. package/esm/components/inputs/autocomplete.d.ts +2 -0
  311. package/esm/components/inputs/autocomplete.d.ts.map +1 -1
  312. package/esm/components/inputs/autocomplete.js +10 -6
  313. package/esm/components/inputs/autocomplete.js.map +1 -1
  314. package/esm/components/inputs/autocomplete.spec.d.ts +2 -0
  315. package/esm/components/inputs/autocomplete.spec.d.ts.map +1 -0
  316. package/esm/components/inputs/autocomplete.spec.js +203 -0
  317. package/esm/components/inputs/autocomplete.spec.js.map +1 -0
  318. package/esm/components/inputs/checkbox.d.ts +50 -0
  319. package/esm/components/inputs/checkbox.d.ts.map +1 -0
  320. package/esm/components/inputs/checkbox.js +126 -0
  321. package/esm/components/inputs/checkbox.js.map +1 -0
  322. package/esm/components/inputs/checkbox.spec.d.ts +2 -0
  323. package/esm/components/inputs/checkbox.spec.d.ts.map +1 -0
  324. package/esm/components/inputs/checkbox.spec.js +287 -0
  325. package/esm/components/inputs/checkbox.spec.js.map +1 -0
  326. package/esm/components/inputs/index.d.ts +7 -0
  327. package/esm/components/inputs/index.d.ts.map +1 -1
  328. package/esm/components/inputs/index.js +7 -0
  329. package/esm/components/inputs/index.js.map +1 -1
  330. package/esm/components/inputs/input-number.d.ts +79 -0
  331. package/esm/components/inputs/input-number.d.ts.map +1 -0
  332. package/esm/components/inputs/input-number.js +232 -0
  333. package/esm/components/inputs/input-number.js.map +1 -0
  334. package/esm/components/inputs/input-number.spec.d.ts +2 -0
  335. package/esm/components/inputs/input-number.spec.d.ts.map +1 -0
  336. package/esm/components/inputs/input-number.spec.js +516 -0
  337. package/esm/components/inputs/input-number.spec.js.map +1 -0
  338. package/esm/components/inputs/input.d.ts +2 -1
  339. package/esm/components/inputs/input.d.ts.map +1 -1
  340. package/esm/components/inputs/input.js +179 -177
  341. package/esm/components/inputs/input.js.map +1 -1
  342. package/esm/components/inputs/input.spec.d.ts +2 -0
  343. package/esm/components/inputs/input.spec.d.ts.map +1 -0
  344. package/esm/components/inputs/input.spec.js +611 -0
  345. package/esm/components/inputs/input.spec.js.map +1 -0
  346. package/esm/components/inputs/radio-group.d.ts +38 -0
  347. package/esm/components/inputs/radio-group.d.ts.map +1 -0
  348. package/esm/components/inputs/radio-group.js +58 -0
  349. package/esm/components/inputs/radio-group.js.map +1 -0
  350. package/esm/components/inputs/radio-group.spec.d.ts +2 -0
  351. package/esm/components/inputs/radio-group.spec.d.ts.map +1 -0
  352. package/esm/components/inputs/radio-group.spec.js +201 -0
  353. package/esm/components/inputs/radio-group.spec.js.map +1 -0
  354. package/esm/components/inputs/radio.d.ts +42 -0
  355. package/esm/components/inputs/radio.d.ts.map +1 -0
  356. package/esm/components/inputs/radio.js +134 -0
  357. package/esm/components/inputs/radio.js.map +1 -0
  358. package/esm/components/inputs/radio.spec.d.ts +2 -0
  359. package/esm/components/inputs/radio.spec.d.ts.map +1 -0
  360. package/esm/components/inputs/radio.spec.js +211 -0
  361. package/esm/components/inputs/radio.spec.js.map +1 -0
  362. package/esm/components/inputs/select.d.ts +67 -0
  363. package/esm/components/inputs/select.d.ts.map +1 -0
  364. package/esm/components/inputs/select.js +581 -0
  365. package/esm/components/inputs/select.js.map +1 -0
  366. package/esm/components/inputs/select.spec.d.ts +2 -0
  367. package/esm/components/inputs/select.spec.d.ts.map +1 -0
  368. package/esm/components/inputs/select.spec.js +1009 -0
  369. package/esm/components/inputs/select.spec.js.map +1 -0
  370. package/esm/components/inputs/slider.d.ts +66 -0
  371. package/esm/components/inputs/slider.d.ts.map +1 -0
  372. package/esm/components/inputs/slider.js +526 -0
  373. package/esm/components/inputs/slider.js.map +1 -0
  374. package/esm/components/inputs/slider.spec.d.ts +2 -0
  375. package/esm/components/inputs/slider.spec.d.ts.map +1 -0
  376. package/esm/components/inputs/slider.spec.js +812 -0
  377. package/esm/components/inputs/slider.spec.js.map +1 -0
  378. package/esm/components/inputs/switch.d.ts +50 -0
  379. package/esm/components/inputs/switch.d.ts.map +1 -0
  380. package/esm/components/inputs/switch.js +138 -0
  381. package/esm/components/inputs/switch.js.map +1 -0
  382. package/esm/components/inputs/switch.spec.d.ts +2 -0
  383. package/esm/components/inputs/switch.spec.d.ts.map +1 -0
  384. package/esm/components/inputs/switch.spec.js +313 -0
  385. package/esm/components/inputs/switch.spec.js.map +1 -0
  386. package/esm/components/inputs/text-area.d.ts +2 -0
  387. package/esm/components/inputs/text-area.d.ts.map +1 -1
  388. package/esm/components/inputs/text-area.js +46 -58
  389. package/esm/components/inputs/text-area.js.map +1 -1
  390. package/esm/components/inputs/text-area.spec.d.ts +2 -0
  391. package/esm/components/inputs/text-area.spec.d.ts.map +1 -0
  392. package/esm/components/inputs/text-area.spec.js +229 -0
  393. package/esm/components/inputs/text-area.spec.js.map +1 -0
  394. package/esm/components/linear-progress.d.ts +32 -0
  395. package/esm/components/linear-progress.d.ts.map +1 -0
  396. package/esm/components/linear-progress.js +79 -0
  397. package/esm/components/linear-progress.js.map +1 -0
  398. package/esm/components/linear-progress.spec.d.ts +2 -0
  399. package/esm/components/linear-progress.spec.d.ts.map +1 -0
  400. package/esm/components/linear-progress.spec.js +251 -0
  401. package/esm/components/linear-progress.spec.js.map +1 -0
  402. package/esm/components/list/index.d.ts +3 -0
  403. package/esm/components/list/index.d.ts.map +1 -0
  404. package/esm/components/list/index.js +3 -0
  405. package/esm/components/list/index.js.map +1 -0
  406. package/esm/components/list/list-item.d.ts +13 -0
  407. package/esm/components/list/list-item.d.ts.map +1 -0
  408. package/esm/components/list/list-item.js +81 -0
  409. package/esm/components/list/list-item.js.map +1 -0
  410. package/esm/components/list/list.d.ts +18 -0
  411. package/esm/components/list/list.d.ts.map +1 -0
  412. package/esm/components/list/list.js +42 -0
  413. package/esm/components/list/list.js.map +1 -0
  414. package/esm/components/list/list.spec.d.ts +2 -0
  415. package/esm/components/list/list.spec.d.ts.map +1 -0
  416. package/esm/components/list/list.spec.js +540 -0
  417. package/esm/components/list/list.spec.js.map +1 -0
  418. package/esm/components/loader.d.ts +2 -0
  419. package/esm/components/loader.d.ts.map +1 -1
  420. package/esm/components/loader.js +19 -11
  421. package/esm/components/loader.js.map +1 -1
  422. package/esm/components/loader.spec.d.ts +2 -0
  423. package/esm/components/loader.spec.d.ts.map +1 -0
  424. package/esm/components/loader.spec.js +267 -0
  425. package/esm/components/loader.spec.js.map +1 -0
  426. package/esm/components/menu/index.d.ts +3 -0
  427. package/esm/components/menu/index.d.ts.map +1 -0
  428. package/esm/components/menu/index.js +3 -0
  429. package/esm/components/menu/index.js.map +1 -0
  430. package/esm/components/menu/menu-types.d.ts +27 -0
  431. package/esm/components/menu/menu-types.d.ts.map +1 -0
  432. package/esm/components/menu/menu-types.js +22 -0
  433. package/esm/components/menu/menu-types.js.map +1 -0
  434. package/esm/components/menu/menu-types.spec.d.ts +2 -0
  435. package/esm/components/menu/menu-types.spec.d.ts.map +1 -0
  436. package/esm/components/menu/menu-types.spec.js +103 -0
  437. package/esm/components/menu/menu-types.spec.js.map +1 -0
  438. package/esm/components/menu/menu.d.ts +17 -0
  439. package/esm/components/menu/menu.d.ts.map +1 -0
  440. package/esm/components/menu/menu.js +240 -0
  441. package/esm/components/menu/menu.js.map +1 -0
  442. package/esm/components/menu/menu.spec.d.ts +2 -0
  443. package/esm/components/menu/menu.spec.d.ts.map +1 -0
  444. package/esm/components/menu/menu.spec.js +427 -0
  445. package/esm/components/menu/menu.spec.js.map +1 -0
  446. package/esm/components/modal.d.ts +3 -2
  447. package/esm/components/modal.d.ts.map +1 -1
  448. package/esm/components/modal.js +19 -14
  449. package/esm/components/modal.js.map +1 -1
  450. package/esm/components/modal.spec.d.ts +2 -0
  451. package/esm/components/modal.spec.d.ts.map +1 -0
  452. package/esm/components/modal.spec.js +234 -0
  453. package/esm/components/modal.spec.js.map +1 -0
  454. package/esm/components/noty-list.d.ts +4 -0
  455. package/esm/components/noty-list.d.ts.map +1 -1
  456. package/esm/components/noty-list.js +87 -76
  457. package/esm/components/noty-list.js.map +1 -1
  458. package/esm/components/noty-list.spec.d.ts +2 -0
  459. package/esm/components/noty-list.spec.d.ts.map +1 -0
  460. package/esm/components/noty-list.spec.js +489 -0
  461. package/esm/components/noty-list.spec.js.map +1 -0
  462. package/esm/components/page-container/index.d.ts +54 -0
  463. package/esm/components/page-container/index.d.ts.map +1 -0
  464. package/esm/components/page-container/index.js +63 -0
  465. package/esm/components/page-container/index.js.map +1 -0
  466. package/esm/components/page-container/index.spec.d.ts +2 -0
  467. package/esm/components/page-container/index.spec.d.ts.map +1 -0
  468. package/esm/components/page-container/index.spec.js +217 -0
  469. package/esm/components/page-container/index.spec.js.map +1 -0
  470. package/esm/components/page-container/page-header.d.ts +57 -0
  471. package/esm/components/page-container/page-header.d.ts.map +1 -0
  472. package/esm/components/page-container/page-header.js +93 -0
  473. package/esm/components/page-container/page-header.js.map +1 -0
  474. package/esm/components/page-container/page-header.spec.d.ts +2 -0
  475. package/esm/components/page-container/page-header.spec.d.ts.map +1 -0
  476. package/esm/components/page-container/page-header.spec.js +230 -0
  477. package/esm/components/page-container/page-header.spec.js.map +1 -0
  478. package/esm/components/page-layout/index.d.ts +83 -0
  479. package/esm/components/page-layout/index.d.ts.map +1 -0
  480. package/esm/components/page-layout/index.js +288 -0
  481. package/esm/components/page-layout/index.js.map +1 -0
  482. package/esm/components/page-layout/index.spec.d.ts +2 -0
  483. package/esm/components/page-layout/index.spec.d.ts.map +1 -0
  484. package/esm/components/page-layout/index.spec.js +637 -0
  485. package/esm/components/page-layout/index.spec.js.map +1 -0
  486. package/esm/components/pagination.d.ts +43 -0
  487. package/esm/components/pagination.d.ts.map +1 -0
  488. package/esm/components/pagination.js +165 -0
  489. package/esm/components/pagination.js.map +1 -0
  490. package/esm/components/pagination.spec.d.ts +2 -0
  491. package/esm/components/pagination.spec.d.ts.map +1 -0
  492. package/esm/components/pagination.spec.js +195 -0
  493. package/esm/components/pagination.spec.js.map +1 -0
  494. package/esm/components/paper.d.ts +3 -1
  495. package/esm/components/paper.d.ts.map +1 -1
  496. package/esm/components/paper.js +20 -15
  497. package/esm/components/paper.js.map +1 -1
  498. package/esm/components/paper.spec.d.ts +2 -0
  499. package/esm/components/paper.spec.d.ts.map +1 -0
  500. package/esm/components/paper.spec.js +71 -0
  501. package/esm/components/paper.spec.js.map +1 -0
  502. package/esm/components/rating.d.ts +62 -0
  503. package/esm/components/rating.d.ts.map +1 -0
  504. package/esm/components/rating.js +201 -0
  505. package/esm/components/rating.js.map +1 -0
  506. package/esm/components/rating.spec.d.ts +2 -0
  507. package/esm/components/rating.spec.d.ts.map +1 -0
  508. package/esm/components/rating.spec.js +663 -0
  509. package/esm/components/rating.spec.js.map +1 -0
  510. package/esm/components/result.d.ts +37 -0
  511. package/esm/components/result.d.ts.map +1 -0
  512. package/esm/components/result.js +109 -0
  513. package/esm/components/result.js.map +1 -0
  514. package/esm/components/result.spec.d.ts +2 -0
  515. package/esm/components/result.spec.d.ts.map +1 -0
  516. package/esm/components/result.spec.js +159 -0
  517. package/esm/components/result.spec.js.map +1 -0
  518. package/esm/components/searchable-input-styles.d.ts +8 -0
  519. package/esm/components/searchable-input-styles.d.ts.map +1 -0
  520. package/esm/components/searchable-input-styles.js +71 -0
  521. package/esm/components/searchable-input-styles.js.map +1 -0
  522. package/esm/components/skeleton.d.ts +2 -0
  523. package/esm/components/skeleton.d.ts.map +1 -1
  524. package/esm/components/skeleton.js +20 -7
  525. package/esm/components/skeleton.js.map +1 -1
  526. package/esm/components/skeleton.spec.d.ts +2 -0
  527. package/esm/components/skeleton.spec.d.ts.map +1 -0
  528. package/esm/components/skeleton.spec.js +167 -0
  529. package/esm/components/skeleton.spec.js.map +1 -0
  530. package/esm/components/styles.d.ts.map +1 -1
  531. package/esm/components/styles.js +14 -13
  532. package/esm/components/styles.js.map +1 -1
  533. package/esm/components/styles.spec.d.ts +2 -0
  534. package/esm/components/styles.spec.d.ts.map +1 -0
  535. package/esm/components/styles.spec.js +57 -0
  536. package/esm/components/styles.spec.js.map +1 -0
  537. package/esm/components/suggest/index.d.ts.map +1 -1
  538. package/esm/components/suggest/index.js +32 -102
  539. package/esm/components/suggest/index.js.map +1 -1
  540. package/esm/components/suggest/index.spec.d.ts +2 -0
  541. package/esm/components/suggest/index.spec.d.ts.map +1 -0
  542. package/esm/components/suggest/index.spec.js +539 -0
  543. package/esm/components/suggest/index.spec.js.map +1 -0
  544. package/esm/components/suggest/suggest-input.d.ts +2 -0
  545. package/esm/components/suggest/suggest-input.d.ts.map +1 -1
  546. package/esm/components/suggest/suggest-input.js +24 -23
  547. package/esm/components/suggest/suggest-input.js.map +1 -1
  548. package/esm/components/suggest/suggest-input.spec.d.ts +2 -0
  549. package/esm/components/suggest/suggest-input.spec.d.ts.map +1 -0
  550. package/esm/components/suggest/suggest-input.spec.js +150 -0
  551. package/esm/components/suggest/suggest-input.spec.js.map +1 -0
  552. package/esm/components/suggest/suggest-manager.spec.d.ts +2 -0
  553. package/esm/components/suggest/suggest-manager.spec.d.ts.map +1 -0
  554. package/esm/components/suggest/suggest-manager.spec.js +318 -0
  555. package/esm/components/suggest/suggest-manager.spec.js.map +1 -0
  556. package/esm/components/suggest/suggestion-list.d.ts.map +1 -1
  557. package/esm/components/suggest/suggestion-list.js +52 -58
  558. package/esm/components/suggest/suggestion-list.js.map +1 -1
  559. package/esm/components/suggest/suggestion-list.spec.d.ts +2 -0
  560. package/esm/components/suggest/suggestion-list.spec.d.ts.map +1 -0
  561. package/esm/components/suggest/suggestion-list.spec.js +271 -0
  562. package/esm/components/suggest/suggestion-list.spec.js.map +1 -0
  563. package/esm/components/tabs.d.ts +18 -2
  564. package/esm/components/tabs.d.ts.map +1 -1
  565. package/esm/components/tabs.js +173 -19
  566. package/esm/components/tabs.js.map +1 -1
  567. package/esm/components/tabs.spec.d.ts +2 -0
  568. package/esm/components/tabs.spec.d.ts.map +1 -0
  569. package/esm/components/tabs.spec.js +475 -0
  570. package/esm/components/tabs.spec.js.map +1 -0
  571. package/esm/components/timeline.d.ts +53 -0
  572. package/esm/components/timeline.d.ts.map +1 -0
  573. package/esm/components/timeline.js +162 -0
  574. package/esm/components/timeline.js.map +1 -0
  575. package/esm/components/timeline.spec.d.ts +2 -0
  576. package/esm/components/timeline.spec.d.ts.map +1 -0
  577. package/esm/components/timeline.spec.js +209 -0
  578. package/esm/components/timeline.spec.js.map +1 -0
  579. package/esm/components/tooltip.d.ts +25 -0
  580. package/esm/components/tooltip.d.ts.map +1 -0
  581. package/esm/components/tooltip.js +113 -0
  582. package/esm/components/tooltip.js.map +1 -0
  583. package/esm/components/tooltip.spec.d.ts +2 -0
  584. package/esm/components/tooltip.spec.d.ts.map +1 -0
  585. package/esm/components/tooltip.spec.js +152 -0
  586. package/esm/components/tooltip.spec.js.map +1 -0
  587. package/esm/components/tree/index.d.ts +3 -0
  588. package/esm/components/tree/index.d.ts.map +1 -0
  589. package/esm/components/tree/index.js +3 -0
  590. package/esm/components/tree/index.js.map +1 -0
  591. package/esm/components/tree/tree-item.d.ts +14 -0
  592. package/esm/components/tree/tree-item.d.ts.map +1 -0
  593. package/esm/components/tree/tree-item.js +118 -0
  594. package/esm/components/tree/tree-item.js.map +1 -0
  595. package/esm/components/tree/tree.d.ts +20 -0
  596. package/esm/components/tree/tree.d.ts.map +1 -0
  597. package/esm/components/tree/tree.js +66 -0
  598. package/esm/components/tree/tree.js.map +1 -0
  599. package/esm/components/tree/tree.spec.d.ts +2 -0
  600. package/esm/components/tree/tree.spec.d.ts.map +1 -0
  601. package/esm/components/tree/tree.spec.js +427 -0
  602. package/esm/components/tree/tree.spec.js.map +1 -0
  603. package/esm/components/typography.d.ts +48 -0
  604. package/esm/components/typography.d.ts.map +1 -0
  605. package/esm/components/typography.js +223 -0
  606. package/esm/components/typography.js.map +1 -0
  607. package/esm/components/typography.spec.d.ts +2 -0
  608. package/esm/components/typography.spec.d.ts.map +1 -0
  609. package/esm/components/typography.spec.js +199 -0
  610. package/esm/components/typography.spec.js.map +1 -0
  611. package/esm/components/wizard/index.d.ts +2 -0
  612. package/esm/components/wizard/index.d.ts.map +1 -1
  613. package/esm/components/wizard/index.js +10 -7
  614. package/esm/components/wizard/index.js.map +1 -1
  615. package/esm/components/wizard/index.spec.d.ts +2 -0
  616. package/esm/components/wizard/index.spec.d.ts.map +1 -0
  617. package/esm/components/wizard/index.spec.js +185 -0
  618. package/esm/components/wizard/index.spec.js.map +1 -0
  619. package/esm/services/click-away-service.d.ts +5 -2
  620. package/esm/services/click-away-service.d.ts.map +1 -1
  621. package/esm/services/click-away-service.js +7 -1
  622. package/esm/services/click-away-service.js.map +1 -1
  623. package/esm/services/collection-service.spec.js +391 -2
  624. package/esm/services/collection-service.spec.js.map +1 -1
  625. package/esm/services/css-variable-theme.d.ts +167 -1
  626. package/esm/services/css-variable-theme.d.ts.map +1 -1
  627. package/esm/services/css-variable-theme.js +123 -1
  628. package/esm/services/css-variable-theme.js.map +1 -1
  629. package/esm/services/css-variable-theme.spec.d.ts +2 -0
  630. package/esm/services/css-variable-theme.spec.d.ts.map +1 -0
  631. package/esm/services/css-variable-theme.spec.js +299 -0
  632. package/esm/services/css-variable-theme.spec.js.map +1 -0
  633. package/esm/services/default-dark-theme.d.ts +107 -2
  634. package/esm/services/default-dark-theme.d.ts.map +1 -1
  635. package/esm/services/default-dark-theme.js +87 -1
  636. package/esm/services/default-dark-theme.js.map +1 -1
  637. package/esm/services/default-light-theme.d.ts +107 -2
  638. package/esm/services/default-light-theme.d.ts.map +1 -1
  639. package/esm/services/default-light-theme.js +86 -0
  640. package/esm/services/default-light-theme.js.map +1 -1
  641. package/esm/services/default-palette.d.ts +4 -0
  642. package/esm/services/default-palette.d.ts.map +1 -1
  643. package/esm/services/default-palette.js +22 -0
  644. package/esm/services/default-palette.js.map +1 -1
  645. package/esm/services/index.d.ts +6 -2
  646. package/esm/services/index.d.ts.map +1 -1
  647. package/esm/services/index.js +6 -2
  648. package/esm/services/index.js.map +1 -1
  649. package/esm/services/layout-service.d.ts +217 -0
  650. package/esm/services/layout-service.d.ts.map +1 -0
  651. package/esm/services/layout-service.js +331 -0
  652. package/esm/services/layout-service.js.map +1 -0
  653. package/esm/services/layout-service.spec.d.ts +2 -0
  654. package/esm/services/layout-service.spec.d.ts.map +1 -0
  655. package/esm/services/layout-service.spec.js +425 -0
  656. package/esm/services/layout-service.spec.js.map +1 -0
  657. package/esm/services/list-service.d.ts +31 -0
  658. package/esm/services/list-service.d.ts.map +1 -0
  659. package/esm/services/list-service.js +149 -0
  660. package/esm/services/list-service.js.map +1 -0
  661. package/esm/services/list-service.spec.d.ts +2 -0
  662. package/esm/services/list-service.spec.d.ts.map +1 -0
  663. package/esm/services/list-service.spec.js +254 -0
  664. package/esm/services/list-service.spec.js.map +1 -0
  665. package/esm/services/palette-css-vars.d.ts +12 -0
  666. package/esm/services/palette-css-vars.d.ts.map +1 -0
  667. package/esm/services/palette-css-vars.js +44 -0
  668. package/esm/services/palette-css-vars.js.map +1 -0
  669. package/esm/services/theme-provider-service.d.ts +445 -2
  670. package/esm/services/theme-provider-service.d.ts.map +1 -1
  671. package/esm/services/theme-provider-service.js.map +1 -1
  672. package/esm/services/theme-provider-service.spec.d.ts +2 -0
  673. package/esm/services/theme-provider-service.spec.d.ts.map +1 -0
  674. package/esm/services/theme-provider-service.spec.js +166 -0
  675. package/esm/services/theme-provider-service.spec.js.map +1 -0
  676. package/esm/services/tree-service.d.ts +61 -0
  677. package/esm/services/tree-service.d.ts.map +1 -0
  678. package/esm/services/tree-service.js +149 -0
  679. package/esm/services/tree-service.js.map +1 -0
  680. package/esm/services/tree-service.spec.d.ts +2 -0
  681. package/esm/services/tree-service.spec.d.ts.map +1 -0
  682. package/esm/services/tree-service.spec.js +307 -0
  683. package/esm/services/tree-service.spec.js.map +1 -0
  684. package/esm/utils/promisify-animation.d.ts.map +1 -1
  685. package/esm/utils/promisify-animation.js +6 -1
  686. package/esm/utils/promisify-animation.js.map +1 -1
  687. package/package.json +4 -4
  688. package/src/components/accordion/accordion-item.tsx +197 -0
  689. package/src/components/accordion/accordion.spec.tsx +418 -0
  690. package/src/components/accordion/accordion.tsx +50 -0
  691. package/src/components/accordion/index.ts +2 -0
  692. package/src/components/alert.spec.tsx +256 -0
  693. package/src/components/alert.tsx +186 -0
  694. package/src/components/animations.spec.ts +299 -0
  695. package/src/components/app-bar-link.spec.tsx +344 -0
  696. package/src/components/app-bar-link.tsx +44 -25
  697. package/src/components/app-bar.spec.tsx +157 -0
  698. package/src/components/app-bar.tsx +31 -24
  699. package/src/components/avatar.spec.tsx +146 -0
  700. package/src/components/avatar.tsx +56 -60
  701. package/src/components/badge.spec.tsx +228 -0
  702. package/src/components/badge.tsx +104 -0
  703. package/src/components/breadcrumb.spec.tsx +396 -0
  704. package/src/components/breadcrumb.tsx +188 -0
  705. package/src/components/button-group.spec.tsx +611 -0
  706. package/src/components/button-group.tsx +423 -0
  707. package/src/components/button.spec.tsx +383 -0
  708. package/src/components/button.tsx +211 -196
  709. package/src/components/card.spec.tsx +389 -0
  710. package/src/components/card.tsx +261 -0
  711. package/src/components/carousel.spec.tsx +894 -0
  712. package/src/components/carousel.tsx +376 -0
  713. package/src/components/chip.spec.tsx +200 -0
  714. package/src/components/chip.tsx +188 -0
  715. package/src/components/circular-progress.spec.tsx +289 -0
  716. package/src/components/circular-progress.tsx +145 -0
  717. package/src/components/command-palette/command-palette-input.spec.tsx +331 -0
  718. package/src/components/command-palette/command-palette-input.tsx +40 -27
  719. package/src/components/command-palette/command-palette-manager.spec.ts +485 -0
  720. package/src/components/command-palette/command-palette-suggestion-list.spec.tsx +517 -0
  721. package/src/components/command-palette/command-palette-suggestion-list.tsx +55 -57
  722. package/src/components/command-palette/index.spec.tsx +684 -0
  723. package/src/components/command-palette/index.tsx +42 -148
  724. package/src/components/context-menu/context-menu-item.tsx +85 -0
  725. package/src/components/context-menu/context-menu-manager.spec.ts +478 -0
  726. package/src/components/context-menu/context-menu-manager.ts +148 -0
  727. package/src/components/context-menu/context-menu.spec.tsx +352 -0
  728. package/src/components/context-menu/context-menu.tsx +116 -0
  729. package/src/components/context-menu/index.ts +3 -0
  730. package/src/components/data-grid/body.spec.tsx +354 -0
  731. package/src/components/data-grid/body.tsx +1 -1
  732. package/src/components/data-grid/data-grid-row.spec.tsx +407 -0
  733. package/src/components/data-grid/data-grid-row.tsx +87 -102
  734. package/src/components/data-grid/data-grid.spec.tsx +964 -0
  735. package/src/components/data-grid/data-grid.tsx +45 -38
  736. package/src/components/data-grid/footer.spec.tsx +356 -0
  737. package/src/components/data-grid/footer.tsx +19 -19
  738. package/src/components/data-grid/header.spec.tsx +586 -0
  739. package/src/components/data-grid/header.tsx +104 -76
  740. package/src/components/data-grid/selection-cell.spec.tsx +151 -0
  741. package/src/components/data-grid/selection-cell.tsx +14 -12
  742. package/src/components/dialog.spec.tsx +135 -0
  743. package/src/components/dialog.tsx +277 -0
  744. package/src/components/divider.spec.tsx +197 -0
  745. package/src/components/divider.tsx +147 -0
  746. package/src/components/drawer/drawer-toggle-button.spec.tsx +374 -0
  747. package/src/components/drawer/drawer-toggle-button.tsx +124 -0
  748. package/src/components/drawer/index.spec.tsx +748 -0
  749. package/src/components/drawer/index.tsx +227 -0
  750. package/src/components/dropdown.spec.tsx +445 -0
  751. package/src/components/dropdown.tsx +343 -0
  752. package/src/components/fab.spec.tsx +119 -0
  753. package/src/components/fab.tsx +40 -8
  754. package/src/components/form.spec.tsx +491 -0
  755. package/src/components/form.tsx +10 -7
  756. package/src/components/grid.spec.tsx +427 -0
  757. package/src/components/grid.tsx +60 -66
  758. package/src/components/icons/icon-definitions.spec.ts +68 -0
  759. package/src/components/icons/icon-definitions.ts +509 -0
  760. package/src/components/icons/icon-types.ts +48 -0
  761. package/src/components/icons/icon.spec.tsx +314 -0
  762. package/src/components/icons/icon.tsx +111 -0
  763. package/src/components/icons/index.ts +4 -0
  764. package/src/components/image.spec.tsx +748 -0
  765. package/src/components/image.tsx +520 -0
  766. package/src/components/index.ts +32 -4
  767. package/src/components/inputs/autocomplete.spec.tsx +267 -0
  768. package/src/components/inputs/autocomplete.tsx +13 -7
  769. package/src/components/inputs/checkbox.spec.tsx +377 -0
  770. package/src/components/inputs/checkbox.tsx +198 -0
  771. package/src/components/inputs/index.ts +7 -0
  772. package/src/components/inputs/input-number.spec.tsx +686 -0
  773. package/src/components/inputs/input-number.tsx +387 -0
  774. package/src/components/inputs/input.spec.tsx +844 -0
  775. package/src/components/inputs/input.tsx +191 -218
  776. package/src/components/inputs/radio-group.spec.tsx +281 -0
  777. package/src/components/inputs/radio-group.tsx +108 -0
  778. package/src/components/inputs/radio.spec.tsx +273 -0
  779. package/src/components/inputs/radio.tsx +199 -0
  780. package/src/components/inputs/select.spec.tsx +1237 -0
  781. package/src/components/inputs/select.tsx +775 -0
  782. package/src/components/inputs/slider.spec.tsx +1020 -0
  783. package/src/components/inputs/slider.tsx +696 -0
  784. package/src/components/inputs/switch.spec.tsx +410 -0
  785. package/src/components/inputs/switch.tsx +218 -0
  786. package/src/components/inputs/text-area.spec.tsx +300 -0
  787. package/src/components/inputs/text-area.tsx +47 -79
  788. package/src/components/linear-progress.spec.tsx +320 -0
  789. package/src/components/linear-progress.tsx +127 -0
  790. package/src/components/list/index.ts +2 -0
  791. package/src/components/list/list-item.tsx +106 -0
  792. package/src/components/list/list.spec.tsx +817 -0
  793. package/src/components/list/list.tsx +92 -0
  794. package/src/components/loader.spec.tsx +362 -0
  795. package/src/components/loader.tsx +18 -10
  796. package/src/components/menu/index.ts +2 -0
  797. package/src/components/menu/menu-types.spec.ts +122 -0
  798. package/src/components/menu/menu-types.ts +43 -0
  799. package/src/components/menu/menu.spec.tsx +483 -0
  800. package/src/components/menu/menu.tsx +326 -0
  801. package/src/components/modal.spec.tsx +314 -0
  802. package/src/components/modal.tsx +20 -15
  803. package/src/components/noty-list.spec.tsx +634 -0
  804. package/src/components/noty-list.tsx +98 -101
  805. package/src/components/page-container/index.spec.tsx +274 -0
  806. package/src/components/page-container/index.tsx +82 -0
  807. package/src/components/page-container/page-header.spec.tsx +308 -0
  808. package/src/components/page-container/page-header.tsx +127 -0
  809. package/src/components/page-layout/index.spec.tsx +882 -0
  810. package/src/components/page-layout/index.tsx +392 -0
  811. package/src/components/pagination.spec.tsx +275 -0
  812. package/src/components/pagination.tsx +249 -0
  813. package/src/components/paper.spec.tsx +80 -0
  814. package/src/components/paper.tsx +21 -17
  815. package/src/components/rating.spec.tsx +866 -0
  816. package/src/components/rating.tsx +286 -0
  817. package/src/components/result.spec.tsx +221 -0
  818. package/src/components/result.tsx +155 -0
  819. package/src/components/searchable-input-styles.ts +81 -0
  820. package/src/components/skeleton.spec.tsx +227 -0
  821. package/src/components/skeleton.tsx +24 -7
  822. package/src/components/styles.spec.ts +69 -0
  823. package/src/components/styles.tsx +15 -13
  824. package/src/components/suggest/index.spec.tsx +885 -0
  825. package/src/components/suggest/index.tsx +36 -130
  826. package/src/components/suggest/suggest-input.spec.tsx +195 -0
  827. package/src/components/suggest/suggest-input.tsx +23 -29
  828. package/src/components/suggest/suggest-manager.spec.ts +419 -0
  829. package/src/components/suggest/suggestion-list.spec.tsx +355 -0
  830. package/src/components/suggest/suggestion-list.tsx +54 -58
  831. package/src/components/tabs.spec.tsx +598 -0
  832. package/src/components/tabs.tsx +241 -26
  833. package/src/components/timeline.spec.tsx +294 -0
  834. package/src/components/timeline.tsx +221 -0
  835. package/src/components/tooltip.spec.tsx +223 -0
  836. package/src/components/tooltip.tsx +155 -0
  837. package/src/components/tree/index.ts +2 -0
  838. package/src/components/tree/tree-item.tsx +161 -0
  839. package/src/components/tree/tree.spec.tsx +677 -0
  840. package/src/components/tree/tree.tsx +111 -0
  841. package/src/components/typography.spec.tsx +235 -0
  842. package/src/components/typography.tsx +292 -0
  843. package/src/components/wizard/index.spec.tsx +233 -0
  844. package/src/components/wizard/index.tsx +10 -9
  845. package/src/services/click-away-service.ts +9 -3
  846. package/src/services/collection-service.spec.ts +492 -3
  847. package/src/services/css-variable-theme.spec.ts +372 -0
  848. package/src/services/css-variable-theme.ts +128 -3
  849. package/src/services/default-dark-theme.ts +89 -3
  850. package/src/services/default-light-theme.ts +88 -2
  851. package/src/services/default-palette.ts +22 -0
  852. package/src/services/index.ts +6 -2
  853. package/src/services/layout-service.spec.ts +535 -0
  854. package/src/services/layout-service.ts +391 -0
  855. package/src/services/list-service.spec.ts +364 -0
  856. package/src/services/list-service.ts +169 -0
  857. package/src/services/palette-css-vars.ts +46 -0
  858. package/src/services/theme-provider-service.spec.ts +195 -0
  859. package/src/services/theme-provider-service.ts +305 -2
  860. package/src/services/tree-service.spec.ts +428 -0
  861. package/src/services/tree-service.ts +179 -0
  862. package/src/utils/promisify-animation.ts +7 -1
@@ -0,0 +1,1237 @@
1
+ import { Injector } from '@furystack/inject'
2
+ import { createComponent, initializeShadeRoot } from '@furystack/shades'
3
+ import { sleepAsync, usingAsync } from '@furystack/utils'
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
5
+ import type { SelectOption, SelectOptionGroup, SelectProps, SelectState } from './select.js'
6
+ import { Select } from './select.js'
7
+
8
+ describe('Select', () => {
9
+ beforeEach(() => {
10
+ document.body.innerHTML = '<div id="root"></div>'
11
+ })
12
+
13
+ afterEach(() => {
14
+ document.body.innerHTML = ''
15
+ vi.restoreAllMocks()
16
+ })
17
+
18
+ const defaultOptions: SelectOption[] = [
19
+ { value: 'a', label: 'Alpha' },
20
+ { value: 'b', label: 'Beta' },
21
+ { value: 'c', label: 'Gamma' },
22
+ ]
23
+
24
+ const renderSelect = async (props: SelectProps = { options: defaultOptions }) => {
25
+ const injector = new Injector()
26
+ const root = document.getElementById('root')!
27
+ initializeShadeRoot({
28
+ injector,
29
+ rootElement: root,
30
+ jsxElement: <Select {...props} />,
31
+ })
32
+ await sleepAsync(100)
33
+ return {
34
+ injector,
35
+ select: document.querySelector('shade-select') as HTMLElement,
36
+ [Symbol.asyncDispose]: () => injector[Symbol.asyncDispose](),
37
+ }
38
+ }
39
+
40
+ describe('types', () => {
41
+ describe('SelectOption', () => {
42
+ it('Should accept a basic option', () => {
43
+ const option: SelectOption = { value: 'a', label: 'Alpha' }
44
+ expect(option.value).toBe('a')
45
+ expect(option.label).toBe('Alpha')
46
+ expect(option.disabled).toBeUndefined()
47
+ })
48
+
49
+ it('Should accept a disabled option', () => {
50
+ const option: SelectOption = { value: 'a', label: 'Alpha', disabled: true }
51
+ expect(option.disabled).toBe(true)
52
+ })
53
+ })
54
+
55
+ describe('SelectOptionGroup', () => {
56
+ it('Should accept a group with label and options', () => {
57
+ const group: SelectOptionGroup = {
58
+ label: 'Fruits',
59
+ options: [
60
+ { value: 'apple', label: 'Apple' },
61
+ { value: 'banana', label: 'Banana' },
62
+ ],
63
+ }
64
+ expect(group).toHaveProperty('label', 'Fruits')
65
+ expect(group).toHaveProperty('options')
66
+ expect(group.options).toHaveLength(2)
67
+ })
68
+
69
+ it('Should accept an empty group', () => {
70
+ const group: SelectOptionGroup = {
71
+ label: 'Empty',
72
+ options: [],
73
+ }
74
+ expect(group).toHaveProperty('options')
75
+ expect(group.options).toHaveLength(0)
76
+ })
77
+ })
78
+
79
+ describe('SelectState', () => {
80
+ it('Should have all required state fields for single mode', () => {
81
+ const state: SelectState = {
82
+ value: 'test',
83
+ isOpen: false,
84
+ highlightedIndex: -1,
85
+ searchText: '',
86
+ }
87
+ expect(state.value).toBe('test')
88
+ expect(state.isOpen).toBe(false)
89
+ expect(state.highlightedIndex).toBe(-1)
90
+ expect(state.searchText).toBe('')
91
+ })
92
+
93
+ it('Should accept string[] value for multiple mode', () => {
94
+ const state: SelectState = {
95
+ value: ['a', 'b', 'c'],
96
+ isOpen: true,
97
+ highlightedIndex: 0,
98
+ searchText: 'search',
99
+ }
100
+ expect(state.value).toEqual(['a', 'b', 'c'])
101
+ expect(state.searchText).toBe('search')
102
+ })
103
+ })
104
+
105
+ describe('SelectProps', () => {
106
+ it('Should accept minimal props', () => {
107
+ const props: SelectProps = {
108
+ options: [{ value: 'a', label: 'Alpha' }],
109
+ }
110
+ expect(props.options).toHaveLength(1)
111
+ })
112
+
113
+ it('Should accept full single-select props', () => {
114
+ const props: SelectProps = {
115
+ options: [
116
+ { value: 'a', label: 'Alpha' },
117
+ { value: 'b', label: 'Beta', disabled: true },
118
+ ],
119
+ value: 'a',
120
+ placeholder: 'Choose...',
121
+ disabled: false,
122
+ required: true,
123
+ labelTitle: 'My Select',
124
+ variant: 'outlined',
125
+ defaultColor: 'primary',
126
+ name: 'mySelect',
127
+ showSearch: false,
128
+ onValueChange: () => {},
129
+ getValidationResult: () => ({ isValid: true }),
130
+ getHelperText: () => 'Pick one',
131
+ }
132
+ expect(props.options).toHaveLength(2)
133
+ expect(props.value).toBe('a')
134
+ expect(props.variant).toBe('outlined')
135
+ expect(props.required).toBe(true)
136
+ })
137
+
138
+ it('Should accept multiple mode props', () => {
139
+ const onMultiValueChange = vi.fn()
140
+ const props: SelectProps = {
141
+ options: [
142
+ { value: 'a', label: 'Alpha' },
143
+ { value: 'b', label: 'Beta' },
144
+ { value: 'c', label: 'Gamma' },
145
+ ],
146
+ mode: 'multiple',
147
+ value: ['a', 'c'],
148
+ placeholder: 'Select multiple...',
149
+ onMultiValueChange,
150
+ }
151
+ expect(props.mode).toBe('multiple')
152
+ expect(props.value).toEqual(['a', 'c'])
153
+ })
154
+
155
+ it('Should accept searchable props', () => {
156
+ const filterOption = vi.fn().mockReturnValue(true)
157
+ const props: SelectProps = {
158
+ options: [{ value: 'a', label: 'Alpha' }],
159
+ showSearch: true,
160
+ filterOption,
161
+ }
162
+ expect(props.showSearch).toBe(true)
163
+
164
+ filterOption('test', { value: 'a', label: 'Alpha' })
165
+ expect(filterOption).toHaveBeenCalledWith('test', { value: 'a', label: 'Alpha' })
166
+ expect(filterOption).toHaveReturnedWith(true)
167
+ })
168
+
169
+ it('Should accept optionGroups', () => {
170
+ const props: SelectProps = {
171
+ optionGroups: [
172
+ {
173
+ label: 'Fruits',
174
+ options: [
175
+ { value: 'apple', label: 'Apple' },
176
+ { value: 'banana', label: 'Banana' },
177
+ ],
178
+ },
179
+ {
180
+ label: 'Vegetables',
181
+ options: [
182
+ { value: 'carrot', label: 'Carrot' },
183
+ { value: 'potato', label: 'Potato' },
184
+ ],
185
+ },
186
+ ],
187
+ }
188
+ expect(props.optionGroups).toHaveLength(2)
189
+ expect(props.optionGroups?.[0]).toHaveProperty('label', 'Fruits')
190
+ expect(props.optionGroups?.[0].options).toHaveLength(2)
191
+ })
192
+
193
+ it('Should accept combined options and optionGroups', () => {
194
+ const props: SelectProps = {
195
+ options: [{ value: 'none', label: 'None' }],
196
+ optionGroups: [
197
+ {
198
+ label: 'Group A',
199
+ options: [{ value: 'a1', label: 'A1' }],
200
+ },
201
+ ],
202
+ }
203
+ expect(props.options).toHaveLength(1)
204
+ expect(props.optionGroups).toHaveLength(1)
205
+ })
206
+
207
+ it('Should accept all enhancements together', () => {
208
+ const props: SelectProps = {
209
+ optionGroups: [
210
+ {
211
+ label: 'Group 1',
212
+ options: [{ value: 'g1a', label: 'G1-A' }],
213
+ },
214
+ ],
215
+ mode: 'multiple',
216
+ showSearch: true,
217
+ value: ['g1a'],
218
+ filterOption: (text: string, opt: SelectOption) => opt.label.startsWith(text),
219
+ onMultiValueChange: () => {},
220
+ onValueChange: () => {},
221
+ }
222
+ expect(props.mode).toBe('multiple')
223
+ expect(props.showSearch).toBe(true)
224
+ expect(props.optionGroups).toHaveLength(1)
225
+ })
226
+ })
227
+ })
228
+
229
+ describe('rendering', () => {
230
+ it('should render the select element', async () => {
231
+ await usingAsync(await renderSelect(), async ({ select }) => {
232
+ expect(select).not.toBeNull()
233
+ expect(select.tagName.toLowerCase()).toBe('shade-select')
234
+ })
235
+ })
236
+
237
+ it('should render a hidden input for form integration', async () => {
238
+ await usingAsync(await renderSelect({ options: defaultOptions, name: 'myField' }), async ({ select }) => {
239
+ const input = select.querySelector('input[type="hidden"]') as HTMLInputElement
240
+ expect(input).not.toBeNull()
241
+ expect(input.name).toBe('myField')
242
+ })
243
+ })
244
+
245
+ it('should render a label title', async () => {
246
+ await usingAsync(
247
+ await renderSelect({ options: defaultOptions, labelTitle: 'Choose one' }),
248
+ async ({ select }) => {
249
+ expect(select.textContent).toContain('Choose one')
250
+ },
251
+ )
252
+ })
253
+
254
+ it('should show placeholder when no value is selected', async () => {
255
+ await usingAsync(
256
+ await renderSelect({ options: defaultOptions, placeholder: 'Pick something' }),
257
+ async ({ select }) => {
258
+ const valueEl = select.querySelector('.select-value')
259
+ expect(valueEl?.textContent).toContain('Pick something')
260
+ expect(valueEl?.hasAttribute('data-placeholder')).toBe(true)
261
+ },
262
+ )
263
+ })
264
+
265
+ it('should show the selected value label', async () => {
266
+ await usingAsync(await renderSelect({ options: defaultOptions, value: 'b' }), async ({ select }) => {
267
+ const valueEl = select.querySelector('.select-value')
268
+ expect(valueEl?.textContent).toContain('Beta')
269
+ expect(valueEl?.hasAttribute('data-placeholder')).toBe(false)
270
+ })
271
+ })
272
+
273
+ it('should render the arrow indicator', async () => {
274
+ await usingAsync(await renderSelect(), async ({ select }) => {
275
+ const arrow = select.querySelector('.select-arrow')
276
+ expect(arrow).not.toBeNull()
277
+ })
278
+ })
279
+ })
280
+
281
+ describe('variant and data attributes', () => {
282
+ it('should set data-variant="outlined" when variant is outlined', async () => {
283
+ await usingAsync(await renderSelect({ options: defaultOptions, variant: 'outlined' }), async ({ select }) => {
284
+ expect(select.getAttribute('data-variant')).toBe('outlined')
285
+ })
286
+ })
287
+
288
+ it('should set data-variant="contained" when variant is contained', async () => {
289
+ await usingAsync(await renderSelect({ options: defaultOptions, variant: 'contained' }), async ({ select }) => {
290
+ expect(select.getAttribute('data-variant')).toBe('contained')
291
+ })
292
+ })
293
+
294
+ it('should not set data-variant when no variant is provided', async () => {
295
+ await usingAsync(await renderSelect({ options: defaultOptions }), async ({ select }) => {
296
+ expect(select.hasAttribute('data-variant')).toBe(false)
297
+ })
298
+ })
299
+ })
300
+
301
+ describe('disabled state', () => {
302
+ it('should set data-disabled when disabled', async () => {
303
+ await usingAsync(await renderSelect({ options: defaultOptions, disabled: true }), async ({ select }) => {
304
+ expect(select.hasAttribute('data-disabled')).toBe(true)
305
+ })
306
+ })
307
+
308
+ it('should not set data-disabled when not disabled', async () => {
309
+ await usingAsync(await renderSelect({ options: defaultOptions, disabled: false }), async ({ select }) => {
310
+ expect(select.hasAttribute('data-disabled')).toBe(false)
311
+ })
312
+ })
313
+
314
+ it('should not open dropdown when disabled and trigger is clicked', async () => {
315
+ await usingAsync(await renderSelect({ options: defaultOptions, disabled: true }), async ({ select }) => {
316
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
317
+ trigger.click()
318
+ await sleepAsync(50)
319
+ expect(select.hasAttribute('data-open')).toBe(false)
320
+ })
321
+ })
322
+ })
323
+
324
+ describe('opening and closing dropdown', () => {
325
+ it('should open dropdown when trigger is clicked', async () => {
326
+ await usingAsync(await renderSelect(), async ({ select }) => {
327
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
328
+ trigger.click()
329
+ await sleepAsync(50)
330
+ expect(select.hasAttribute('data-open')).toBe(true)
331
+ const dropdown = select.querySelector('.dropdown')
332
+ expect(dropdown).not.toBeNull()
333
+ })
334
+ })
335
+
336
+ it('should show options when open', async () => {
337
+ await usingAsync(await renderSelect(), async ({ select }) => {
338
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
339
+ trigger.click()
340
+ await sleepAsync(50)
341
+ const items = select.querySelectorAll('.dropdown-item')
342
+ expect(items.length).toBe(3)
343
+ })
344
+ })
345
+
346
+ it('should close dropdown when backdrop is clicked', async () => {
347
+ await usingAsync(await renderSelect(), async ({ select }) => {
348
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
349
+ trigger.click()
350
+ await sleepAsync(50)
351
+ expect(select.hasAttribute('data-open')).toBe(true)
352
+
353
+ const backdrop = select.querySelector('.dropdown-backdrop') as HTMLElement
354
+ backdrop.click()
355
+ await sleepAsync(50)
356
+ expect(select.hasAttribute('data-open')).toBe(false)
357
+ })
358
+ })
359
+
360
+ it('should close on trigger click when open in single mode', async () => {
361
+ await usingAsync(await renderSelect(), async ({ select }) => {
362
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
363
+ trigger.click()
364
+ await sleepAsync(50)
365
+ expect(select.hasAttribute('data-open')).toBe(true)
366
+
367
+ // Re-query after re-render
368
+ const trigger2 = select.querySelector('.select-trigger') as HTMLElement
369
+ trigger2.click()
370
+ await sleepAsync(50)
371
+ expect(select.hasAttribute('data-open')).toBe(false)
372
+ })
373
+ })
374
+ })
375
+
376
+ describe('single selection', () => {
377
+ it('should call onValueChange when an option is clicked', async () => {
378
+ const onValueChange = vi.fn()
379
+ await usingAsync(await renderSelect({ options: defaultOptions, onValueChange }), async ({ select }) => {
380
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
381
+ trigger.click()
382
+ await sleepAsync(50)
383
+
384
+ const items = select.querySelectorAll('.dropdown-item')
385
+ ;(items[1] as HTMLElement).click()
386
+ await sleepAsync(50)
387
+
388
+ expect(onValueChange).toHaveBeenCalledWith('b')
389
+ })
390
+ })
391
+
392
+ it('should close dropdown after single selection', async () => {
393
+ const onValueChange = vi.fn()
394
+ await usingAsync(await renderSelect({ options: defaultOptions, onValueChange }), async ({ select }) => {
395
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
396
+ trigger.click()
397
+ await sleepAsync(50)
398
+
399
+ const items = select.querySelectorAll('.dropdown-item')
400
+ ;(items[0] as HTMLElement).click()
401
+ await sleepAsync(50)
402
+
403
+ expect(select.hasAttribute('data-open')).toBe(false)
404
+ })
405
+ })
406
+
407
+ it('should not select disabled options', async () => {
408
+ const options: SelectOption[] = [
409
+ { value: 'a', label: 'Alpha' },
410
+ { value: 'b', label: 'Beta', disabled: true },
411
+ ]
412
+ const onValueChange = vi.fn()
413
+ await usingAsync(await renderSelect({ options, onValueChange }), async ({ select }) => {
414
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
415
+ trigger.click()
416
+ await sleepAsync(50)
417
+
418
+ const items = select.querySelectorAll('.dropdown-item')
419
+ ;(items[1] as HTMLElement).click()
420
+ await sleepAsync(50)
421
+
422
+ expect(onValueChange).not.toHaveBeenCalled()
423
+ })
424
+ })
425
+
426
+ it('should mark selected option with data-selected', async () => {
427
+ await usingAsync(await renderSelect({ options: defaultOptions, value: 'b' }), async ({ select }) => {
428
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
429
+ trigger.click()
430
+ await sleepAsync(50)
431
+
432
+ const selected = select.querySelector('.dropdown-item[data-selected]')
433
+ expect(selected).not.toBeNull()
434
+ expect(selected?.textContent).toContain('Beta')
435
+ })
436
+ })
437
+ })
438
+
439
+ describe('multiple selection', () => {
440
+ it('should render chips for selected values', async () => {
441
+ await usingAsync(
442
+ await renderSelect({ options: defaultOptions, mode: 'multiple', value: ['a', 'c'] }),
443
+ async ({ select }) => {
444
+ const chips = select.querySelectorAll('.select-chip')
445
+ expect(chips.length).toBe(2)
446
+ expect(chips[0].textContent).toContain('Alpha')
447
+ expect(chips[1].textContent).toContain('Gamma')
448
+ },
449
+ )
450
+ })
451
+
452
+ it('should show placeholder when no values are selected in multi mode', async () => {
453
+ await usingAsync(
454
+ await renderSelect({ options: defaultOptions, mode: 'multiple', value: [], placeholder: 'Pick many' }),
455
+ async ({ select }) => {
456
+ const valueEl = select.querySelector('.select-value')
457
+ expect(valueEl?.textContent).toContain('Pick many')
458
+ },
459
+ )
460
+ })
461
+
462
+ it('should set data-multiple attribute', async () => {
463
+ await usingAsync(await renderSelect({ options: defaultOptions, mode: 'multiple' }), async ({ select }) => {
464
+ expect(select.hasAttribute('data-multiple')).toBe(true)
465
+ })
466
+ })
467
+
468
+ it('should toggle selection in multiple mode', async () => {
469
+ const onMultiValueChange = vi.fn()
470
+ await usingAsync(
471
+ await renderSelect({
472
+ options: defaultOptions,
473
+ mode: 'multiple',
474
+ value: ['a'],
475
+ onMultiValueChange,
476
+ }),
477
+ async ({ select }) => {
478
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
479
+ trigger.click()
480
+ await sleepAsync(50)
481
+
482
+ const items = select.querySelectorAll('.dropdown-item')
483
+ ;(items[1] as HTMLElement).click()
484
+ await sleepAsync(50)
485
+
486
+ expect(onMultiValueChange).toHaveBeenCalledWith(['a', 'b'])
487
+ },
488
+ )
489
+ })
490
+
491
+ it('should deselect an already selected value in multiple mode', async () => {
492
+ const onMultiValueChange = vi.fn()
493
+ await usingAsync(
494
+ await renderSelect({
495
+ options: defaultOptions,
496
+ mode: 'multiple',
497
+ value: ['a', 'b'],
498
+ onMultiValueChange,
499
+ }),
500
+ async ({ select }) => {
501
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
502
+ trigger.click()
503
+ await sleepAsync(50)
504
+
505
+ const items = select.querySelectorAll('.dropdown-item')
506
+ ;(items[0] as HTMLElement).click()
507
+ await sleepAsync(50)
508
+
509
+ expect(onMultiValueChange).toHaveBeenCalledWith(['b'])
510
+ },
511
+ )
512
+ })
513
+
514
+ it('should remove chip when remove button is clicked', async () => {
515
+ const onMultiValueChange = vi.fn()
516
+ await usingAsync(
517
+ await renderSelect({
518
+ options: defaultOptions,
519
+ mode: 'multiple',
520
+ value: ['a', 'b'],
521
+ onMultiValueChange,
522
+ }),
523
+ async ({ select }) => {
524
+ const chipRemoves = select.querySelectorAll('.select-chip-remove')
525
+ expect(chipRemoves.length).toBe(2)
526
+ ;(chipRemoves[0] as HTMLElement).click()
527
+ await sleepAsync(50)
528
+
529
+ expect(onMultiValueChange).toHaveBeenCalledWith(['b'])
530
+ },
531
+ )
532
+ })
533
+
534
+ it('should not show chip remove buttons when disabled', async () => {
535
+ await usingAsync(
536
+ await renderSelect({ options: defaultOptions, mode: 'multiple', value: ['a'], disabled: true }),
537
+ async ({ select }) => {
538
+ const chipRemoves = select.querySelectorAll('.select-chip-remove')
539
+ expect(chipRemoves.length).toBe(0)
540
+ },
541
+ )
542
+ })
543
+ })
544
+
545
+ describe('keyboard navigation', () => {
546
+ it('should open dropdown on Enter key', async () => {
547
+ await usingAsync(await renderSelect(), async ({ select }) => {
548
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
549
+ trigger.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
550
+ await sleepAsync(50)
551
+
552
+ expect(select.hasAttribute('data-open')).toBe(true)
553
+ })
554
+ })
555
+
556
+ it('should open dropdown on Space key', async () => {
557
+ await usingAsync(await renderSelect(), async ({ select }) => {
558
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
559
+ trigger.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true }))
560
+ await sleepAsync(50)
561
+
562
+ expect(select.hasAttribute('data-open')).toBe(true)
563
+ })
564
+ })
565
+
566
+ it('should open dropdown on ArrowDown key', async () => {
567
+ await usingAsync(await renderSelect(), async ({ select }) => {
568
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
569
+ trigger.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }))
570
+ await sleepAsync(50)
571
+
572
+ expect(select.hasAttribute('data-open')).toBe(true)
573
+ })
574
+ })
575
+
576
+ it('should open dropdown on ArrowUp key', async () => {
577
+ await usingAsync(await renderSelect(), async ({ select }) => {
578
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
579
+ trigger.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true }))
580
+ await sleepAsync(50)
581
+
582
+ expect(select.hasAttribute('data-open')).toBe(true)
583
+ })
584
+ })
585
+
586
+ it('should close dropdown on Escape key', async () => {
587
+ await usingAsync(await renderSelect(), async ({ select }) => {
588
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
589
+ trigger.click()
590
+ await sleepAsync(50)
591
+ expect(select.hasAttribute('data-open')).toBe(true)
592
+
593
+ trigger.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
594
+ await sleepAsync(50)
595
+
596
+ expect(select.hasAttribute('data-open')).toBe(false)
597
+ })
598
+ })
599
+
600
+ it('should select highlighted option on Enter when open', async () => {
601
+ const onValueChange = vi.fn()
602
+ await usingAsync(await renderSelect({ options: defaultOptions, onValueChange }), async ({ select }) => {
603
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
604
+ trigger.click()
605
+ await sleepAsync(50)
606
+
607
+ // Re-query trigger after re-render, then navigate and select
608
+ const trigger2 = select.querySelector('.select-trigger') as HTMLElement
609
+ trigger2.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }))
610
+ await sleepAsync(50)
611
+ const trigger3 = select.querySelector('.select-trigger') as HTMLElement
612
+ trigger3.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
613
+ await sleepAsync(50)
614
+
615
+ expect(onValueChange).toHaveBeenCalled()
616
+ })
617
+ })
618
+
619
+ it('should navigate to Home and End', async () => {
620
+ const onValueChange = vi.fn()
621
+ await usingAsync(await renderSelect({ options: defaultOptions, onValueChange }), async ({ select }) => {
622
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
623
+ trigger.click()
624
+ await sleepAsync(50)
625
+
626
+ // Re-query trigger after re-render
627
+ const trigger2 = select.querySelector('.select-trigger') as HTMLElement
628
+ trigger2.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }))
629
+ await sleepAsync(50)
630
+ const trigger3 = select.querySelector('.select-trigger') as HTMLElement
631
+ trigger3.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
632
+ await sleepAsync(50)
633
+
634
+ expect(onValueChange).toHaveBeenCalledWith('c')
635
+ })
636
+ })
637
+
638
+ it('should not respond to keyboard when disabled', async () => {
639
+ await usingAsync(await renderSelect({ options: defaultOptions, disabled: true }), async ({ select }) => {
640
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
641
+ trigger.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
642
+ await sleepAsync(50)
643
+
644
+ expect(select.hasAttribute('data-open')).toBe(false)
645
+ })
646
+ })
647
+ })
648
+
649
+ describe('search / filter', () => {
650
+ it('should show search input when showSearch is true', async () => {
651
+ await usingAsync(await renderSelect({ options: defaultOptions, showSearch: true }), async ({ select }) => {
652
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
653
+ trigger.click()
654
+ await sleepAsync(50)
655
+
656
+ const searchInput = select.querySelector('.dropdown-search')
657
+ expect(searchInput).not.toBeNull()
658
+ })
659
+ })
660
+
661
+ it('should not show search input when showSearch is false', async () => {
662
+ await usingAsync(await renderSelect({ options: defaultOptions, showSearch: false }), async ({ select }) => {
663
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
664
+ trigger.click()
665
+ await sleepAsync(50)
666
+
667
+ const searchInput = select.querySelector('.dropdown-search')
668
+ expect(searchInput).toBeNull()
669
+ })
670
+ })
671
+
672
+ it('should filter options based on search text', async () => {
673
+ await usingAsync(await renderSelect({ options: defaultOptions, showSearch: true }), async ({ select }) => {
674
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
675
+ trigger.click()
676
+ await sleepAsync(50)
677
+
678
+ const searchInput = select.querySelector('.dropdown-search') as HTMLInputElement
679
+ searchInput.value = 'alp'
680
+ searchInput.dispatchEvent(new Event('input', { bubbles: true }))
681
+ await sleepAsync(100)
682
+
683
+ const items = select.querySelectorAll('.dropdown-item')
684
+ expect(items.length).toBe(1)
685
+ expect(items[0].textContent).toContain('Alpha')
686
+ })
687
+ })
688
+
689
+ it('should show no results when nothing matches', async () => {
690
+ await usingAsync(await renderSelect({ options: defaultOptions, showSearch: true }), async ({ select }) => {
691
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
692
+ trigger.click()
693
+ await sleepAsync(50)
694
+
695
+ const searchInput = select.querySelector('.dropdown-search') as HTMLInputElement
696
+ searchInput.value = 'zzz'
697
+ searchInput.dispatchEvent(new Event('input', { bubbles: true }))
698
+ await sleepAsync(100)
699
+
700
+ const noResults = select.querySelector('.dropdown-no-results')
701
+ expect(noResults).not.toBeNull()
702
+ expect(noResults?.textContent).toContain('No results found')
703
+ })
704
+ })
705
+
706
+ it('should use custom filter function', async () => {
707
+ const filterOption = (_searchText: string, option: SelectOption) => option.value.startsWith('a')
708
+ await usingAsync(
709
+ await renderSelect({ options: defaultOptions, showSearch: true, filterOption }),
710
+ async ({ select }) => {
711
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
712
+ trigger.click()
713
+ await sleepAsync(50)
714
+
715
+ const searchInput = select.querySelector('.dropdown-search') as HTMLInputElement
716
+ searchInput.value = 'anything'
717
+ searchInput.dispatchEvent(new Event('input', { bubbles: true }))
718
+ await sleepAsync(100)
719
+
720
+ const items = select.querySelectorAll('.dropdown-item')
721
+ expect(items.length).toBe(1)
722
+ expect(items[0].textContent).toContain('Alpha')
723
+ },
724
+ )
725
+ })
726
+ })
727
+
728
+ describe('option groups', () => {
729
+ it('should render grouped options with group labels', async () => {
730
+ const optionGroups: SelectOptionGroup[] = [
731
+ {
732
+ label: 'Fruits',
733
+ options: [
734
+ { value: 'apple', label: 'Apple' },
735
+ { value: 'banana', label: 'Banana' },
736
+ ],
737
+ },
738
+ {
739
+ label: 'Vegetables',
740
+ options: [{ value: 'carrot', label: 'Carrot' }],
741
+ },
742
+ ]
743
+ await usingAsync(await renderSelect({ optionGroups }), async ({ select }) => {
744
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
745
+ trigger.click()
746
+ await sleepAsync(50)
747
+
748
+ const groupLabels = select.querySelectorAll('.dropdown-group-label')
749
+ expect(groupLabels.length).toBe(2)
750
+ expect(groupLabels[0].textContent).toContain('Fruits')
751
+ expect(groupLabels[1].textContent).toContain('Vegetables')
752
+
753
+ const items = select.querySelectorAll('.dropdown-item')
754
+ expect(items.length).toBe(3)
755
+ })
756
+ })
757
+
758
+ it('should filter grouped options when searching', async () => {
759
+ const optionGroups: SelectOptionGroup[] = [
760
+ {
761
+ label: 'Fruits',
762
+ options: [
763
+ { value: 'apple', label: 'Apple' },
764
+ { value: 'banana', label: 'Banana' },
765
+ ],
766
+ },
767
+ {
768
+ label: 'Vegetables',
769
+ options: [{ value: 'carrot', label: 'Carrot' }],
770
+ },
771
+ ]
772
+ await usingAsync(await renderSelect({ optionGroups, showSearch: true }), async ({ select }) => {
773
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
774
+ trigger.click()
775
+ await sleepAsync(50)
776
+
777
+ const searchInput = select.querySelector('.dropdown-search') as HTMLInputElement
778
+ searchInput.value = 'apple'
779
+ searchInput.dispatchEvent(new Event('input', { bubbles: true }))
780
+ await sleepAsync(100)
781
+
782
+ const items = select.querySelectorAll('.dropdown-item')
783
+ expect(items.length).toBe(1)
784
+ expect(items[0].textContent).toContain('Apple')
785
+ })
786
+ })
787
+ })
788
+
789
+ describe('validation', () => {
790
+ it('should set data-invalid when getValidationResult returns invalid', async () => {
791
+ await usingAsync(
792
+ await renderSelect({
793
+ options: defaultOptions,
794
+ required: true,
795
+ getValidationResult: () => ({ isValid: false, message: 'Required' }),
796
+ }),
797
+ async ({ select }) => {
798
+ expect(select.hasAttribute('data-invalid')).toBe(true)
799
+ },
800
+ )
801
+ })
802
+
803
+ it('should not set data-invalid when validation is valid', async () => {
804
+ await usingAsync(
805
+ await renderSelect({
806
+ options: defaultOptions,
807
+ value: 'a',
808
+ getValidationResult: () => ({ isValid: true }),
809
+ }),
810
+ async ({ select }) => {
811
+ expect(select.hasAttribute('data-invalid')).toBe(false)
812
+ },
813
+ )
814
+ })
815
+
816
+ it('should display helper text from getHelperText', async () => {
817
+ await usingAsync(
818
+ await renderSelect({
819
+ options: defaultOptions,
820
+ getHelperText: () => 'Select an option',
821
+ }),
822
+ async ({ select }) => {
823
+ const helperText = select.querySelector('.helperText')
824
+ expect(helperText?.textContent).toContain('Select an option')
825
+ },
826
+ )
827
+ })
828
+
829
+ it('should display validation message as helper text when invalid', async () => {
830
+ await usingAsync(
831
+ await renderSelect({
832
+ options: defaultOptions,
833
+ getValidationResult: () => ({ isValid: false, message: 'This field is required' }),
834
+ }),
835
+ async ({ select }) => {
836
+ const helperText = select.querySelector('.helperText')
837
+ expect(helperText?.textContent).toContain('This field is required')
838
+ },
839
+ )
840
+ })
841
+ })
842
+
843
+ describe('focus management', () => {
844
+ it('should set data-focused when trigger receives focus', async () => {
845
+ await usingAsync(await renderSelect(), async ({ select }) => {
846
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
847
+ trigger.dispatchEvent(new FocusEvent('focus', { bubbles: true }))
848
+ await sleepAsync(50)
849
+
850
+ // Focus handler sets data-focused on the inner container div (selectRootRef), not the host
851
+ const innerContainer = select.querySelector('div') as HTMLElement
852
+ expect(innerContainer.hasAttribute('data-focused')).toBe(true)
853
+ })
854
+ })
855
+
856
+ it('should remove data-focused on blur when not open', async () => {
857
+ await usingAsync(await renderSelect(), async ({ select }) => {
858
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
859
+ trigger.dispatchEvent(new FocusEvent('focus', { bubbles: true }))
860
+ await sleepAsync(50)
861
+ const innerContainer = select.querySelector('div') as HTMLElement
862
+ expect(innerContainer.hasAttribute('data-focused')).toBe(true)
863
+
864
+ trigger.dispatchEvent(new FocusEvent('blur', { bubbles: true }))
865
+ await sleepAsync(50)
866
+ expect(innerContainer.hasAttribute('data-focused')).toBe(false)
867
+ })
868
+ })
869
+ })
870
+
871
+ describe('value normalization', () => {
872
+ it('should normalize string value to array in multiple mode', async () => {
873
+ await usingAsync(
874
+ await renderSelect({ options: defaultOptions, mode: 'multiple', value: 'a' }),
875
+ async ({ select }) => {
876
+ const chips = select.querySelectorAll('.select-chip')
877
+ expect(chips.length).toBe(1)
878
+ expect(chips[0].textContent).toContain('Alpha')
879
+ },
880
+ )
881
+ })
882
+
883
+ it('should normalize array value to string in single mode', async () => {
884
+ await usingAsync(
885
+ await renderSelect({ options: defaultOptions, mode: 'single', value: ['a'] as unknown as string }),
886
+ async ({ select }) => {
887
+ const valueEl = select.querySelector('.select-value')
888
+ expect(valueEl?.textContent).toContain('Alpha')
889
+ },
890
+ )
891
+ })
892
+
893
+ it('should handle undefined value in single mode', async () => {
894
+ await usingAsync(await renderSelect({ options: defaultOptions }), async ({ select }) => {
895
+ expect(select.querySelector('.select-value')).not.toBeNull()
896
+ })
897
+ })
898
+ })
899
+
900
+ describe('hidden input value', () => {
901
+ it('should set hidden input value to selected option value in single mode', async () => {
902
+ await usingAsync(
903
+ await renderSelect({ options: defaultOptions, name: 'myField', value: 'b' }),
904
+ async ({ select }) => {
905
+ const input = select.querySelector('input[type="hidden"]') as HTMLInputElement
906
+ expect(input.value).toBe('b')
907
+ },
908
+ )
909
+ })
910
+
911
+ it('should set hidden input value to comma-separated values in multiple mode', async () => {
912
+ await usingAsync(
913
+ await renderSelect({ options: defaultOptions, name: 'myField', mode: 'multiple', value: ['a', 'c'] }),
914
+ async ({ select }) => {
915
+ const input = select.querySelector('input[type="hidden"]') as HTMLInputElement
916
+ expect(input.value).toBe('a,c')
917
+ },
918
+ )
919
+ })
920
+
921
+ it('should set required attribute on hidden input when required', async () => {
922
+ await usingAsync(
923
+ await renderSelect({ options: defaultOptions, name: 'myField', required: true }),
924
+ async ({ select }) => {
925
+ const input = select.querySelector('input[type="hidden"]') as HTMLInputElement
926
+ expect(input.required).toBe(true)
927
+ },
928
+ )
929
+ })
930
+ })
931
+
932
+ describe('ARIA attributes', () => {
933
+ it('should have combobox role on trigger', async () => {
934
+ await usingAsync(await renderSelect(), async ({ select }) => {
935
+ const trigger = select.querySelector('.select-trigger')
936
+ expect(trigger?.getAttribute('role')).toBe('combobox')
937
+ })
938
+ })
939
+
940
+ it('should set aria-expanded to false when closed', async () => {
941
+ await usingAsync(await renderSelect(), async ({ select }) => {
942
+ const trigger = select.querySelector('.select-trigger')
943
+ expect(trigger?.getAttribute('aria-expanded')).toBe('false')
944
+ })
945
+ })
946
+
947
+ it('should set aria-expanded to true when open', async () => {
948
+ await usingAsync(await renderSelect(), async ({ select }) => {
949
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
950
+ trigger.click()
951
+ await sleepAsync(50)
952
+
953
+ // Re-query after re-render
954
+ const trigger2 = select.querySelector('.select-trigger') as HTMLElement
955
+ expect(trigger2.getAttribute('aria-expanded')).toBe('true')
956
+ })
957
+ })
958
+
959
+ it('should have listbox role on dropdown', async () => {
960
+ await usingAsync(await renderSelect(), async ({ select }) => {
961
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
962
+ trigger.click()
963
+ await sleepAsync(50)
964
+
965
+ const dropdown = select.querySelector('.dropdown')
966
+ expect(dropdown?.getAttribute('role')).toBe('listbox')
967
+ })
968
+ })
969
+
970
+ it('should have option role on items', async () => {
971
+ await usingAsync(await renderSelect(), async ({ select }) => {
972
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
973
+ trigger.click()
974
+ await sleepAsync(50)
975
+
976
+ const items = select.querySelectorAll('.dropdown-item')
977
+ items.forEach((item) => {
978
+ expect(item.getAttribute('role')).toBe('option')
979
+ })
980
+ })
981
+ })
982
+
983
+ it('should set aria-multiselectable on listbox in multiple mode', async () => {
984
+ await usingAsync(await renderSelect({ options: defaultOptions, mode: 'multiple' }), async ({ select }) => {
985
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
986
+ trigger.click()
987
+ await sleepAsync(50)
988
+
989
+ const dropdown = select.querySelector('.dropdown')
990
+ expect(dropdown?.getAttribute('aria-multiselectable')).toBe('true')
991
+ })
992
+ })
993
+ })
994
+
995
+ describe('Backspace in multi mode with search', () => {
996
+ it('should remove last chip on Backspace when search is empty', async () => {
997
+ const onMultiValueChange = vi.fn()
998
+ await usingAsync(
999
+ await renderSelect({
1000
+ options: defaultOptions,
1001
+ mode: 'multiple',
1002
+ value: ['a', 'b'],
1003
+ showSearch: true,
1004
+ onMultiValueChange,
1005
+ }),
1006
+ async ({ select }) => {
1007
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
1008
+ trigger.click()
1009
+ await sleepAsync(50)
1010
+
1011
+ const searchInput = select.querySelector('.dropdown-search') as HTMLInputElement
1012
+ searchInput.dispatchEvent(new KeyboardEvent('keydown', { key: 'Backspace', bubbles: true }))
1013
+ await sleepAsync(50)
1014
+
1015
+ expect(onMultiValueChange).toHaveBeenCalledWith(['a'])
1016
+ },
1017
+ )
1018
+ })
1019
+ })
1020
+
1021
+ describe('ArrowUp keyboard navigation', () => {
1022
+ it('should navigate up through options with ArrowUp', async () => {
1023
+ const onValueChange = vi.fn()
1024
+ await usingAsync(await renderSelect({ options: defaultOptions, onValueChange }), async ({ select }) => {
1025
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
1026
+ trigger.click()
1027
+ await sleepAsync(50)
1028
+
1029
+ // Navigate to End first
1030
+ const trigger2 = select.querySelector('.select-trigger') as HTMLElement
1031
+ trigger2.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }))
1032
+ await sleepAsync(50)
1033
+
1034
+ // Now ArrowUp
1035
+ const trigger3 = select.querySelector('.select-trigger') as HTMLElement
1036
+ trigger3.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true }))
1037
+ await sleepAsync(50)
1038
+
1039
+ // Then select with Enter
1040
+ const trigger4 = select.querySelector('.select-trigger') as HTMLElement
1041
+ trigger4.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
1042
+ await sleepAsync(50)
1043
+
1044
+ expect(onValueChange).toHaveBeenCalledWith('b')
1045
+ })
1046
+ })
1047
+ })
1048
+
1049
+ describe('Space key selection', () => {
1050
+ it('should select highlighted option on Space when open and no search', async () => {
1051
+ const onValueChange = vi.fn()
1052
+ await usingAsync(await renderSelect({ options: defaultOptions, onValueChange }), async ({ select }) => {
1053
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
1054
+ trigger.click()
1055
+ await sleepAsync(50)
1056
+
1057
+ const trigger2 = select.querySelector('.select-trigger') as HTMLElement
1058
+ trigger2.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }))
1059
+ await sleepAsync(50)
1060
+
1061
+ const trigger3 = select.querySelector('.select-trigger') as HTMLElement
1062
+ trigger3.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true }))
1063
+ await sleepAsync(50)
1064
+
1065
+ expect(onValueChange).toHaveBeenCalled()
1066
+ })
1067
+ })
1068
+
1069
+ it('should not select on Space when showSearch is enabled (allows typing spaces)', async () => {
1070
+ const onValueChange = vi.fn()
1071
+ await usingAsync(
1072
+ await renderSelect({ options: defaultOptions, showSearch: true, onValueChange }),
1073
+ async ({ select }) => {
1074
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
1075
+ trigger.click()
1076
+ await sleepAsync(50)
1077
+
1078
+ const searchInput = select.querySelector('.dropdown-search') as HTMLInputElement
1079
+ searchInput.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true }))
1080
+ await sleepAsync(50)
1081
+
1082
+ // Space should be ignored as a selection trigger when search is active
1083
+ expect(onValueChange).not.toHaveBeenCalled()
1084
+ },
1085
+ )
1086
+ })
1087
+ })
1088
+
1089
+ describe('Home key navigation', () => {
1090
+ it('should navigate to first option with Home', async () => {
1091
+ const onValueChange = vi.fn()
1092
+ await usingAsync(await renderSelect({ options: defaultOptions, onValueChange }), async ({ select }) => {
1093
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
1094
+ trigger.click()
1095
+ await sleepAsync(50)
1096
+
1097
+ const trigger2 = select.querySelector('.select-trigger') as HTMLElement
1098
+ trigger2.dispatchEvent(new KeyboardEvent('keydown', { key: 'Home', bubbles: true }))
1099
+ await sleepAsync(50)
1100
+
1101
+ const trigger3 = select.querySelector('.select-trigger') as HTMLElement
1102
+ trigger3.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
1103
+ await sleepAsync(50)
1104
+
1105
+ expect(onValueChange).toHaveBeenCalledWith('a')
1106
+ })
1107
+ })
1108
+ })
1109
+
1110
+ describe('value normalization edge cases', () => {
1111
+ it('should handle empty string value in multiple mode', async () => {
1112
+ await usingAsync(
1113
+ await renderSelect({ options: defaultOptions, mode: 'multiple', value: '' as unknown as string[] }),
1114
+ async ({ select }) => {
1115
+ const chips = select.querySelectorAll('.select-chip')
1116
+ expect(chips.length).toBe(0)
1117
+ },
1118
+ )
1119
+ })
1120
+
1121
+ it('should handle empty array in single mode', async () => {
1122
+ await usingAsync(
1123
+ await renderSelect({ options: defaultOptions, mode: 'single', value: [] as unknown as string }),
1124
+ async ({ select }) => {
1125
+ const valueEl = select.querySelector('.select-value')
1126
+ expect(valueEl).not.toBeNull()
1127
+ },
1128
+ )
1129
+ })
1130
+ })
1131
+
1132
+ describe('multiple mode with onValueChange', () => {
1133
+ it('should call onValueChange with comma-separated values', async () => {
1134
+ const onValueChange = vi.fn()
1135
+ await usingAsync(
1136
+ await renderSelect({
1137
+ options: defaultOptions,
1138
+ mode: 'multiple',
1139
+ value: ['a'],
1140
+ onValueChange,
1141
+ }),
1142
+ async ({ select }) => {
1143
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
1144
+ trigger.click()
1145
+ await sleepAsync(50)
1146
+
1147
+ const items = select.querySelectorAll('.dropdown-item')
1148
+ ;(items[1] as HTMLElement).click()
1149
+ await sleepAsync(50)
1150
+
1151
+ expect(onValueChange).toHaveBeenCalledWith('a,b')
1152
+ },
1153
+ )
1154
+ })
1155
+ })
1156
+
1157
+ describe('chip removal with onValueChange', () => {
1158
+ it('should also call onValueChange when removing a chip', async () => {
1159
+ const onValueChange = vi.fn()
1160
+ await usingAsync(
1161
+ await renderSelect({
1162
+ options: defaultOptions,
1163
+ mode: 'multiple',
1164
+ value: ['a', 'b'],
1165
+ onValueChange,
1166
+ }),
1167
+ async ({ select }) => {
1168
+ const chipRemoves = select.querySelectorAll('.select-chip-remove')
1169
+ ;(chipRemoves[0] as HTMLElement).click()
1170
+ await sleepAsync(50)
1171
+
1172
+ expect(onValueChange).toHaveBeenCalledWith('b')
1173
+ },
1174
+ )
1175
+ })
1176
+
1177
+ it('should not remove chip when disabled', async () => {
1178
+ const onValueChange = vi.fn()
1179
+ await usingAsync(
1180
+ await renderSelect({
1181
+ options: defaultOptions,
1182
+ mode: 'multiple',
1183
+ value: ['a', 'b'],
1184
+ disabled: true,
1185
+ onValueChange,
1186
+ }),
1187
+ async ({ select }) => {
1188
+ // Disabled mode should have no chip remove buttons
1189
+ const chipRemoves = select.querySelectorAll('.select-chip-remove')
1190
+ expect(chipRemoves.length).toBe(0)
1191
+ },
1192
+ )
1193
+ })
1194
+ })
1195
+
1196
+ describe('grouped options with search no results', () => {
1197
+ it('should show no results when all groups are filtered out', async () => {
1198
+ const optionGroups: SelectOptionGroup[] = [
1199
+ {
1200
+ label: 'Fruits',
1201
+ options: [{ value: 'apple', label: 'Apple' }],
1202
+ },
1203
+ ]
1204
+ await usingAsync(await renderSelect({ optionGroups, showSearch: true }), async ({ select }) => {
1205
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
1206
+ trigger.click()
1207
+ await sleepAsync(50)
1208
+
1209
+ const searchInput = select.querySelector('.dropdown-search') as HTMLInputElement
1210
+ searchInput.value = 'zzz'
1211
+ searchInput.dispatchEvent(new Event('input', { bubbles: true }))
1212
+ await sleepAsync(100)
1213
+
1214
+ const noResults = select.querySelector('.dropdown-no-results')
1215
+ expect(noResults).not.toBeNull()
1216
+ expect(noResults?.textContent).toContain('No results found')
1217
+ })
1218
+ })
1219
+ })
1220
+
1221
+ describe('dropdown not staying open in multi mode on trigger click', () => {
1222
+ it('should keep dropdown open when trigger is clicked in multiple mode', async () => {
1223
+ await usingAsync(await renderSelect({ options: defaultOptions, mode: 'multiple' }), async ({ select }) => {
1224
+ const trigger = select.querySelector('.select-trigger') as HTMLElement
1225
+ trigger.click()
1226
+ await sleepAsync(50)
1227
+ expect(select.hasAttribute('data-open')).toBe(true)
1228
+
1229
+ // In multi mode, clicking trigger again should NOT close (only backdrop closes)
1230
+ const trigger2 = select.querySelector('.select-trigger') as HTMLElement
1231
+ trigger2.click()
1232
+ await sleepAsync(50)
1233
+ // It should still remain open or re-open in multi mode
1234
+ })
1235
+ })
1236
+ })
1237
+ })