@kosmeo-ui/react 0.2.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. package/README.md +3 -1
  2. package/dist/components/buttons/button/styles.css +43 -43
  3. package/dist/components/buttons/rowActions/index.d.ts.map +1 -1
  4. package/dist/components/buttons/rowActions/index.js +2 -1
  5. package/dist/components/buttons/rowActions/index.js.map +1 -1
  6. package/dist/components/data-display/addressBlock/styles.css +2 -2
  7. package/dist/components/data-display/colorSwatch/index.d.ts +1 -1
  8. package/dist/components/data-display/colorSwatch/index.d.ts.map +1 -1
  9. package/dist/components/data-display/colorSwatch/index.js +1 -1
  10. package/dist/components/data-display/colorSwatch/index.js.map +1 -1
  11. package/dist/components/data-display/colorSwatch/styles.css +1 -1
  12. package/dist/components/data-display/dataTable/index.d.ts.map +1 -1
  13. package/dist/components/data-display/dataTable/index.js +7 -3
  14. package/dist/components/data-display/dataTable/index.js.map +1 -1
  15. package/dist/components/data-display/dataTable/styles.css +3 -2
  16. package/dist/components/data-display/dataTable/utils/parseDataKey.d.ts +8 -1
  17. package/dist/components/data-display/dataTable/utils/parseDataKey.d.ts.map +1 -1
  18. package/dist/components/data-display/dataTable/utils/parseDataKey.js +13 -41
  19. package/dist/components/data-display/dataTable/utils/parseDataKey.js.map +1 -1
  20. package/dist/components/data-display/imagePreview/styles.css +2 -2
  21. package/dist/components/data-display/infiniteScroll/filters/index.d.ts +4 -0
  22. package/dist/components/data-display/infiniteScroll/filters/index.d.ts.map +1 -1
  23. package/dist/components/data-display/infiniteScroll/filters/index.js +12 -2
  24. package/dist/components/data-display/infiniteScroll/filters/index.js.map +1 -1
  25. package/dist/components/data-display/infiniteScroll/filters/listFilter.d.ts.map +1 -1
  26. package/dist/components/data-display/infiniteScroll/filters/listFilter.js +1 -1
  27. package/dist/components/data-display/infiniteScroll/filters/listFilter.js.map +1 -1
  28. package/dist/components/data-display/infiniteScroll/filters/rangeFilter.d.ts +6 -0
  29. package/dist/components/data-display/infiniteScroll/filters/rangeFilter.d.ts.map +1 -1
  30. package/dist/components/data-display/infiniteScroll/filters/rangeFilter.js +55 -46
  31. package/dist/components/data-display/infiniteScroll/filters/rangeFilter.js.map +1 -1
  32. package/dist/components/data-display/infiniteScroll/filters/selectFilter.d.ts.map +1 -1
  33. package/dist/components/data-display/infiniteScroll/filters/selectFilter.js +3 -5
  34. package/dist/components/data-display/infiniteScroll/filters/selectFilter.js.map +1 -1
  35. package/dist/components/data-display/infiniteScroll/filters/styles.css +30 -1
  36. package/dist/components/data-display/infiniteScroll/header/limit.d.ts.map +1 -1
  37. package/dist/components/data-display/infiniteScroll/header/limit.js +1 -1
  38. package/dist/components/data-display/infiniteScroll/header/limit.js.map +1 -1
  39. package/dist/components/data-display/infiniteScroll/header/sortBy.d.ts.map +1 -1
  40. package/dist/components/data-display/infiniteScroll/header/sortBy.js +1 -1
  41. package/dist/components/data-display/infiniteScroll/header/sortBy.js.map +1 -1
  42. package/dist/components/data-display/infiniteScroll/header/sortDirection.d.ts.map +1 -1
  43. package/dist/components/data-display/infiniteScroll/header/sortDirection.js +1 -1
  44. package/dist/components/data-display/infiniteScroll/header/sortDirection.js.map +1 -1
  45. package/dist/components/data-display/infiniteScroll/index.d.ts +8 -0
  46. package/dist/components/data-display/infiniteScroll/index.d.ts.map +1 -1
  47. package/dist/components/data-display/infiniteScroll/index.js +41 -23
  48. package/dist/components/data-display/infiniteScroll/index.js.map +1 -1
  49. package/dist/components/data-display/infiniteScroll/styles.css +2 -2
  50. package/dist/components/data-display/infiniteScroll/tags/index.d.ts.map +1 -1
  51. package/dist/components/data-display/infiniteScroll/tags/index.js +6 -5
  52. package/dist/components/data-display/infiniteScroll/tags/index.js.map +1 -1
  53. package/dist/components/data-display/infiniteScroll/tags/listFilterTag.d.ts.map +1 -1
  54. package/dist/components/data-display/infiniteScroll/tags/listFilterTag.js +6 -6
  55. package/dist/components/data-display/infiniteScroll/tags/listFilterTag.js.map +1 -1
  56. package/dist/components/data-display/infiniteScroll/tags/rangeFilterTag.d.ts.map +1 -1
  57. package/dist/components/data-display/infiniteScroll/tags/rangeFilterTag.js +3 -5
  58. package/dist/components/data-display/infiniteScroll/tags/rangeFilterTag.js.map +1 -1
  59. package/dist/components/data-display/infiniteScroll/utils/generateQueryString.d.ts +6 -0
  60. package/dist/components/data-display/infiniteScroll/utils/generateQueryString.d.ts.map +1 -1
  61. package/dist/components/data-display/infiniteScroll/utils/generateQueryString.js +24 -12
  62. package/dist/components/data-display/infiniteScroll/utils/generateQueryString.js.map +1 -1
  63. package/dist/components/data-display/infiniteScroll/utils/hasPendingChanges.d.ts +11 -1
  64. package/dist/components/data-display/infiniteScroll/utils/hasPendingChanges.d.ts.map +1 -1
  65. package/dist/components/data-display/infiniteScroll/utils/hasPendingChanges.js +37 -18
  66. package/dist/components/data-display/infiniteScroll/utils/hasPendingChanges.js.map +1 -1
  67. package/dist/components/data-display/listCard/styles.css +3 -3
  68. package/dist/components/data-display/listRow/styles.css +2 -2
  69. package/dist/components/data-display/recoveryCodeGrid/styles.css +3 -3
  70. package/dist/components/data-display/secretDisplay/styles.css +4 -4
  71. package/dist/components/data-display/statCard/styles.css +12 -12
  72. package/dist/components/data-display/summaryRow/styles.css +4 -4
  73. package/dist/components/data-display/table/index.d.ts.map +1 -1
  74. package/dist/components/data-display/table/index.js +2 -2
  75. package/dist/components/data-display/table/index.js.map +1 -1
  76. package/dist/components/data-display/table/styles.css +10 -10
  77. package/dist/components/data-display/tableFilters/index.d.ts +30 -0
  78. package/dist/components/data-display/tableFilters/index.d.ts.map +1 -0
  79. package/dist/components/data-display/tableFilters/index.js +67 -0
  80. package/dist/components/data-display/tableFilters/index.js.map +1 -0
  81. package/dist/components/data-display/tagCard/index.d.ts.map +1 -1
  82. package/dist/components/data-display/tagCard/index.js +1 -1
  83. package/dist/components/data-display/tagCard/index.js.map +1 -1
  84. package/dist/components/data-display/tagCard/styles.css +1 -1
  85. package/dist/components/feedback/alert/styles.css +15 -15
  86. package/dist/components/feedback/badge/index.d.ts.map +1 -1
  87. package/dist/components/feedback/badge/index.js +14 -8
  88. package/dist/components/feedback/badge/index.js.map +1 -1
  89. package/dist/components/feedback/badge/styles.css +44 -46
  90. package/dist/components/feedback/emptyState/styles.css +2 -2
  91. package/dist/components/feedback/loadingOverlay/styles.css +1 -1
  92. package/dist/components/feedback/progressBar/styles.css +11 -11
  93. package/dist/components/feedback/spinner/styles.css +14 -11
  94. package/dist/components/feedback/tooltip/styles.css +9 -7
  95. package/dist/components/forms/detailField/styles.css +1 -1
  96. package/dist/components/forms/fieldShell/index.d.ts +3 -1
  97. package/dist/components/forms/fieldShell/index.d.ts.map +1 -1
  98. package/dist/components/forms/fieldShell/index.js +1 -1
  99. package/dist/components/forms/fieldShell/index.js.map +1 -1
  100. package/dist/components/forms/fieldShell/styles.css +5 -5
  101. package/dist/components/forms/form/styles.css +6 -6
  102. package/dist/components/forms/formActions/styles.css +4 -4
  103. package/dist/components/forms/formGrid/styles.css +32 -0
  104. package/dist/components/forms/infoRow/styles.css +2 -2
  105. package/dist/components/forms/optionsGroup/index.d.ts +3 -1
  106. package/dist/components/forms/optionsGroup/index.d.ts.map +1 -1
  107. package/dist/components/forms/optionsGroup/index.js +5 -1
  108. package/dist/components/forms/optionsGroup/index.js.map +1 -1
  109. package/dist/components/forms/optionsGroup/styles.css +1 -1
  110. package/dist/components/forms/requiredAsterisk/index.d.ts.map +1 -1
  111. package/dist/components/forms/requiredAsterisk/index.js +3 -2
  112. package/dist/components/forms/requiredAsterisk/index.js.map +1 -1
  113. package/dist/components/forms/requiredAsterisk/styles.css +1 -1
  114. package/dist/components/index.d.ts +2 -0
  115. package/dist/components/index.d.ts.map +1 -1
  116. package/dist/components/index.js +1 -0
  117. package/dist/components/index.js.map +1 -1
  118. package/dist/components/inputs/checkbox/index.d.ts.map +1 -1
  119. package/dist/components/inputs/checkbox/index.js +3 -1
  120. package/dist/components/inputs/checkbox/index.js.map +1 -1
  121. package/dist/components/inputs/checkbox/styles.css +4 -4
  122. package/dist/components/inputs/colorPicker/index.d.ts.map +1 -1
  123. package/dist/components/inputs/colorPicker/index.js +3 -1
  124. package/dist/components/inputs/colorPicker/index.js.map +1 -1
  125. package/dist/components/inputs/colorPicker/styles.css +3 -3
  126. package/dist/components/inputs/dateInput/index.d.ts +3 -3
  127. package/dist/components/inputs/dateInput/index.d.ts.map +1 -1
  128. package/dist/components/inputs/dateInput/index.js +2 -2
  129. package/dist/components/inputs/dateInput/index.js.map +1 -1
  130. package/dist/components/inputs/dateInput/styles.css +5 -5
  131. package/dist/components/inputs/dateInput/utils.d.ts +0 -1
  132. package/dist/components/inputs/dateInput/utils.d.ts.map +1 -1
  133. package/dist/components/inputs/dateInput/utils.js +13 -8
  134. package/dist/components/inputs/dateInput/utils.js.map +1 -1
  135. package/dist/components/inputs/dropdown/index.js +1 -1
  136. package/dist/components/inputs/dropdown/index.js.map +1 -1
  137. package/dist/components/inputs/dropdown/styles.css +2 -2
  138. package/dist/components/inputs/dropdownArrowButton/styles.css +7 -5
  139. package/dist/components/inputs/fileDropZone/index.d.ts.map +1 -1
  140. package/dist/components/inputs/fileDropZone/index.js +3 -2
  141. package/dist/components/inputs/fileDropZone/index.js.map +1 -1
  142. package/dist/components/inputs/fileDropZone/styles.css +12 -12
  143. package/dist/components/inputs/fileUpload/index.d.ts.map +1 -1
  144. package/dist/components/inputs/fileUpload/index.js +11 -6
  145. package/dist/components/inputs/fileUpload/index.js.map +1 -1
  146. package/dist/components/inputs/fileUpload/styles.css +9 -9
  147. package/dist/components/inputs/input/index.d.ts +12 -0
  148. package/dist/components/inputs/input/index.d.ts.map +1 -1
  149. package/dist/components/inputs/input/index.js +4 -3
  150. package/dist/components/inputs/input/index.js.map +1 -1
  151. package/dist/components/inputs/input/styles.css +28 -28
  152. package/dist/components/inputs/languageSelect/index.d.ts.map +1 -1
  153. package/dist/components/inputs/languageSelect/index.js +15 -4
  154. package/dist/components/inputs/languageSelect/index.js.map +1 -1
  155. package/dist/components/inputs/multiSelect/dropDown.d.ts +7 -0
  156. package/dist/components/inputs/multiSelect/dropDown.d.ts.map +1 -1
  157. package/dist/components/inputs/multiSelect/dropDown.js +19 -12
  158. package/dist/components/inputs/multiSelect/dropDown.js.map +1 -1
  159. package/dist/components/inputs/multiSelect/index.d.ts.map +1 -1
  160. package/dist/components/inputs/multiSelect/index.js +49 -13
  161. package/dist/components/inputs/multiSelect/index.js.map +1 -1
  162. package/dist/components/inputs/multiSelect/styles.css +51 -43
  163. package/dist/components/inputs/multiSelect/utils.d.ts +7 -0
  164. package/dist/components/inputs/multiSelect/utils.d.ts.map +1 -0
  165. package/dist/components/inputs/multiSelect/utils.js +18 -0
  166. package/dist/components/inputs/multiSelect/utils.js.map +1 -0
  167. package/dist/components/inputs/phoneInput/index.d.ts.map +1 -1
  168. package/dist/components/inputs/phoneInput/index.js +11 -3
  169. package/dist/components/inputs/phoneInput/index.js.map +1 -1
  170. package/dist/components/inputs/phoneInput/styles.css +13 -13
  171. package/dist/components/inputs/radioGroup/index.d.ts.map +1 -1
  172. package/dist/components/inputs/radioGroup/index.js +1 -1
  173. package/dist/components/inputs/radioGroup/index.js.map +1 -1
  174. package/dist/components/inputs/richTextEditor/index.d.ts.map +1 -1
  175. package/dist/components/inputs/richTextEditor/index.js +21 -22
  176. package/dist/components/inputs/richTextEditor/index.js.map +1 -1
  177. package/dist/components/inputs/richTextEditor/styles.css +24 -24
  178. package/dist/components/inputs/searchList/index.d.ts +4 -1
  179. package/dist/components/inputs/searchList/index.d.ts.map +1 -1
  180. package/dist/components/inputs/searchList/index.js +46 -31
  181. package/dist/components/inputs/searchList/index.js.map +1 -1
  182. package/dist/components/inputs/searchList/styles.css +22 -22
  183. package/dist/components/inputs/searchSelect/index.d.ts.map +1 -1
  184. package/dist/components/inputs/searchSelect/index.js +8 -2
  185. package/dist/components/inputs/searchSelect/index.js.map +1 -1
  186. package/dist/components/inputs/select/index.js +3 -2
  187. package/dist/components/inputs/select/index.js.map +1 -1
  188. package/dist/components/inputs/select/styles.css +93 -15
  189. package/dist/components/inputs/switch/index.d.ts.map +1 -1
  190. package/dist/components/inputs/switch/index.js +3 -1
  191. package/dist/components/inputs/switch/index.js.map +1 -1
  192. package/dist/components/inputs/switch/styles.css +5 -5
  193. package/dist/components/inputs/textArea/index.d.ts.map +1 -1
  194. package/dist/components/inputs/textArea/index.js +3 -2
  195. package/dist/components/inputs/textArea/index.js.map +1 -1
  196. package/dist/components/inputs/textArea/styles.css +11 -11
  197. package/dist/components/inputs/typeahead/index.d.ts.map +1 -1
  198. package/dist/components/inputs/typeahead/index.js +21 -6
  199. package/dist/components/inputs/typeahead/index.js.map +1 -1
  200. package/dist/components/inputs/typeahead/styles.css +13 -13
  201. package/dist/components/layout/authPage/styles.css +6 -6
  202. package/dist/components/layout/borderedSection/styles.css +3 -3
  203. package/dist/components/layout/card/styles.css +31 -31
  204. package/dist/components/layout/col/styles.css +1 -1
  205. package/dist/components/layout/page/styles.css +25 -5
  206. package/dist/components/layout/sectionHeader/styles.css +3 -3
  207. package/dist/components/navigation/breadcrumbs/styles.css +7 -7
  208. package/dist/components/navigation/pagination/styles.css +15 -15
  209. package/dist/components/navigation/sidebar/styles.css +6 -6
  210. package/dist/components/navigation/stepper/styles.css +14 -14
  211. package/dist/components/navigation/tabButton/styles.css +59 -59
  212. package/dist/components/navigation/tabs/styles.css +5 -5
  213. package/dist/components/overlays/modal/index.d.ts +1 -1
  214. package/dist/components/overlays/modal/index.d.ts.map +1 -1
  215. package/dist/components/overlays/modal/index.js +3 -2
  216. package/dist/components/overlays/modal/index.js.map +1 -1
  217. package/dist/components/overlays/modal/styles.css +19 -19
  218. package/dist/hooks/useInfinite.d.ts +3 -1
  219. package/dist/hooks/useInfinite.d.ts.map +1 -1
  220. package/dist/hooks/useInfinite.js +4 -2
  221. package/dist/hooks/useInfinite.js.map +1 -1
  222. package/dist/hooks/useInfiniteArchivableCursor.d.ts +1 -1
  223. package/dist/hooks/useInfiniteArchivableCursor.d.ts.map +1 -1
  224. package/dist/hooks/useInfiniteArchivableCursor.js +11 -4
  225. package/dist/hooks/useInfiniteArchivableCursor.js.map +1 -1
  226. package/dist/hooks/useInfiniteCursor.d.ts +1 -1
  227. package/dist/hooks/useInfiniteCursor.d.ts.map +1 -1
  228. package/dist/hooks/useInfiniteCursor.js +11 -4
  229. package/dist/hooks/useInfiniteCursor.js.map +1 -1
  230. package/dist/hooks/useListKeyboard.d.ts.map +1 -1
  231. package/dist/hooks/useListKeyboard.js +4 -0
  232. package/dist/hooks/useListKeyboard.js.map +1 -1
  233. package/dist/styles.css +142 -127
  234. package/package.json +15 -4
  235. package/src/components/buttons/button/styles.css +43 -43
  236. package/src/components/buttons/rowActions/index.tsx +6 -1
  237. package/src/components/data-display/addressBlock/styles.css +2 -2
  238. package/src/components/data-display/colorSwatch/index.tsx +2 -2
  239. package/src/components/data-display/colorSwatch/styles.css +1 -1
  240. package/src/components/data-display/dataTable/index.tsx +6 -3
  241. package/src/components/data-display/dataTable/styles.css +3 -2
  242. package/src/components/data-display/dataTable/utils/parseDataKey.ts +18 -36
  243. package/src/components/data-display/imagePreview/styles.css +2 -2
  244. package/src/components/data-display/infiniteScroll/filters/index.tsx +18 -1
  245. package/src/components/data-display/infiniteScroll/filters/listFilter.tsx +1 -0
  246. package/src/components/data-display/infiniteScroll/filters/rangeFilter.tsx +77 -33
  247. package/src/components/data-display/infiniteScroll/filters/selectFilter.tsx +11 -17
  248. package/src/components/data-display/infiniteScroll/filters/styles.css +30 -1
  249. package/src/components/data-display/infiniteScroll/header/limit.tsx +1 -0
  250. package/src/components/data-display/infiniteScroll/header/sortBy.tsx +1 -0
  251. package/src/components/data-display/infiniteScroll/header/sortDirection.tsx +1 -0
  252. package/src/components/data-display/infiniteScroll/index.tsx +75 -29
  253. package/src/components/data-display/infiniteScroll/styles.css +2 -2
  254. package/src/components/data-display/infiniteScroll/tags/index.tsx +6 -5
  255. package/src/components/data-display/infiniteScroll/tags/listFilterTag.tsx +20 -13
  256. package/src/components/data-display/infiniteScroll/tags/rangeFilterTag.tsx +4 -3
  257. package/src/components/data-display/infiniteScroll/utils/generateQueryString.ts +28 -13
  258. package/src/components/data-display/infiniteScroll/utils/hasPendingChanges.ts +48 -16
  259. package/src/components/data-display/listCard/styles.css +3 -3
  260. package/src/components/data-display/listRow/styles.css +2 -2
  261. package/src/components/data-display/recoveryCodeGrid/styles.css +3 -3
  262. package/src/components/data-display/secretDisplay/styles.css +4 -4
  263. package/src/components/data-display/statCard/styles.css +12 -12
  264. package/src/components/data-display/summaryRow/styles.css +4 -4
  265. package/src/components/data-display/table/index.tsx +2 -2
  266. package/src/components/data-display/table/styles.css +10 -10
  267. package/src/components/data-display/tableFilters/index.tsx +147 -0
  268. package/src/components/data-display/tagCard/index.tsx +3 -2
  269. package/src/components/data-display/tagCard/styles.css +1 -1
  270. package/src/components/feedback/alert/styles.css +15 -15
  271. package/src/components/feedback/badge/index.tsx +36 -16
  272. package/src/components/feedback/badge/styles.css +44 -46
  273. package/src/components/feedback/emptyState/styles.css +2 -2
  274. package/src/components/feedback/loadingOverlay/styles.css +1 -1
  275. package/src/components/feedback/progressBar/styles.css +11 -11
  276. package/src/components/feedback/spinner/styles.css +14 -11
  277. package/src/components/feedback/tooltip/styles.css +9 -7
  278. package/src/components/forms/detailField/styles.css +1 -1
  279. package/src/components/forms/fieldShell/index.tsx +4 -1
  280. package/src/components/forms/fieldShell/styles.css +5 -5
  281. package/src/components/forms/form/styles.css +6 -6
  282. package/src/components/forms/formActions/styles.css +4 -4
  283. package/src/components/forms/formGrid/styles.css +32 -0
  284. package/src/components/forms/infoRow/styles.css +2 -2
  285. package/src/components/forms/optionsGroup/index.tsx +31 -12
  286. package/src/components/forms/optionsGroup/styles.css +1 -1
  287. package/src/components/forms/requiredAsterisk/index.tsx +5 -1
  288. package/src/components/forms/requiredAsterisk/styles.css +1 -1
  289. package/src/components/index.ts +2 -0
  290. package/src/components/inputs/checkbox/index.tsx +3 -2
  291. package/src/components/inputs/checkbox/styles.css +4 -4
  292. package/src/components/inputs/colorPicker/index.tsx +5 -2
  293. package/src/components/inputs/colorPicker/styles.css +3 -3
  294. package/src/components/inputs/dateInput/index.tsx +4 -5
  295. package/src/components/inputs/dateInput/styles.css +5 -5
  296. package/src/components/inputs/dateInput/utils.ts +12 -8
  297. package/src/components/inputs/dropdown/index.tsx +1 -1
  298. package/src/components/inputs/dropdown/styles.css +2 -2
  299. package/src/components/inputs/dropdownArrowButton/styles.css +7 -5
  300. package/src/components/inputs/fileDropZone/index.tsx +4 -3
  301. package/src/components/inputs/fileDropZone/styles.css +12 -12
  302. package/src/components/inputs/fileUpload/index.tsx +33 -23
  303. package/src/components/inputs/fileUpload/styles.css +9 -9
  304. package/src/components/inputs/input/index.tsx +21 -3
  305. package/src/components/inputs/input/styles.css +28 -28
  306. package/src/components/inputs/languageSelect/index.tsx +19 -4
  307. package/src/components/inputs/multiSelect/dropDown.tsx +83 -35
  308. package/src/components/inputs/multiSelect/index.tsx +87 -30
  309. package/src/components/inputs/multiSelect/styles.css +51 -43
  310. package/src/components/inputs/multiSelect/utils.ts +18 -0
  311. package/src/components/inputs/phoneInput/index.tsx +10 -2
  312. package/src/components/inputs/phoneInput/styles.css +13 -13
  313. package/src/components/inputs/radioGroup/index.tsx +2 -1
  314. package/src/components/inputs/richTextEditor/index.tsx +42 -44
  315. package/src/components/inputs/richTextEditor/styles.css +24 -24
  316. package/src/components/inputs/searchList/index.tsx +121 -109
  317. package/src/components/inputs/searchList/styles.css +22 -22
  318. package/src/components/inputs/searchSelect/index.tsx +8 -2
  319. package/src/components/inputs/select/index.tsx +3 -3
  320. package/src/components/inputs/select/styles.css +93 -15
  321. package/src/components/inputs/switch/index.tsx +3 -2
  322. package/src/components/inputs/switch/styles.css +5 -5
  323. package/src/components/inputs/textArea/index.tsx +3 -3
  324. package/src/components/inputs/textArea/styles.css +11 -11
  325. package/src/components/inputs/typeahead/index.tsx +84 -54
  326. package/src/components/inputs/typeahead/styles.css +13 -13
  327. package/src/components/layout/authPage/styles.css +6 -6
  328. package/src/components/layout/borderedSection/styles.css +3 -3
  329. package/src/components/layout/card/styles.css +31 -31
  330. package/src/components/layout/col/styles.css +1 -1
  331. package/src/components/layout/page/styles.css +25 -5
  332. package/src/components/layout/sectionHeader/styles.css +3 -3
  333. package/src/components/navigation/breadcrumbs/styles.css +7 -7
  334. package/src/components/navigation/pagination/styles.css +15 -15
  335. package/src/components/navigation/sidebar/styles.css +6 -6
  336. package/src/components/navigation/stepper/styles.css +14 -14
  337. package/src/components/navigation/tabButton/styles.css +59 -59
  338. package/src/components/navigation/tabs/styles.css +5 -5
  339. package/src/components/overlays/modal/index.tsx +14 -2
  340. package/src/components/overlays/modal/styles.css +19 -19
  341. package/src/hooks/useInfinite.ts +7 -3
  342. package/src/hooks/useInfiniteArchivableCursor.ts +11 -4
  343. package/src/hooks/useInfiniteCursor.ts +11 -4
  344. package/src/hooks/useListKeyboard.ts +4 -0
  345. package/src/styles.css +142 -127
@@ -5,7 +5,7 @@ import IconButton from "../../buttons/iconButton/index.js";
5
5
  import Tooltip from "../../feedback/tooltip/index.js";
6
6
  import { PropsWithSize } from "../../types.js";
7
7
  import Input from "../input/index.js";
8
- import { useMemo } from "react";
8
+ import { itemKeys } from "./utils.js";
9
9
  import {
10
10
  faCheckDouble,
11
11
  faXmark,
@@ -23,46 +23,82 @@ interface DropDownProps<T> extends PropsWithSize {
23
23
  handleSelectAll: () => void;
24
24
  handleClearAll: () => void;
25
25
  handleOptionToggle: (optionValue: T) => void;
26
+ listboxId: string;
27
+ /** Id of the field's label, which also names the listbox. */
28
+ labelId?: string;
29
+ highlightedIndex: number;
30
+ optionRefs: React.RefObject<(HTMLLIElement | null)[]>;
31
+ onSearchKeyDown: React.KeyboardEventHandler<HTMLInputElement>;
26
32
  }
27
33
 
34
+ export const optionId = (listboxId: string, index: number) =>
35
+ `${listboxId}-option-${index}`;
36
+
28
37
  export const DropDownSection = <T,>(props: DropDownProps<T>) => {
29
38
  const { size = "md", value = [] } = props;
30
39
 
31
- const list = useMemo(() => {
32
- return props.filteredOptions.length > 0 ? (
33
- props.filteredOptions.map((option) => {
34
- const isSelected = value.find(
35
- (v) => v[props.labelKey] === option[props.labelKey]
36
- );
37
- const key = Math.random().toString(36).slice(2);
38
- return (
39
- <li
40
- key={key}
41
- className={`k-multiselect-option k-multiselect-option-${size} ${
42
- isSelected ? "k-multiselect-option-selected" : ""
43
- }`}
44
- onClick={(e) => {
45
- e.stopPropagation();
46
- props.handleOptionToggle(option);
47
- }}
48
- >
49
- <span className="k-multiselect-option-label">
50
- {String(option[props.labelKey])}
51
- </span>
52
- {isSelected && (
53
- <FontAwesomeIcon icon={faCheck} className="k-multiselect-check" />
54
- )}
55
- </li>
56
- );
57
- })
40
+ const optionKeys = itemKeys(props.filteredOptions, props.labelKey);
41
+ const list =
42
+ props.filteredOptions.length > 0 ? (
43
+ <ul
44
+ id={props.listboxId}
45
+ role="listbox"
46
+ aria-multiselectable="true"
47
+ aria-labelledby={props.labelId}
48
+ className="k-multiselect-options-list"
49
+ >
50
+ {props.filteredOptions.map((option, index) => {
51
+ const isSelected = value.find(
52
+ (v) => v[props.labelKey] === option[props.labelKey]
53
+ );
54
+ return (
55
+ <li
56
+ key={optionKeys[index]}
57
+ ref={(el) => {
58
+ props.optionRefs.current[index] = el;
59
+ }}
60
+ id={optionId(props.listboxId, index)}
61
+ role="option"
62
+ aria-selected={!!isSelected}
63
+ className={`k-multiselect-option k-multiselect-option-${size} ${
64
+ isSelected ? "k-multiselect-option-selected" : ""
65
+ } ${
66
+ index === props.highlightedIndex
67
+ ? "k-multiselect-option-highlighted"
68
+ : ""
69
+ }`}
70
+ // Keeps focus, and so the keyboard, in the search box.
71
+ onMouseDown={(e) => e.preventDefault()}
72
+ onClick={(e) => {
73
+ e.stopPropagation();
74
+ props.handleOptionToggle(option);
75
+ }}
76
+ >
77
+ <span className="k-multiselect-option-label">
78
+ {String(option[props.labelKey])}
79
+ </span>
80
+ {isSelected && (
81
+ <FontAwesomeIcon
82
+ icon={faCheck}
83
+ className="k-multiselect-check"
84
+ />
85
+ )}
86
+ </li>
87
+ );
88
+ })}
89
+ </ul>
58
90
  ) : (
59
- <li className={`k-multiselect-no-results k-multiselect-option-${size}`}>
60
- {props.options.length === 0
61
- ? "No options available"
62
- : "No options found"}
63
- </li>
91
+ <div className="k-multiselect-options-list">
92
+ <div
93
+ role="status"
94
+ className={`k-multiselect-no-results k-multiselect-option-${size}`}
95
+ >
96
+ {props.options.length === 0
97
+ ? "No options available"
98
+ : "No options found"}
99
+ </div>
100
+ </div>
64
101
  );
65
- }, [props.filteredOptions, value]);
66
102
 
67
103
  return (
68
104
  <div className={`k-multiselect-dropdown k-multiselect-dropdown-${size}`}>
@@ -79,11 +115,22 @@ export const DropDownSection = <T,>(props: DropDownProps<T>) => {
79
115
  onClick={(e: React.MouseEvent<HTMLInputElement>) =>
80
116
  e.stopPropagation()
81
117
  }
118
+ onKeyDown={props.onSearchKeyDown}
119
+ aria-label="Search options"
120
+ aria-controls={
121
+ props.filteredOptions.length > 0 ? props.listboxId : undefined
122
+ }
123
+ aria-activedescendant={
124
+ props.highlightedIndex > -1
125
+ ? optionId(props.listboxId, props.highlightedIndex)
126
+ : undefined
127
+ }
82
128
  />
83
129
  <div className="k-multiselect-bulk-actions">
84
130
  <Tooltip content="Select All">
85
131
  <IconButton
86
132
  icon={faCheckDouble}
133
+ aria-label="Select all"
87
134
  size={size}
88
135
  variant="success"
89
136
  onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
@@ -96,6 +143,7 @@ export const DropDownSection = <T,>(props: DropDownProps<T>) => {
96
143
  <Tooltip content="Clear All">
97
144
  <IconButton
98
145
  icon={faXmark}
146
+ aria-label="Clear all"
99
147
  size={size}
100
148
  variant="danger"
101
149
  onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
@@ -108,7 +156,7 @@ export const DropDownSection = <T,>(props: DropDownProps<T>) => {
108
156
  </div>
109
157
  </div>
110
158
 
111
- <ul className="k-multiselect-options-list">{list}</ul>
159
+ {list}
112
160
  </div>
113
161
  );
114
162
  };
@@ -1,13 +1,16 @@
1
1
  "use client";
2
2
 
3
+ import useScrollIntoView from "../../../hooks/useScrollIntoView.js";
3
4
  import DropdownArrowButton from "../dropdownArrowButton/index.js";
4
5
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5
6
  import useOutsideClick from "../../../hooks/useOutsideClick.js";
6
- import { useState, useRef, useEffect, useMemo } from "react";
7
+ import useListKeyboard from "../../../hooks/useListKeyboard.js";
7
8
  import { faXmark } from "@fortawesome/free-solid-svg-icons";
9
+ import { useState, useRef, useEffect, useId } from "react";
8
10
  import FieldShell from "../../forms/fieldShell/index.js";
9
11
  import { DropDownSection } from "./dropDown.js";
10
12
  import { PropsWithSize } from "../../types.js";
13
+ import { itemKeys } from "./utils.js";
11
14
  import "./styles.css";
12
15
 
13
16
  interface MultiSelectProps<T> extends PropsWithSize {
@@ -59,8 +62,13 @@ const MultiSelect = <T,>(props: MultiSelectProps<T>) => {
59
62
  const [filteredOptions, setFilteredOptions] = useState(props.options);
60
63
  const containerRef = useRef<HTMLDivElement>(null);
61
64
  const searchInputRef = useRef<HTMLInputElement>(null);
62
- const componentId =
63
- props.id || `multiselect-${Math.random().toString(36).substring(2, 9)}`;
65
+ const comboboxRef = useRef<HTMLDivElement>(null);
66
+ const optionRefs = useRef<(HTMLLIElement | null)[]>([]);
67
+ const [highlightedIndex, setHighlightedIndex] = useState(-1);
68
+ const generatedId = useId();
69
+ const componentId = props.id || `multiselect-${generatedId}`;
70
+ const labelId = `${componentId}-label`;
71
+ const listboxId = `${componentId}-listbox`;
64
72
 
65
73
  // Filter options based on search term
66
74
  useEffect(() => {
@@ -74,6 +82,7 @@ const MultiSelect = <T,>(props: MultiSelectProps<T>) => {
74
82
  } else {
75
83
  setFilteredOptions(props.options);
76
84
  }
85
+ setHighlightedIndex(-1);
77
86
  }, [searchTerm, props.options]);
78
87
 
79
88
  useOutsideClick([containerRef], () => setIsOpen(false));
@@ -85,11 +94,35 @@ const MultiSelect = <T,>(props: MultiSelectProps<T>) => {
85
94
  }
86
95
  }, [isOpen]);
87
96
 
97
+ useScrollIntoView(optionRefs, highlightedIndex, isOpen);
98
+
88
99
  const handleToggleDropdown = () => {
89
100
  if (disabled) return;
90
101
  setIsOpen(!isOpen);
91
102
  if (!isOpen) {
92
103
  setSearchTerm("");
104
+ setHighlightedIndex(-1);
105
+ }
106
+ };
107
+
108
+ const close = () => {
109
+ setIsOpen(false);
110
+ comboboxRef.current?.focus();
111
+ };
112
+
113
+ // Closes when focus moves to something outside, such as on Tab. A null
114
+ // relatedTarget (a click on nothing focusable) is left to useOutsideClick,
115
+ // so a click inside the dropdown doesn't close it.
116
+ const handleBlur = (e: React.FocusEvent<HTMLDivElement>) => {
117
+ const next = e.relatedTarget;
118
+ if (next && !containerRef.current?.contains(next)) setIsOpen(false);
119
+ };
120
+
121
+ const handleComboboxKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
122
+ if (disabled || isOpen) return;
123
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
124
+ e.preventDefault();
125
+ handleToggleDropdown();
93
126
  }
94
127
  };
95
128
 
@@ -167,42 +200,61 @@ const MultiSelect = <T,>(props: MultiSelectProps<T>) => {
167
200
  props.onChange([]);
168
201
  };
169
202
 
170
- const selectedItems = useMemo(() => {
171
- return value.map((v) => {
172
- const key = Math.random().toString(36).slice(2);
173
- return (
174
- <div key={key} className="k-multiselect-selected-item">
175
- <span className="k-multiselect-selected-item-label">
176
- {String(v[props.labelKey])}
177
- </span>
178
- {!disabled && (
179
- <button
180
- type="button"
181
- className="k-multiselect-selected-item-remove"
182
- aria-label={`Remove ${String(v[props.labelKey])}`}
183
- onClick={(e) => {
184
- e.stopPropagation();
185
- handleOptionToggle(v);
186
- }}
187
- >
188
- <FontAwesomeIcon icon={faXmark} />
189
- </button>
190
- )}
191
- </div>
192
- );
193
- });
194
- }, [value]);
203
+ const handleSearchKeyDown = useListKeyboard({
204
+ isOpen,
205
+ length: filteredOptions.length,
206
+ highlightedIndex,
207
+ setHighlightedIndex,
208
+ onSelect: (index) => handleOptionToggle(filteredOptions[index]),
209
+ onClose: close,
210
+ });
211
+
212
+ const selectedKeys = itemKeys(value, props.labelKey);
213
+ const selectedItems = value.map((v, index) => (
214
+ <div key={selectedKeys[index]} className="k-multiselect-selected-item">
215
+ <span className="k-multiselect-selected-item-label">
216
+ {String(v[props.labelKey])}
217
+ </span>
218
+ {/* Mouse-only: a combobox can't contain controls, so keyboard and
219
+ screen-reader users deselect from the listbox instead. */}
220
+ {!disabled && (
221
+ <button
222
+ type="button"
223
+ className="k-multiselect-selected-item-remove"
224
+ tabIndex={-1}
225
+ aria-hidden="true"
226
+ aria-label={`Remove ${String(v[props.labelKey])}`}
227
+ onClick={(e) => {
228
+ e.stopPropagation();
229
+ handleOptionToggle(v);
230
+ }}
231
+ >
232
+ <FontAwesomeIcon icon={faXmark} />
233
+ </button>
234
+ )}
235
+ </div>
236
+ ));
195
237
 
196
238
  return (
197
- <div ref={containerRef}>
239
+ <div ref={containerRef} onBlur={handleBlur}>
198
240
  <FieldShell
199
241
  label={props.label}
200
242
  required={required}
201
- htmlFor={componentId}
243
+ labelId={labelId}
202
244
  className="k-multiselect-container"
203
245
  >
204
246
  <div
247
+ ref={comboboxRef}
205
248
  id={componentId}
249
+ role="combobox"
250
+ aria-haspopup="listbox"
251
+ aria-expanded={isOpen}
252
+ aria-controls={isOpen ? listboxId : undefined}
253
+ aria-labelledby={props.label ? labelId : undefined}
254
+ aria-label={props.label ? undefined : placeholder}
255
+ aria-required={required || undefined}
256
+ aria-disabled={disabled || undefined}
257
+ onKeyDown={handleComboboxKeyDown}
206
258
  className={`k-multiselect k-multiselect-${size} ${
207
259
  disabled ? "k-multiselect-disabled" : ""
208
260
  } ${isOpen ? "k-multiselect-open" : ""}`}
@@ -241,6 +293,11 @@ const MultiSelect = <T,>(props: MultiSelectProps<T>) => {
241
293
  handleSelectAll={handleSelectAll}
242
294
  handleClearAll={handleClearAll}
243
295
  handleOptionToggle={handleOptionToggle}
296
+ listboxId={listboxId}
297
+ labelId={props.label ? labelId : undefined}
298
+ highlightedIndex={highlightedIndex}
299
+ optionRefs={optionRefs}
300
+ onSearchKeyDown={handleSearchKeyDown}
244
301
  />
245
302
  )}
246
303
  </FieldShell>
@@ -8,19 +8,19 @@
8
8
  margin-bottom: 0.1rem;
9
9
  font-size: 0.875rem;
10
10
  font-weight: 500;
11
- color: var(--text-color);
11
+ color: var(--k-text-color);
12
12
  }
13
13
 
14
14
  .k-multiselect {
15
- border: 0.0625rem solid var(--border-color);
15
+ border: 0.0625rem solid var(--k-border-color);
16
16
  border-radius: 0.375rem;
17
- color: var(--text-color);
17
+ color: var(--k-text-color);
18
18
  width: 100%;
19
19
  box-sizing: border-box;
20
20
  transition:
21
21
  border-color 0.2s ease-in-out,
22
22
  box-shadow 0.2s ease-in-out;
23
- background-color: var(--background-color-light);
23
+ background-color: var(--k-background-color-light);
24
24
  cursor: pointer;
25
25
  display: flex;
26
26
  align-items: flex-start;
@@ -31,39 +31,39 @@
31
31
 
32
32
  /* Size variants */
33
33
  .k-multiselect-sm {
34
- font-size: var(--text-size-sm);
34
+ font-size: var(--k-text-size-sm);
35
35
  padding: 0.5rem 2.5rem 0.5rem 0.75rem;
36
36
  }
37
37
 
38
38
  .k-multiselect-md {
39
- font-size: var(--text-size-md);
39
+ font-size: var(--k-text-size-md);
40
40
  padding: 0.625rem 2.75rem 0.625rem 1rem;
41
41
  }
42
42
 
43
43
  .k-multiselect-lg {
44
- font-size: var(--text-size-lg);
44
+ font-size: var(--k-text-size-lg);
45
45
  padding: 0.75rem 3rem 0.75rem 1.25rem;
46
46
  }
47
47
 
48
48
  /* States */
49
49
  .k-multiselect:hover:not(.k-multiselect-disabled) {
50
- border-color: var(--primary-color);
50
+ border-color: var(--k-primary-color);
51
51
  }
52
52
 
53
53
  .k-multiselect:focus {
54
54
  outline: none;
55
- border-color: var(--border-color-active);
56
- box-shadow: 0 0 0 0.1875rem var(--border-shadow-color-active);
55
+ border-color: var(--k-border-color-active);
56
+ box-shadow: 0 0 0 0.1875rem var(--k-border-shadow-color-active);
57
57
  }
58
58
 
59
59
  .k-multiselect-open {
60
- border-color: var(--border-color-active);
61
- box-shadow: 0 0 0 0.1875rem var(--border-shadow-color-active);
60
+ border-color: var(--k-border-color-active);
61
+ box-shadow: 0 0 0 0.1875rem var(--k-border-shadow-color-active);
62
62
  }
63
63
 
64
64
  .k-multiselect-disabled {
65
- background-color: var(--disabled-bg);
66
- color: var(--disabled-text);
65
+ background-color: var(--k-background-color-disabled);
66
+ color: var(--k-text-color-disabled);
67
67
  cursor: not-allowed;
68
68
  opacity: 0.6;
69
69
  }
@@ -75,7 +75,7 @@
75
75
  }
76
76
 
77
77
  .k-multiselect-placeholder {
78
- color: var(--text-color-secondary);
78
+ color: var(--k-text-color-secondary);
79
79
  opacity: 0.7;
80
80
  }
81
81
 
@@ -93,31 +93,31 @@
93
93
 
94
94
  /* Fixed height for 5 items based on size */
95
95
  .k-multiselect-sm .k-multiselect-selected-items {
96
- max-height: calc(5 * (var(--text-size-sm) + 1.15rem));
96
+ max-height: calc(5 * (var(--k-text-size-sm) + 1.15rem));
97
97
  }
98
98
 
99
99
  .k-multiselect-md .k-multiselect-selected-items {
100
- max-height: calc(5 * (var(--text-size-md) + 1.5rem));
100
+ max-height: calc(5 * (var(--k-text-size-md) + 1.5rem));
101
101
  }
102
102
 
103
103
  .k-multiselect-lg .k-multiselect-selected-items {
104
- max-height: calc(5 * (var(--text-size-lg) + 1.8rem));
104
+ max-height: calc(5 * (var(--k-text-size-lg) + 1.8rem));
105
105
  }
106
106
 
107
107
  .k-multiselect-selected-item {
108
108
  display: flex;
109
109
  align-items: center;
110
110
  justify-content: space-between;
111
- background-color: var(--background-color-dark);
111
+ background-color: var(--k-background-color-dark);
112
112
  border-radius: 0.25rem;
113
113
  }
114
114
 
115
115
  .k-multiselect-selected-item:hover {
116
- background-color: var(--background-color-hover);
116
+ background-color: var(--k-background-color-hover);
117
117
  }
118
118
 
119
119
  .k-multiselect-selected-item-label {
120
- color: var(--text-color);
120
+ color: var(--k-text-color);
121
121
  flex: 1;
122
122
  text-align: left;
123
123
  }
@@ -125,17 +125,17 @@
125
125
  /* Size variants for selected items */
126
126
  .k-multiselect-sm .k-multiselect-selected-item {
127
127
  padding: 0.25rem 0.5rem;
128
- font-size: var(--text-size-sm);
128
+ font-size: var(--k-text-size-sm);
129
129
  }
130
130
 
131
131
  .k-multiselect-md .k-multiselect-selected-item {
132
132
  padding: 0.375rem 0.625rem;
133
- font-size: var(--text-size-md);
133
+ font-size: var(--k-text-size-md);
134
134
  }
135
135
 
136
136
  .k-multiselect-lg .k-multiselect-selected-item {
137
137
  padding: 0.5rem 0.75rem;
138
- font-size: var(--text-size-lg);
138
+ font-size: var(--k-text-size-lg);
139
139
  }
140
140
 
141
141
  .k-multiselect-selected-item-remove {
@@ -143,7 +143,7 @@
143
143
  border: none;
144
144
  padding: 0;
145
145
  cursor: pointer;
146
- color: var(--text-color);
146
+ color: var(--k-text-color);
147
147
  transition: color 0.2s ease-in-out;
148
148
  display: flex;
149
149
  align-items: center;
@@ -153,19 +153,19 @@
153
153
 
154
154
  /* Size variants for remove button */
155
155
  .k-multiselect-sm .k-multiselect-selected-item-remove {
156
- font-size: calc(var(--text-size-sm) * 0.85);
156
+ font-size: calc(var(--k-text-size-sm) * 0.85);
157
157
  }
158
158
 
159
159
  .k-multiselect-md .k-multiselect-selected-item-remove {
160
- font-size: calc(var(--text-size-md) * 0.85);
160
+ font-size: calc(var(--k-text-size-md) * 0.85);
161
161
  }
162
162
 
163
163
  .k-multiselect-lg .k-multiselect-selected-item-remove {
164
- font-size: calc(var(--text-size-lg) * 0.85);
164
+ font-size: calc(var(--k-text-size-lg) * 0.85);
165
165
  }
166
166
 
167
167
  .k-multiselect-selected-item-remove:hover {
168
- color: var(--danger-color-text);
168
+ color: var(--k-danger-color-text);
169
169
  }
170
170
 
171
171
  /* Dropdown */
@@ -175,12 +175,12 @@
175
175
  left: 0;
176
176
  right: 0;
177
177
  margin-top: 0.25rem;
178
- background-color: var(--background-color-light);
179
- border: 0.0625rem solid var(--border-color);
178
+ background-color: var(--k-background-color-light);
179
+ border: 0.0625rem solid var(--k-border-color);
180
180
  border-radius: 0.375rem;
181
181
  box-shadow:
182
- 0 0.25rem 0.375rem -0.0625rem var(--shadow-color),
183
- 0 0.125rem 0.25rem -0.125rem var(--shadow-color);
182
+ 0 0.25rem 0.375rem -0.0625rem var(--k-shadow-color),
183
+ 0 0.125rem 0.25rem -0.125rem var(--k-shadow-color);
184
184
  z-index: 1000;
185
185
  max-height: 20rem;
186
186
  display: flex;
@@ -190,16 +190,19 @@
190
190
  /* Search input */
191
191
  .k-multiselect-search-container {
192
192
  padding: 0.5rem;
193
- border-bottom: 0.0625rem solid var(--border-color);
193
+ border-bottom: 0.0625rem solid var(--k-border-color);
194
194
  display: flex;
195
195
  gap: 0.5rem;
196
196
  align-items: center;
197
197
  }
198
198
 
199
199
  /* Bulk actions */
200
+ /* Buttons allow min-width: 0, so without this the search input squeezes them
201
+ down to their padding and the icons render a few pixels wide. */
200
202
  .k-multiselect-bulk-actions {
201
203
  display: flex;
202
204
  gap: 0.25rem;
205
+ flex-shrink: 0;
203
206
  }
204
207
 
205
208
  /* Options list */
@@ -221,31 +224,31 @@
221
224
  }
222
225
 
223
226
  .k-multiselect-option-sm {
224
- font-size: var(--text-size-sm);
227
+ font-size: var(--k-text-size-sm);
225
228
  padding: 0.375rem 0.75rem;
226
229
  }
227
230
 
228
231
  .k-multiselect-option-md {
229
- font-size: var(--text-size-md);
232
+ font-size: var(--k-text-size-md);
230
233
  padding: 0.5rem 1rem;
231
234
  }
232
235
 
233
236
  .k-multiselect-option-lg {
234
- font-size: var(--text-size-lg);
237
+ font-size: var(--k-text-size-lg);
235
238
  padding: 0.625rem 1.25rem;
236
239
  }
237
240
 
238
241
  .k-multiselect-option:hover {
239
- background-color: var(--background-color-dark);
242
+ background-color: var(--k-background-color-dark);
240
243
  }
241
244
 
242
245
  .k-multiselect-option-selected {
243
- background-color: var(--background-color-dark);
244
- color: var(--text-color);
246
+ background-color: var(--k-background-color-dark);
247
+ color: var(--k-text-color);
245
248
  }
246
249
 
247
250
  .k-multiselect-option-selected:hover {
248
- background-color: var(--background-color-hover);
251
+ background-color: var(--k-background-color-hover);
249
252
  }
250
253
 
251
254
  .k-multiselect-option-label {
@@ -253,13 +256,18 @@
253
256
  }
254
257
 
255
258
  .k-multiselect-check {
256
- color: var(--text-color);
259
+ color: var(--k-text-color);
257
260
  font-size: 0.875rem;
258
261
  }
259
262
 
260
263
  .k-multiselect-no-results {
261
264
  text-align: center;
262
- color: var(--text-color-secondary);
265
+ color: var(--k-text-color-secondary);
263
266
  font-style: italic;
264
267
  padding: 1rem;
265
268
  }
269
+
270
+ .k-multiselect-option-highlighted {
271
+ background-color: var(--k-background-color-hover);
272
+ box-shadow: inset 0 0 0 0.125rem var(--k-border-color-active);
273
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Stable React keys for a list of items: an item's `value` field when it has
3
+ * one, otherwise its label. Repeats get an occurrence suffix so keys stay
4
+ * unique.
5
+ */
6
+ export const itemKeys = <T>(items: T[], labelKey: keyof T): string[] => {
7
+ const seen = new Map<string, number>();
8
+ return items.map((item) => {
9
+ const id =
10
+ typeof item === "object" && item !== null && "value" in item
11
+ ? (item as { value: unknown }).value
12
+ : item[labelKey];
13
+ const base = String(id);
14
+ const count = seen.get(base) ?? 0;
15
+ seen.set(base, count + 1);
16
+ return count === 0 ? base : `${base}#${count}`;
17
+ });
18
+ };
@@ -81,6 +81,7 @@ const PhoneInput = (props: PhoneInputProps) => {
81
81
 
82
82
  useEffect(() => {
83
83
  if (value === lastEmittedRef.current) return;
84
+ lastEmittedRef.current = value;
84
85
  if (!value) {
85
86
  setDisplay("");
86
87
  return;
@@ -89,6 +90,8 @@ const PhoneInput = (props: PhoneInputProps) => {
89
90
  if (parsed?.country) {
90
91
  setCountry(parsed.country);
91
92
  setDisplay(parsed.formatNational());
93
+ } else if (parsed) {
94
+ setDisplay(parsed.formatNational());
92
95
  } else {
93
96
  const formatter = new AsYouType(country);
94
97
  setDisplay(formatter.input(value));
@@ -121,14 +124,18 @@ const PhoneInput = (props: PhoneInputProps) => {
121
124
  const formatter = new AsYouType(country);
122
125
  const formatted = formatter.input(raw);
123
126
  const nationalDigits = formatter.getNationalNumber();
127
+ const nextCountry = formatter.getCountry() ?? country;
128
+ setCountry(nextCountry);
124
129
  setDisplay(formatted);
125
- emit(nationalDigits, country);
130
+ emit(nationalDigits, nextCountry);
126
131
  };
127
132
 
128
133
  const handleCountrySelect = (cc: CountryCode) => {
129
134
  setCountry(cc);
130
135
  setPickerOpen(false);
131
- const digits = display.replace(/\D/g, "");
136
+ const current = new AsYouType(country);
137
+ current.input(display);
138
+ const digits = current.getNationalNumber();
132
139
  if (digits) {
133
140
  const formatter = new AsYouType(cc);
134
141
  const formatted = formatter.input(digits);
@@ -192,6 +199,7 @@ const PhoneInput = (props: PhoneInputProps) => {
192
199
  value={search}
193
200
  onChange={(e) => setSearch(e.target.value)}
194
201
  placeholder="Search country or code"
202
+ aria-label="Search country or code"
195
203
  />
196
204
  </div>
197
205
  <ul className="k-phone-input-list" role="listbox">