@kosmeo-ui/react 0.1.1 → 1.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 (418) hide show
  1. package/README.md +3 -1
  2. package/dist/components/buttons/button/index.d.ts +2 -0
  3. package/dist/components/buttons/button/index.d.ts.map +1 -1
  4. package/dist/components/buttons/button/index.js +2 -2
  5. package/dist/components/buttons/button/index.js.map +1 -1
  6. package/dist/components/buttons/button/styles.css +45 -43
  7. package/dist/components/buttons/rowActions/index.d.ts.map +1 -1
  8. package/dist/components/buttons/rowActions/index.js +2 -1
  9. package/dist/components/buttons/rowActions/index.js.map +1 -1
  10. package/dist/components/buttons/rowActions/styles.css +7 -0
  11. package/dist/components/data-display/addressBlock/styles.css +2 -4
  12. package/dist/components/data-display/colorSwatch/index.d.ts +1 -1
  13. package/dist/components/data-display/colorSwatch/index.d.ts.map +1 -1
  14. package/dist/components/data-display/colorSwatch/index.js +1 -1
  15. package/dist/components/data-display/colorSwatch/index.js.map +1 -1
  16. package/dist/components/data-display/colorSwatch/styles.css +1 -1
  17. package/dist/components/data-display/dataTable/index.d.ts.map +1 -1
  18. package/dist/components/data-display/dataTable/index.js +7 -3
  19. package/dist/components/data-display/dataTable/index.js.map +1 -1
  20. package/dist/components/data-display/dataTable/styles.css +18 -2
  21. package/dist/components/data-display/dataTable/utils/parseDataKey.d.ts +8 -1
  22. package/dist/components/data-display/dataTable/utils/parseDataKey.d.ts.map +1 -1
  23. package/dist/components/data-display/dataTable/utils/parseDataKey.js +13 -41
  24. package/dist/components/data-display/dataTable/utils/parseDataKey.js.map +1 -1
  25. package/dist/components/data-display/imagePreview/styles.css +2 -2
  26. package/dist/components/data-display/infiniteScroll/filters/index.d.ts +4 -0
  27. package/dist/components/data-display/infiniteScroll/filters/index.d.ts.map +1 -1
  28. package/dist/components/data-display/infiniteScroll/filters/index.js +12 -2
  29. package/dist/components/data-display/infiniteScroll/filters/index.js.map +1 -1
  30. package/dist/components/data-display/infiniteScroll/filters/listFilter.d.ts.map +1 -1
  31. package/dist/components/data-display/infiniteScroll/filters/listFilter.js +1 -1
  32. package/dist/components/data-display/infiniteScroll/filters/listFilter.js.map +1 -1
  33. package/dist/components/data-display/infiniteScroll/filters/rangeFilter.d.ts +6 -0
  34. package/dist/components/data-display/infiniteScroll/filters/rangeFilter.d.ts.map +1 -1
  35. package/dist/components/data-display/infiniteScroll/filters/rangeFilter.js +55 -46
  36. package/dist/components/data-display/infiniteScroll/filters/rangeFilter.js.map +1 -1
  37. package/dist/components/data-display/infiniteScroll/filters/searchFilter.d.ts.map +1 -1
  38. package/dist/components/data-display/infiniteScroll/filters/searchFilter.js +4 -35
  39. package/dist/components/data-display/infiniteScroll/filters/searchFilter.js.map +1 -1
  40. package/dist/components/data-display/infiniteScroll/filters/selectFilter.d.ts.map +1 -1
  41. package/dist/components/data-display/infiniteScroll/filters/selectFilter.js +3 -5
  42. package/dist/components/data-display/infiniteScroll/filters/selectFilter.js.map +1 -1
  43. package/dist/components/data-display/infiniteScroll/filters/styles.css +34 -1
  44. package/dist/components/data-display/infiniteScroll/header/deleteButton.d.ts.map +1 -1
  45. package/dist/components/data-display/infiniteScroll/header/deleteButton.js +1 -1
  46. package/dist/components/data-display/infiniteScroll/header/deleteButton.js.map +1 -1
  47. package/dist/components/data-display/infiniteScroll/header/index.d.ts.map +1 -1
  48. package/dist/components/data-display/infiniteScroll/header/index.js +1 -1
  49. package/dist/components/data-display/infiniteScroll/header/index.js.map +1 -1
  50. package/dist/components/data-display/infiniteScroll/header/limit.d.ts.map +1 -1
  51. package/dist/components/data-display/infiniteScroll/header/limit.js +1 -1
  52. package/dist/components/data-display/infiniteScroll/header/limit.js.map +1 -1
  53. package/dist/components/data-display/infiniteScroll/header/sortBy.d.ts.map +1 -1
  54. package/dist/components/data-display/infiniteScroll/header/sortBy.js +1 -1
  55. package/dist/components/data-display/infiniteScroll/header/sortBy.js.map +1 -1
  56. package/dist/components/data-display/infiniteScroll/header/sortDirection.d.ts.map +1 -1
  57. package/dist/components/data-display/infiniteScroll/header/sortDirection.js +1 -1
  58. package/dist/components/data-display/infiniteScroll/header/sortDirection.js.map +1 -1
  59. package/dist/components/data-display/infiniteScroll/index.d.ts +8 -0
  60. package/dist/components/data-display/infiniteScroll/index.d.ts.map +1 -1
  61. package/dist/components/data-display/infiniteScroll/index.js +41 -23
  62. package/dist/components/data-display/infiniteScroll/index.js.map +1 -1
  63. package/dist/components/data-display/infiniteScroll/styles.css +2 -2
  64. package/dist/components/data-display/infiniteScroll/table/index.d.ts.map +1 -1
  65. package/dist/components/data-display/infiniteScroll/table/index.js +2 -2
  66. package/dist/components/data-display/infiniteScroll/table/index.js.map +1 -1
  67. package/dist/components/data-display/infiniteScroll/tags/index.d.ts.map +1 -1
  68. package/dist/components/data-display/infiniteScroll/tags/index.js +7 -11
  69. package/dist/components/data-display/infiniteScroll/tags/index.js.map +1 -1
  70. package/dist/components/data-display/infiniteScroll/tags/listFilterTag.d.ts.map +1 -1
  71. package/dist/components/data-display/infiniteScroll/tags/listFilterTag.js +8 -8
  72. package/dist/components/data-display/infiniteScroll/tags/listFilterTag.js.map +1 -1
  73. package/dist/components/data-display/infiniteScroll/tags/rangeFilterTag.d.ts.map +1 -1
  74. package/dist/components/data-display/infiniteScroll/tags/rangeFilterTag.js +6 -18
  75. package/dist/components/data-display/infiniteScroll/tags/rangeFilterTag.js.map +1 -1
  76. package/dist/components/data-display/infiniteScroll/tags/selectFilterTag.d.ts.map +1 -1
  77. package/dist/components/data-display/infiniteScroll/tags/selectFilterTag.js +3 -5
  78. package/dist/components/data-display/infiniteScroll/tags/selectFilterTag.js.map +1 -1
  79. package/dist/components/data-display/infiniteScroll/tags/styles.css +1 -29
  80. package/dist/components/data-display/infiniteScroll/utils/generateQueryString.d.ts +6 -0
  81. package/dist/components/data-display/infiniteScroll/utils/generateQueryString.d.ts.map +1 -1
  82. package/dist/components/data-display/infiniteScroll/utils/generateQueryString.js +24 -12
  83. package/dist/components/data-display/infiniteScroll/utils/generateQueryString.js.map +1 -1
  84. package/dist/components/data-display/infiniteScroll/utils/hasPendingChanges.d.ts +11 -1
  85. package/dist/components/data-display/infiniteScroll/utils/hasPendingChanges.d.ts.map +1 -1
  86. package/dist/components/data-display/infiniteScroll/utils/hasPendingChanges.js +37 -18
  87. package/dist/components/data-display/infiniteScroll/utils/hasPendingChanges.js.map +1 -1
  88. package/dist/components/data-display/listCard/styles.css +3 -3
  89. package/dist/components/data-display/listRow/styles.css +2 -2
  90. package/dist/components/data-display/recoveryCodeGrid/styles.css +3 -4
  91. package/dist/components/data-display/secretDisplay/styles.css +4 -4
  92. package/dist/components/data-display/statCard/styles.css +12 -12
  93. package/dist/components/data-display/summaryRow/styles.css +4 -4
  94. package/dist/components/data-display/table/index.d.ts.map +1 -1
  95. package/dist/components/data-display/table/index.js +2 -2
  96. package/dist/components/data-display/table/index.js.map +1 -1
  97. package/dist/components/data-display/table/styles.css +22 -11
  98. package/dist/components/data-display/tableFilters/index.d.ts +30 -0
  99. package/dist/components/data-display/tableFilters/index.d.ts.map +1 -0
  100. package/dist/components/data-display/tableFilters/index.js +67 -0
  101. package/dist/components/data-display/tableFilters/index.js.map +1 -0
  102. package/dist/components/data-display/tagCard/index.d.ts.map +1 -1
  103. package/dist/components/data-display/tagCard/index.js +1 -1
  104. package/dist/components/data-display/tagCard/index.js.map +1 -1
  105. package/dist/components/data-display/tagCard/styles.css +1 -1
  106. package/dist/components/feedback/alert/styles.css +15 -15
  107. package/dist/components/feedback/badge/index.d.ts.map +1 -1
  108. package/dist/components/feedback/badge/index.js +14 -8
  109. package/dist/components/feedback/badge/index.js.map +1 -1
  110. package/dist/components/feedback/badge/styles.css +45 -45
  111. package/dist/components/feedback/emptyState/styles.css +2 -4
  112. package/dist/components/feedback/loadingOverlay/styles.css +1 -1
  113. package/dist/components/feedback/progressBar/index.d.ts.map +1 -1
  114. package/dist/components/feedback/progressBar/index.js +7 -2
  115. package/dist/components/feedback/progressBar/index.js.map +1 -1
  116. package/dist/components/feedback/progressBar/styles.css +25 -16
  117. package/dist/components/feedback/spinner/styles.css +14 -24
  118. package/dist/components/feedback/tooltip/styles.css +9 -7
  119. package/dist/components/forms/detailField/styles.css +1 -1
  120. package/dist/components/forms/fieldShell/index.d.ts +3 -1
  121. package/dist/components/forms/fieldShell/index.d.ts.map +1 -1
  122. package/dist/components/forms/fieldShell/index.js +1 -1
  123. package/dist/components/forms/fieldShell/index.js.map +1 -1
  124. package/dist/components/forms/fieldShell/styles.css +5 -5
  125. package/dist/components/forms/form/styles.css +6 -6
  126. package/dist/components/forms/formActions/styles.css +4 -4
  127. package/dist/components/forms/formGrid/styles.css +32 -0
  128. package/dist/components/forms/infoRow/styles.css +2 -3
  129. package/dist/components/forms/optionsGroup/index.d.ts +3 -1
  130. package/dist/components/forms/optionsGroup/index.d.ts.map +1 -1
  131. package/dist/components/forms/optionsGroup/index.js +5 -1
  132. package/dist/components/forms/optionsGroup/index.js.map +1 -1
  133. package/dist/components/forms/optionsGroup/styles.css +1 -1
  134. package/dist/components/forms/requiredAsterisk/index.d.ts.map +1 -1
  135. package/dist/components/forms/requiredAsterisk/index.js +3 -2
  136. package/dist/components/forms/requiredAsterisk/index.js.map +1 -1
  137. package/dist/components/forms/requiredAsterisk/styles.css +1 -1
  138. package/dist/components/index.d.ts +4 -0
  139. package/dist/components/index.d.ts.map +1 -1
  140. package/dist/components/index.js +2 -0
  141. package/dist/components/index.js.map +1 -1
  142. package/dist/components/inputs/checkbox/index.d.ts +6 -1
  143. package/dist/components/inputs/checkbox/index.d.ts.map +1 -1
  144. package/dist/components/inputs/checkbox/index.js +12 -3
  145. package/dist/components/inputs/checkbox/index.js.map +1 -1
  146. package/dist/components/inputs/checkbox/styles.css +11 -3
  147. package/dist/components/inputs/colorPicker/index.d.ts.map +1 -1
  148. package/dist/components/inputs/colorPicker/index.js +3 -1
  149. package/dist/components/inputs/colorPicker/index.js.map +1 -1
  150. package/dist/components/inputs/colorPicker/styles.css +3 -3
  151. package/dist/components/inputs/dateInput/index.d.ts +6 -6
  152. package/dist/components/inputs/dateInput/index.d.ts.map +1 -1
  153. package/dist/components/inputs/dateInput/index.js +15 -5
  154. package/dist/components/inputs/dateInput/index.js.map +1 -1
  155. package/dist/components/inputs/dateInput/styles.css +5 -5
  156. package/dist/components/inputs/dateInput/utils.d.ts +0 -1
  157. package/dist/components/inputs/dateInput/utils.d.ts.map +1 -1
  158. package/dist/components/inputs/dateInput/utils.js +13 -8
  159. package/dist/components/inputs/dateInput/utils.js.map +1 -1
  160. package/dist/components/inputs/dropdown/index.d.ts +2 -0
  161. package/dist/components/inputs/dropdown/index.d.ts.map +1 -1
  162. package/dist/components/inputs/dropdown/index.js +2 -2
  163. package/dist/components/inputs/dropdown/index.js.map +1 -1
  164. package/dist/components/inputs/dropdown/styles.css +2 -2
  165. package/dist/components/inputs/dropdownArrowButton/index.d.ts.map +1 -1
  166. package/dist/components/inputs/dropdownArrowButton/index.js +1 -1
  167. package/dist/components/inputs/dropdownArrowButton/index.js.map +1 -1
  168. package/dist/components/inputs/dropdownArrowButton/styles.css +7 -5
  169. package/dist/components/inputs/fileDropZone/index.d.ts.map +1 -1
  170. package/dist/components/inputs/fileDropZone/index.js +3 -2
  171. package/dist/components/inputs/fileDropZone/index.js.map +1 -1
  172. package/dist/components/inputs/fileDropZone/styles.css +12 -12
  173. package/dist/components/inputs/fileUpload/index.d.ts.map +1 -1
  174. package/dist/components/inputs/fileUpload/index.js +11 -6
  175. package/dist/components/inputs/fileUpload/index.js.map +1 -1
  176. package/dist/components/inputs/fileUpload/styles.css +9 -9
  177. package/dist/components/inputs/input/index.d.ts +17 -1
  178. package/dist/components/inputs/input/index.d.ts.map +1 -1
  179. package/dist/components/inputs/input/index.js +27 -5
  180. package/dist/components/inputs/input/index.js.map +1 -1
  181. package/dist/components/inputs/input/styles.css +68 -24
  182. package/dist/components/inputs/languageSelect/index.d.ts.map +1 -1
  183. package/dist/components/inputs/languageSelect/index.js +15 -4
  184. package/dist/components/inputs/languageSelect/index.js.map +1 -1
  185. package/dist/components/inputs/multiSelect/dropDown.d.ts +7 -0
  186. package/dist/components/inputs/multiSelect/dropDown.d.ts.map +1 -1
  187. package/dist/components/inputs/multiSelect/dropDown.js +19 -12
  188. package/dist/components/inputs/multiSelect/dropDown.js.map +1 -1
  189. package/dist/components/inputs/multiSelect/index.d.ts.map +1 -1
  190. package/dist/components/inputs/multiSelect/index.js +49 -13
  191. package/dist/components/inputs/multiSelect/index.js.map +1 -1
  192. package/dist/components/inputs/multiSelect/styles.css +51 -43
  193. package/dist/components/inputs/multiSelect/utils.d.ts +7 -0
  194. package/dist/components/inputs/multiSelect/utils.d.ts.map +1 -0
  195. package/dist/components/inputs/multiSelect/utils.js +18 -0
  196. package/dist/components/inputs/multiSelect/utils.js.map +1 -0
  197. package/dist/components/inputs/phoneInput/index.d.ts.map +1 -1
  198. package/dist/components/inputs/phoneInput/index.js +11 -3
  199. package/dist/components/inputs/phoneInput/index.js.map +1 -1
  200. package/dist/components/inputs/phoneInput/styles.css +13 -13
  201. package/dist/components/inputs/radioGroup/index.d.ts.map +1 -1
  202. package/dist/components/inputs/radioGroup/index.js +1 -1
  203. package/dist/components/inputs/radioGroup/index.js.map +1 -1
  204. package/dist/components/inputs/richTextEditor/index.d.ts.map +1 -1
  205. package/dist/components/inputs/richTextEditor/index.js +30 -20
  206. package/dist/components/inputs/richTextEditor/index.js.map +1 -1
  207. package/dist/components/inputs/richTextEditor/styles.css +24 -24
  208. package/dist/components/inputs/searchList/index.d.ts +4 -1
  209. package/dist/components/inputs/searchList/index.d.ts.map +1 -1
  210. package/dist/components/inputs/searchList/index.js +46 -31
  211. package/dist/components/inputs/searchList/index.js.map +1 -1
  212. package/dist/components/inputs/searchList/styles.css +22 -22
  213. package/dist/components/inputs/searchSelect/index.d.ts.map +1 -1
  214. package/dist/components/inputs/searchSelect/index.js +8 -2
  215. package/dist/components/inputs/searchSelect/index.js.map +1 -1
  216. package/dist/components/inputs/select/index.js +3 -2
  217. package/dist/components/inputs/select/index.js.map +1 -1
  218. package/dist/components/inputs/select/styles.css +93 -15
  219. package/dist/components/inputs/switch/index.d.ts.map +1 -1
  220. package/dist/components/inputs/switch/index.js +3 -1
  221. package/dist/components/inputs/switch/index.js.map +1 -1
  222. package/dist/components/inputs/switch/styles.css +5 -5
  223. package/dist/components/inputs/textArea/index.d.ts.map +1 -1
  224. package/dist/components/inputs/textArea/index.js +3 -2
  225. package/dist/components/inputs/textArea/index.js.map +1 -1
  226. package/dist/components/inputs/textArea/styles.css +11 -11
  227. package/dist/components/inputs/typeahead/index.d.ts.map +1 -1
  228. package/dist/components/inputs/typeahead/index.js +21 -6
  229. package/dist/components/inputs/typeahead/index.js.map +1 -1
  230. package/dist/components/inputs/typeahead/styles.css +13 -13
  231. package/dist/components/layout/authPage/styles.css +6 -6
  232. package/dist/components/layout/borderedSection/index.d.ts +3 -1
  233. package/dist/components/layout/borderedSection/index.d.ts.map +1 -1
  234. package/dist/components/layout/borderedSection/index.js +2 -2
  235. package/dist/components/layout/borderedSection/index.js.map +1 -1
  236. package/dist/components/layout/borderedSection/styles.css +3 -3
  237. package/dist/components/layout/card/styles.css +53 -31
  238. package/dist/components/layout/col/styles.css +1 -1
  239. package/dist/components/layout/page/styles.css +25 -5
  240. package/dist/components/layout/sectionHeader/styles.css +3 -4
  241. package/dist/components/navigation/breadcrumbs/styles.css +7 -7
  242. package/dist/components/navigation/pagination/index.d.ts +23 -0
  243. package/dist/components/navigation/pagination/index.d.ts.map +1 -0
  244. package/dist/components/navigation/pagination/index.js +29 -0
  245. package/dist/components/navigation/pagination/index.js.map +1 -0
  246. package/dist/components/navigation/pagination/styles.css +113 -0
  247. package/dist/components/navigation/pagination/utils.d.ts +9 -0
  248. package/dist/components/navigation/pagination/utils.d.ts.map +1 -0
  249. package/dist/components/navigation/pagination/utils.js +25 -0
  250. package/dist/components/navigation/pagination/utils.js.map +1 -0
  251. package/dist/components/navigation/sidebar/styles.css +13 -5
  252. package/dist/components/navigation/stepper/styles.css +14 -14
  253. package/dist/components/navigation/tabButton/styles.css +59 -59
  254. package/dist/components/navigation/tabs/styles.css +5 -5
  255. package/dist/components/overlays/confirmationModal/index.d.ts +5 -0
  256. package/dist/components/overlays/confirmationModal/index.d.ts.map +1 -1
  257. package/dist/components/overlays/confirmationModal/index.js +23 -4
  258. package/dist/components/overlays/confirmationModal/index.js.map +1 -1
  259. package/dist/components/overlays/confirmationModal/styles.css +3 -0
  260. package/dist/components/overlays/modal/index.d.ts +2 -0
  261. package/dist/components/overlays/modal/index.d.ts.map +1 -1
  262. package/dist/components/overlays/modal/index.js +13 -4
  263. package/dist/components/overlays/modal/index.js.map +1 -1
  264. package/dist/components/overlays/modal/styles.css +19 -19
  265. package/dist/hooks/index.d.ts +1 -0
  266. package/dist/hooks/index.d.ts.map +1 -1
  267. package/dist/hooks/index.js +1 -0
  268. package/dist/hooks/index.js.map +1 -1
  269. package/dist/hooks/useInfinite.d.ts +3 -1
  270. package/dist/hooks/useInfinite.d.ts.map +1 -1
  271. package/dist/hooks/useInfinite.js +4 -2
  272. package/dist/hooks/useInfinite.js.map +1 -1
  273. package/dist/hooks/useInfiniteArchivableCursor.d.ts +1 -1
  274. package/dist/hooks/useInfiniteArchivableCursor.d.ts.map +1 -1
  275. package/dist/hooks/useInfiniteArchivableCursor.js +11 -4
  276. package/dist/hooks/useInfiniteArchivableCursor.js.map +1 -1
  277. package/dist/hooks/useInfiniteCursor.d.ts +1 -1
  278. package/dist/hooks/useInfiniteCursor.d.ts.map +1 -1
  279. package/dist/hooks/useInfiniteCursor.js +11 -4
  280. package/dist/hooks/useInfiniteCursor.js.map +1 -1
  281. package/dist/hooks/usePaginated.d.ts +43 -0
  282. package/dist/hooks/usePaginated.d.ts.map +1 -0
  283. package/dist/hooks/usePaginated.js +60 -0
  284. package/dist/hooks/usePaginated.js.map +1 -0
  285. package/dist/styles.css +161 -123
  286. package/package.json +15 -4
  287. package/src/components/buttons/button/index.tsx +14 -5
  288. package/src/components/buttons/button/styles.css +45 -43
  289. package/src/components/buttons/rowActions/index.tsx +6 -1
  290. package/src/components/buttons/rowActions/styles.css +7 -0
  291. package/src/components/data-display/addressBlock/styles.css +2 -4
  292. package/src/components/data-display/colorSwatch/index.tsx +2 -2
  293. package/src/components/data-display/colorSwatch/styles.css +1 -1
  294. package/src/components/data-display/dataTable/index.tsx +6 -3
  295. package/src/components/data-display/dataTable/styles.css +18 -2
  296. package/src/components/data-display/dataTable/utils/parseDataKey.ts +18 -36
  297. package/src/components/data-display/imagePreview/styles.css +2 -2
  298. package/src/components/data-display/infiniteScroll/filters/index.tsx +18 -1
  299. package/src/components/data-display/infiniteScroll/filters/listFilter.tsx +1 -0
  300. package/src/components/data-display/infiniteScroll/filters/rangeFilter.tsx +77 -33
  301. package/src/components/data-display/infiniteScroll/filters/searchFilter.tsx +16 -65
  302. package/src/components/data-display/infiniteScroll/filters/selectFilter.tsx +11 -17
  303. package/src/components/data-display/infiniteScroll/filters/styles.css +34 -1
  304. package/src/components/data-display/infiniteScroll/header/deleteButton.tsx +1 -0
  305. package/src/components/data-display/infiniteScroll/header/index.tsx +4 -0
  306. package/src/components/data-display/infiniteScroll/header/limit.tsx +1 -0
  307. package/src/components/data-display/infiniteScroll/header/sortBy.tsx +1 -0
  308. package/src/components/data-display/infiniteScroll/header/sortDirection.tsx +1 -0
  309. package/src/components/data-display/infiniteScroll/index.tsx +75 -29
  310. package/src/components/data-display/infiniteScroll/styles.css +2 -2
  311. package/src/components/data-display/infiniteScroll/table/index.tsx +2 -0
  312. package/src/components/data-display/infiniteScroll/tags/index.tsx +7 -16
  313. package/src/components/data-display/infiniteScroll/tags/listFilterTag.tsx +31 -28
  314. package/src/components/data-display/infiniteScroll/tags/rangeFilterTag.tsx +8 -25
  315. package/src/components/data-display/infiniteScroll/tags/selectFilterTag.tsx +4 -11
  316. package/src/components/data-display/infiniteScroll/tags/styles.css +1 -29
  317. package/src/components/data-display/infiniteScroll/utils/generateQueryString.ts +28 -13
  318. package/src/components/data-display/infiniteScroll/utils/hasPendingChanges.ts +48 -16
  319. package/src/components/data-display/listCard/styles.css +3 -3
  320. package/src/components/data-display/listRow/styles.css +2 -2
  321. package/src/components/data-display/recoveryCodeGrid/styles.css +3 -4
  322. package/src/components/data-display/secretDisplay/styles.css +4 -4
  323. package/src/components/data-display/statCard/styles.css +12 -12
  324. package/src/components/data-display/summaryRow/styles.css +4 -4
  325. package/src/components/data-display/table/index.tsx +2 -2
  326. package/src/components/data-display/table/styles.css +22 -11
  327. package/src/components/data-display/tableFilters/index.tsx +147 -0
  328. package/src/components/data-display/tagCard/index.tsx +7 -4
  329. package/src/components/data-display/tagCard/styles.css +1 -1
  330. package/src/components/feedback/alert/styles.css +15 -15
  331. package/src/components/feedback/badge/index.tsx +36 -16
  332. package/src/components/feedback/badge/styles.css +45 -45
  333. package/src/components/feedback/emptyState/styles.css +2 -4
  334. package/src/components/feedback/loadingOverlay/styles.css +1 -1
  335. package/src/components/feedback/progressBar/index.tsx +14 -8
  336. package/src/components/feedback/progressBar/styles.css +25 -16
  337. package/src/components/feedback/spinner/styles.css +14 -24
  338. package/src/components/feedback/tooltip/styles.css +9 -7
  339. package/src/components/forms/detailField/styles.css +1 -1
  340. package/src/components/forms/fieldShell/index.tsx +4 -1
  341. package/src/components/forms/fieldShell/styles.css +5 -5
  342. package/src/components/forms/form/styles.css +6 -6
  343. package/src/components/forms/formActions/styles.css +4 -4
  344. package/src/components/forms/formGrid/styles.css +32 -0
  345. package/src/components/forms/infoRow/styles.css +2 -3
  346. package/src/components/forms/optionsGroup/index.tsx +31 -12
  347. package/src/components/forms/optionsGroup/styles.css +1 -1
  348. package/src/components/forms/requiredAsterisk/index.tsx +5 -1
  349. package/src/components/forms/requiredAsterisk/styles.css +1 -1
  350. package/src/components/index.ts +4 -0
  351. package/src/components/inputs/checkbox/index.tsx +27 -6
  352. package/src/components/inputs/checkbox/styles.css +11 -3
  353. package/src/components/inputs/colorPicker/index.tsx +5 -2
  354. package/src/components/inputs/colorPicker/styles.css +3 -3
  355. package/src/components/inputs/dateInput/index.tsx +17 -9
  356. package/src/components/inputs/dateInput/styles.css +5 -5
  357. package/src/components/inputs/dateInput/utils.ts +12 -8
  358. package/src/components/inputs/dropdown/index.tsx +5 -1
  359. package/src/components/inputs/dropdown/styles.css +2 -2
  360. package/src/components/inputs/dropdownArrowButton/index.tsx +1 -0
  361. package/src/components/inputs/dropdownArrowButton/styles.css +7 -5
  362. package/src/components/inputs/fileDropZone/index.tsx +4 -3
  363. package/src/components/inputs/fileDropZone/styles.css +12 -12
  364. package/src/components/inputs/fileUpload/index.tsx +33 -23
  365. package/src/components/inputs/fileUpload/styles.css +9 -9
  366. package/src/components/inputs/input/index.tsx +67 -6
  367. package/src/components/inputs/input/styles.css +68 -24
  368. package/src/components/inputs/languageSelect/index.tsx +19 -4
  369. package/src/components/inputs/multiSelect/dropDown.tsx +83 -35
  370. package/src/components/inputs/multiSelect/index.tsx +87 -29
  371. package/src/components/inputs/multiSelect/styles.css +51 -43
  372. package/src/components/inputs/multiSelect/utils.ts +18 -0
  373. package/src/components/inputs/phoneInput/index.tsx +16 -4
  374. package/src/components/inputs/phoneInput/styles.css +13 -13
  375. package/src/components/inputs/radioGroup/index.tsx +2 -1
  376. package/src/components/inputs/richTextEditor/index.tsx +59 -37
  377. package/src/components/inputs/richTextEditor/styles.css +24 -24
  378. package/src/components/inputs/searchList/index.tsx +121 -109
  379. package/src/components/inputs/searchList/styles.css +22 -22
  380. package/src/components/inputs/searchSelect/index.tsx +8 -2
  381. package/src/components/inputs/select/index.tsx +3 -3
  382. package/src/components/inputs/select/styles.css +93 -15
  383. package/src/components/inputs/switch/index.tsx +3 -2
  384. package/src/components/inputs/switch/styles.css +5 -5
  385. package/src/components/inputs/textArea/index.tsx +3 -3
  386. package/src/components/inputs/textArea/styles.css +11 -11
  387. package/src/components/inputs/typeahead/index.tsx +84 -54
  388. package/src/components/inputs/typeahead/styles.css +13 -13
  389. package/src/components/layout/authPage/styles.css +6 -6
  390. package/src/components/layout/borderedSection/index.tsx +4 -1
  391. package/src/components/layout/borderedSection/styles.css +3 -3
  392. package/src/components/layout/card/styles.css +53 -31
  393. package/src/components/layout/col/styles.css +1 -1
  394. package/src/components/layout/page/styles.css +25 -5
  395. package/src/components/layout/sectionHeader/styles.css +3 -4
  396. package/src/components/navigation/breadcrumbs/styles.css +7 -7
  397. package/src/components/navigation/pagination/index.tsx +134 -0
  398. package/src/components/navigation/pagination/styles.css +113 -0
  399. package/src/components/navigation/pagination/utils.ts +32 -0
  400. package/src/components/navigation/sidebar/styles.css +13 -5
  401. package/src/components/navigation/stepper/styles.css +14 -14
  402. package/src/components/navigation/tabButton/styles.css +59 -59
  403. package/src/components/navigation/tabs/styles.css +5 -5
  404. package/src/components/overlays/confirmationModal/index.tsx +37 -1
  405. package/src/components/overlays/confirmationModal/styles.css +3 -0
  406. package/src/components/overlays/modal/index.tsx +23 -4
  407. package/src/components/overlays/modal/styles.css +19 -19
  408. package/src/hooks/index.ts +4 -0
  409. package/src/hooks/useInfinite.ts +7 -3
  410. package/src/hooks/useInfiniteArchivableCursor.ts +11 -4
  411. package/src/hooks/useInfiniteCursor.ts +11 -4
  412. package/src/hooks/usePaginated.ts +123 -0
  413. package/src/styles.css +161 -123
  414. package/dist/components/data-display/infiniteScroll/tags/searchFilterTag.d.ts +0 -10
  415. package/dist/components/data-display/infiniteScroll/tags/searchFilterTag.d.ts.map +0 -1
  416. package/dist/components/data-display/infiniteScroll/tags/searchFilterTag.js +0 -22
  417. package/dist/components/data-display/infiniteScroll/tags/searchFilterTag.js.map +0 -1
  418. package/src/components/data-display/infiniteScroll/tags/searchFilterTag.tsx +0 -41
@@ -1,7 +1,10 @@
1
1
  "use client";
2
2
 
3
3
  import Button from "../../buttons/button/index.js";
4
+ import Input from "../../inputs/input/index.js";
4
5
  import Modal from "../modal/index.js";
6
+ import { useState } from "react";
7
+ import "./styles.css";
5
8
 
6
9
  export interface ConfirmationModalProps {
7
10
  show: boolean;
@@ -12,14 +15,34 @@ export interface ConfirmationModalProps {
12
15
  confirmButtonText: string;
13
16
  cancelButtonText?: string;
14
17
  isLoading?: boolean;
18
+ /** **_Optional_** text the user must type, exactly, before the confirm button enables (e.g. the name of what's being deleted) */
19
+ confirmationText?: string;
20
+ /** **_Optional_** whether Escape and a click outside close the modal. Defaults to `true` */
21
+ dismissible?: boolean;
15
22
  }
16
23
 
17
24
  const ConfirmationModal = (props: ConfirmationModalProps) => {
25
+ const [typed, setTyped] = useState("");
26
+ const [wasShown, setWasShown] = useState(props.show);
27
+
28
+ // Clear the typed text each time the modal opens, so a match from a
29
+ // previous confirmation never carries over.
30
+ if (props.show !== wasShown) {
31
+ setWasShown(props.show);
32
+ if (props.show) setTyped("");
33
+ }
34
+
35
+ const confirmed =
36
+ props.confirmationText === undefined || typed === props.confirmationText;
37
+ const canConfirm = confirmed && !props.isLoading;
38
+
18
39
  return (
19
40
  <Modal
20
41
  show={props.show}
21
42
  title={props.title}
22
43
  onClose={props.handleHide}
44
+ // Cancel is disabled while loading; Escape and the backdrop follow suit.
45
+ dismissible={props.dismissible !== false && !props.isLoading}
23
46
  footerButtons={[
24
47
  <Button
25
48
  key="cancel"
@@ -34,13 +57,26 @@ const ConfirmationModal = (props: ConfirmationModalProps) => {
34
57
  variant="danger"
35
58
  onClick={props.handleConfirm}
36
59
  isLoading={props.isLoading}
37
- disabled={props.isLoading}
60
+ disabled={!canConfirm}
38
61
  >
39
62
  {props.confirmButtonText}
40
63
  </Button>,
41
64
  ]}
42
65
  >
43
66
  {props.body}
67
+ {props.confirmationText !== undefined && (
68
+ <div className="k-confirmation-modal-check">
69
+ <Input
70
+ label={`Type "${props.confirmationText}" to confirm`}
71
+ value={typed}
72
+ onChange={(e) => setTyped(e.target.value)}
73
+ onKeyDown={(e) => {
74
+ if (e.key === "Enter" && canConfirm) props.handleConfirm();
75
+ }}
76
+ autoComplete="off"
77
+ />
78
+ </div>
79
+ )}
44
80
  </Modal>
45
81
  );
46
82
  };
@@ -0,0 +1,3 @@
1
+ .k-confirmation-modal-check {
2
+ margin-top: 1rem;
3
+ }
@@ -23,13 +23,16 @@ interface ModalProps extends PropsWithChildren {
23
23
  * editors) that would feel cramped at `lg`.
24
24
  */
25
25
  size?: ModalSize;
26
+ /** **_Optional_** whether Escape and a click on the backdrop close the modal. When `false`, only the modal's own buttons can close it. Defaults to `true` */
27
+ dismissible?: boolean;
26
28
  }
27
29
 
28
30
  const Modal = (props: ModalProps) => {
29
- const { size = "md" } = props;
31
+ const { size = "md", dismissible = true } = props;
30
32
  const [shouldRender, setShouldRender] = useState(props.show);
31
33
  const [isAnimating, setIsAnimating] = useState(false);
32
34
  const contentRef = useRef<HTMLDivElement>(null);
35
+ const pressStartedOnOverlay = useRef(false);
33
36
 
34
37
  useEffect(() => {
35
38
  if (props.show) {
@@ -46,13 +49,13 @@ const Modal = (props: ModalProps) => {
46
49
  }, [props.show]);
47
50
 
48
51
  useEffect(() => {
49
- if (!props.show) return;
52
+ if (!props.show || !dismissible) return;
50
53
  const handler = (e: KeyboardEvent) => {
51
54
  if (e.key === "Escape") props.onClose();
52
55
  };
53
56
  document.addEventListener("keydown", handler);
54
57
  return () => document.removeEventListener("keydown", handler);
55
- }, [props.show, props.onClose]);
58
+ }, [props.show, props.onClose, dismissible]);
56
59
 
57
60
  useFocusTrap(contentRef, !!props.show && !!shouldRender);
58
61
 
@@ -60,7 +63,23 @@ const Modal = (props: ModalProps) => {
60
63
 
61
64
  return (
62
65
  <Portal>
63
- <div className={`k-modal-overlay ${isAnimating ? "closing" : ""}`}>
66
+ {/* Close only when the press starts and ends on the backdrop, so a text
67
+ selection dragged out of the dialog doesn't close it. */}
68
+ <div
69
+ className={`k-modal-overlay ${isAnimating ? "closing" : ""}`}
70
+ onMouseDown={(e) => {
71
+ pressStartedOnOverlay.current = e.target === e.currentTarget;
72
+ }}
73
+ onClick={(e) => {
74
+ if (
75
+ dismissible &&
76
+ pressStartedOnOverlay.current &&
77
+ e.target === e.currentTarget
78
+ ) {
79
+ props.onClose();
80
+ }
81
+ }}
82
+ >
64
83
  <div
65
84
  ref={contentRef}
66
85
  className={`k-modal-content ${isAnimating ? "closing" : ""} ${size}`}
@@ -1,4 +1,4 @@
1
- @keyframes fadeIn {
1
+ @keyframes k-fade-in {
2
2
  from {
3
3
  opacity: 0;
4
4
  }
@@ -7,7 +7,7 @@
7
7
  }
8
8
  }
9
9
 
10
- @keyframes fadeOut {
10
+ @keyframes k-fade-out {
11
11
  from {
12
12
  opacity: 1;
13
13
  }
@@ -16,7 +16,7 @@
16
16
  }
17
17
  }
18
18
 
19
- @keyframes scaleIn {
19
+ @keyframes k-scale-in {
20
20
  from {
21
21
  transform: scale(0.95);
22
22
  }
@@ -25,7 +25,7 @@
25
25
  }
26
26
  }
27
27
 
28
- @keyframes scaleOut {
28
+ @keyframes k-scale-out {
29
29
  from {
30
30
  transform: scale(1);
31
31
  }
@@ -37,7 +37,7 @@
37
37
  .k-modal-overlay {
38
38
  position: fixed;
39
39
  inset: 0;
40
- background-color: var(--background-color-overlay);
40
+ background-color: var(--k-background-color-overlay);
41
41
  display: flex;
42
42
  align-items: center;
43
43
  justify-content: center;
@@ -45,16 +45,16 @@
45
45
  padding: 1rem;
46
46
  opacity: 1;
47
47
  pointer-events: auto;
48
- animation: fadeIn 0.2s ease-out forwards;
48
+ animation: k-fade-in 0.2s ease-out forwards;
49
49
  }
50
50
 
51
51
  .k-modal-content {
52
- background-color: var(--background-color-light);
52
+ background-color: var(--k-background-color-light);
53
53
  border-radius: 0.5rem;
54
54
  padding: 1rem;
55
55
  box-shadow:
56
- 0 1.25rem 1.5625rem -0.3125rem var(--shadow-color),
57
- 0 0.5rem 0.625rem -0.375rem var(--shadow-color);
56
+ 0 1.25rem 1.5625rem -0.3125rem var(--k-shadow-color),
57
+ 0 0.5rem 0.625rem -0.375rem var(--k-shadow-color);
58
58
  max-width: 40rem;
59
59
  width: 100%;
60
60
  display: flex;
@@ -63,7 +63,7 @@
63
63
  opacity: 1;
64
64
  transform: scale(1);
65
65
  pointer-events: auto;
66
- animation: scaleIn 0.2s ease-out forwards;
66
+ animation: k-scale-in 0.2s ease-out forwards;
67
67
  max-height: 80vh;
68
68
  overflow: hidden;
69
69
  }
@@ -88,21 +88,21 @@
88
88
  }
89
89
 
90
90
  .k-modal-overlay.closing {
91
- animation: fadeOut 0.2s ease-in forwards;
91
+ animation: k-fade-out 0.2s ease-in forwards;
92
92
  pointer-events: none;
93
93
  }
94
94
 
95
95
  .k-modal-content.closing {
96
- animation: scaleOut 0.2s ease-in forwards;
96
+ animation: k-scale-out 0.2s ease-in forwards;
97
97
  pointer-events: none;
98
98
  }
99
99
 
100
100
  .k-modal-header {
101
101
  padding-bottom: 0.5rem;
102
- border-bottom: 0.0625rem solid var(--border-color);
103
- font-size: var(--text-size-xl);
102
+ border-bottom: 0.0625rem solid var(--k-border-color);
103
+ font-size: var(--k-text-size-xl);
104
104
  font-weight: 700;
105
- color: var(--text-color);
105
+ color: var(--k-text-color);
106
106
  }
107
107
 
108
108
  .k-modal-body {
@@ -110,22 +110,22 @@
110
110
  flex-direction: column;
111
111
  padding-top: 0.5rem;
112
112
  padding-bottom: 0.5rem;
113
- color: var(--text-color-secondary);
113
+ color: var(--k-text-color-secondary);
114
114
  overflow-y: auto;
115
115
  min-height: 0;
116
116
  flex: 1;
117
117
  }
118
118
 
119
119
  .k-modal-message {
120
- font-size: var(--text-size-lg);
120
+ font-size: var(--k-text-size-lg);
121
121
  font-weight: 600;
122
- color: var(--text-color);
122
+ color: var(--k-text-color);
123
123
  margin-bottom: 1rem;
124
124
  }
125
125
 
126
126
  .k-modal-footer {
127
127
  padding-top: 0.5rem;
128
- border-top: 0.0625rem solid var(--border-color);
128
+ border-top: 0.0625rem solid var(--k-border-color);
129
129
  display: flex;
130
130
  justify-content: end;
131
131
  gap: 0.5rem;
@@ -4,6 +4,10 @@ export {
4
4
  type UseInfiniteReturn,
5
5
  } from "./useInfinite.js";
6
6
  export { default as useInfiniteCursor } from "./useInfiniteCursor.js";
7
+ export {
8
+ default as usePaginated,
9
+ type UsePaginatedReturn,
10
+ } from "./usePaginated.js";
7
11
  export { default as useScrollIntoView } from "./useScrollIntoView.js";
8
12
  export { default as useDebouncedValue } from "./useDebouncedValue.js";
9
13
  export { default as useOutsideClick } from "./useOutsideClick.js";
@@ -18,7 +18,7 @@ interface UseInfiniteOptions {
18
18
  queryKey: string;
19
19
  /** Organization ID to scope cache keys (prevents stale cross-org data) */
20
20
  orgId?: string | null;
21
- /** Initial limit (default: 10) */
21
+ /** Initial limit (default: 25, InfiniteScroll's default page size) */
22
22
  initialLimit?: number;
23
23
  /** Whether or not the query should be enabled */
24
24
  enabled?: boolean;
@@ -29,6 +29,8 @@ export interface UseInfiniteReturn<T> {
29
29
  hasMore: boolean;
30
30
  isLoading: boolean;
31
31
  isReloading: boolean;
32
+ /** The failed request's error, or null; cleared once a load succeeds. */
33
+ error: Error | null;
32
34
  total: number;
33
35
  onQueryChange: (queryString: string) => void;
34
36
  reload: () => void;
@@ -42,7 +44,7 @@ const useInfinite = <T extends { id: number | string }>(
42
44
  endpoint,
43
45
  queryKey,
44
46
  orgId,
45
- initialLimit = 10,
47
+ initialLimit = 25,
46
48
  } = options;
47
49
 
48
50
  const [queryString, setQueryString] = useState(
@@ -139,9 +141,11 @@ const useInfinite = <T extends { id: number | string }>(
139
141
 
140
142
  return {
141
143
  data: allData,
142
- hasMore: query.data?.hasMore ?? true,
144
+ // After a failure, stop offering pages: reload() retries.
145
+ hasMore: query.isError ? false : (query.data?.hasMore ?? true),
143
146
  isLoading: query.isLoading,
144
147
  isReloading: query.isFetching && allData.length > 0,
148
+ error: query.error,
145
149
  total: query.data?.total ?? 0,
146
150
  onQueryChange: handleQueryChange,
147
151
  reload,
@@ -24,7 +24,7 @@ interface UseInfiniteArchivableCursorOptions {
24
24
  queryKey: string | (string | null)[];
25
25
  /** Organization ID to scope cache keys (prevents stale cross-org data). */
26
26
  orgId?: string | null;
27
- /** Initial page size (default: 10). */
27
+ /** Initial page size (default: 25, InfiniteScroll's default). */
28
28
  initialLimit?: number;
29
29
  enabled?: boolean;
30
30
  }
@@ -45,7 +45,7 @@ const useInfiniteArchivableCursor = <T extends { id: number | string }>(
45
45
  endpoint,
46
46
  queryKey,
47
47
  orgId,
48
- initialLimit = 10,
48
+ initialLimit = 25,
49
49
  enabled = true,
50
50
  } = options;
51
51
 
@@ -98,7 +98,10 @@ const useInfiniteArchivableCursor = <T extends { id: number | string }>(
98
98
  // value it passes is meaningless for cursor mode — just fetch the next page.
99
99
  if (normalized === lastQueryRef.current) {
100
100
  const q = queryRef.current;
101
- if (q.hasNextPage && !q.isFetchingNextPage) q.fetchNextPage();
101
+ // cancelRefetch: false joins a request already in flight. The default
102
+ // cancels and resends it, and isFetchingNextPage can't stop that: it's
103
+ // read from a render, so two calls in one tick both see it false.
104
+ if (q.hasNextPage) q.fetchNextPage({ cancelRefetch: false });
102
105
  return;
103
106
  }
104
107
  lastQueryRef.current = normalized;
@@ -127,13 +130,17 @@ const useInfiniteArchivableCursor = <T extends { id: number | string }>(
127
130
  }, [query.data]);
128
131
 
129
132
  const lastPage = query.data?.pages[query.data.pages.length - 1];
130
- const hasMore = lastPage?.hasMore ?? query.hasNextPage ?? false;
133
+ // After a failure, stop offering pages: reload() retries.
134
+ const hasMore = query.isError
135
+ ? false
136
+ : (lastPage?.hasMore ?? query.hasNextPage ?? false);
131
137
 
132
138
  return {
133
139
  data: allData,
134
140
  hasMore,
135
141
  isLoading: query.isLoading,
136
142
  isReloading: query.isRefetching && allData.length > 0,
143
+ error: query.error,
137
144
  total: 0,
138
145
  onQueryChange,
139
146
  reload,
@@ -20,7 +20,7 @@ interface UseInfiniteCursorOptions {
20
20
  queryKey: string;
21
21
  /** Organization ID to scope cache keys (prevents stale cross-org data). */
22
22
  orgId?: string | null;
23
- /** Initial page size (default: 10). */
23
+ /** Initial page size (default: 25, InfiniteScroll's default). */
24
24
  initialLimit?: number;
25
25
  enabled?: boolean;
26
26
  }
@@ -41,7 +41,7 @@ const useInfiniteCursor = <T extends { id: number | string }>(
41
41
  endpoint,
42
42
  queryKey,
43
43
  orgId,
44
- initialLimit = 10,
44
+ initialLimit = 25,
45
45
  enabled = true,
46
46
  } = options;
47
47
 
@@ -80,7 +80,10 @@ const useInfiniteCursor = <T extends { id: number | string }>(
80
80
  // value it passes is meaningless for cursor mode — just trigger fetchNextPage.
81
81
  if (normalized === lastQueryRef.current) {
82
82
  const q = queryRef.current;
83
- if (q.hasNextPage && !q.isFetchingNextPage) q.fetchNextPage();
83
+ // cancelRefetch: false joins a request already in flight. The default
84
+ // cancels and resends it, and isFetchingNextPage can't stop that: it's
85
+ // read from a render, so two calls in one tick both see it false.
86
+ if (q.hasNextPage) q.fetchNextPage({ cancelRefetch: false });
84
87
  return;
85
88
  }
86
89
  lastQueryRef.current = normalized;
@@ -109,13 +112,17 @@ const useInfiniteCursor = <T extends { id: number | string }>(
109
112
  }, [query.data]);
110
113
 
111
114
  const lastPage = query.data?.pages[query.data.pages.length - 1];
112
- const hasMore = lastPage?.hasMore ?? query.hasNextPage ?? false;
115
+ // After a failure, stop offering pages: reload() retries.
116
+ const hasMore = query.isError
117
+ ? false
118
+ : (lastPage?.hasMore ?? query.hasNextPage ?? false);
113
119
 
114
120
  return {
115
121
  data: allData,
116
122
  hasMore,
117
123
  isLoading: query.isLoading,
118
124
  isReloading: query.isRefetching && allData.length > 0,
125
+ error: query.error,
119
126
  total: 0,
120
127
  onQueryChange,
121
128
  reload,
@@ -0,0 +1,123 @@
1
+ "use client";
2
+
3
+ import { keepPreviousData, useQuery } from "@tanstack/react-query";
4
+ import { useCallback, useEffect, useState } from "react";
5
+ import { AxiosInstance } from "axios";
6
+
7
+ interface OffsetPageResponse<T> {
8
+ data: T[];
9
+ total: number;
10
+ }
11
+
12
+ type QueryParams = Record<string, string | number | boolean | undefined>;
13
+
14
+ interface UsePaginatedOptions {
15
+ axiosInstance: AxiosInstance;
16
+ /** API endpoint to fetch from (e.g., "/v1/projects"). It takes `limit` and `offset` and returns `{ data, total }`. */
17
+ endpoint: string;
18
+ /** Query key for React Query caching. */
19
+ queryKey: string;
20
+ /** Organization ID to scope cache keys (prevents stale cross-org data). */
21
+ orgId?: string | null;
22
+ /** Initial page size (default: 10). */
23
+ initialPageSize?: number;
24
+ /** Extra query params such as filters and sort. Changing them returns to page 1. */
25
+ params?: QueryParams;
26
+ enabled?: boolean;
27
+ }
28
+
29
+ export interface UsePaginatedReturn<T> {
30
+ /** The current page's rows. */
31
+ data: T[];
32
+ /** Total matching rows across all pages. */
33
+ total: number;
34
+ /** Current page, starting at 1. */
35
+ page: number;
36
+ pageSize: number;
37
+ pageCount: number;
38
+ setPage: (page: number) => void;
39
+ /** Changes the page size and returns to page 1. */
40
+ setPageSize: (pageSize: number) => void;
41
+ /** True until the first page arrives. */
42
+ isLoading: boolean;
43
+ /** True whenever a page is loading, including after the first. */
44
+ isFetching: boolean;
45
+ error: Error | null;
46
+ refetch: () => void;
47
+ }
48
+
49
+ /**
50
+ * One page at a time from an offset endpoint (`limit` + `offset` in,
51
+ * `{ data, total }` out), for `Pagination`. The previous page stays on screen
52
+ * while the next one loads. Use `useInfiniteCursor` for `InfiniteScroll`.
53
+ */
54
+ const usePaginated = <T>(
55
+ options: UsePaginatedOptions
56
+ ): UsePaginatedReturn<T> => {
57
+ const {
58
+ axiosInstance,
59
+ endpoint,
60
+ queryKey,
61
+ orgId,
62
+ initialPageSize = 10,
63
+ params,
64
+ enabled = true,
65
+ } = options;
66
+
67
+ const [page, setPage] = useState(1);
68
+ const [pageSize, setPageSizeState] = useState(initialPageSize);
69
+
70
+ // New filters or sort make the old page number meaningless.
71
+ const paramsKey = JSON.stringify(params ?? {});
72
+ const [prevParamsKey, setPrevParamsKey] = useState(paramsKey);
73
+ if (paramsKey !== prevParamsKey) {
74
+ setPrevParamsKey(paramsKey);
75
+ setPage(1);
76
+ }
77
+
78
+ const query = useQuery<OffsetPageResponse<T>, Error>({
79
+ queryKey: [`${queryKey}-paged`, orgId ?? null, paramsKey, page, pageSize],
80
+ enabled,
81
+ placeholderData: keepPreviousData,
82
+ queryFn: async () => {
83
+ const res = await axiosInstance.get<OffsetPageResponse<T>>(endpoint, {
84
+ params: { ...params, limit: pageSize, offset: (page - 1) * pageSize },
85
+ });
86
+ return res.data;
87
+ },
88
+ });
89
+
90
+ const total = query.data?.total ?? 0;
91
+ const pageCount = Math.max(1, Math.ceil(total / pageSize));
92
+
93
+ // Rows deleted from the last page can leave it empty; step back.
94
+ useEffect(() => {
95
+ if (query.data && !query.isPlaceholderData && page > pageCount) {
96
+ setPage(pageCount);
97
+ }
98
+ }, [query.data, query.isPlaceholderData, page, pageCount]);
99
+
100
+ const setPageSize = useCallback((size: number) => {
101
+ setPageSizeState(size);
102
+ setPage(1);
103
+ }, []);
104
+
105
+ const { refetch } = query;
106
+ const refetchPage = useCallback(() => void refetch(), [refetch]);
107
+
108
+ return {
109
+ data: query.data?.data ?? [],
110
+ total,
111
+ page,
112
+ pageSize,
113
+ pageCount,
114
+ setPage,
115
+ setPageSize,
116
+ isLoading: query.isLoading,
117
+ isFetching: query.isFetching,
118
+ error: query.error,
119
+ refetch: refetchPage,
120
+ };
121
+ };
122
+
123
+ export default usePaginated;