@takaro/lib-components 0.0.0-next.0da151e

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 (430) hide show
  1. package/.babelrc +7 -0
  2. package/@types/files.d.ts +23 -0
  3. package/@types/react-table-config.d.ts +121 -0
  4. package/Dockerfile.dev +21 -0
  5. package/package.json +15 -0
  6. package/public/images/7-days-to-die/logo.png +0 -0
  7. package/public/images/csmm-icon.png +0 -0
  8. package/public/images/milk.png +0 -0
  9. package/public/images/placeholder-01.jpeg +0 -0
  10. package/public/images/placeholder-02.jpeg +0 -0
  11. package/public/images/placeholder-03.jpeg +0 -0
  12. package/public/images/rust/logo.png +0 -0
  13. package/readme.md +10 -0
  14. package/src/components/actions/Button/Button.stories.tsx +149 -0
  15. package/src/components/actions/Button/Button.test.tsx +8 -0
  16. package/src/components/actions/Button/Button.test.tsx.snap +89 -0
  17. package/src/components/actions/Button/__snapshots__/Button.test.tsx.snap +18 -0
  18. package/src/components/actions/Button/index.tsx +89 -0
  19. package/src/components/actions/Button/style.ts +142 -0
  20. package/src/components/actions/ContextMenu/ContextMenu.stories.tsx +41 -0
  21. package/src/components/actions/ContextMenu/Group.tsx +34 -0
  22. package/src/components/actions/ContextMenu/MenuItem.tsx +69 -0
  23. package/src/components/actions/ContextMenu/index.tsx +216 -0
  24. package/src/components/actions/Dropdown/Dropdown.stories.tsx +88 -0
  25. package/src/components/actions/Dropdown/DropdownContext.tsx +21 -0
  26. package/src/components/actions/Dropdown/DropdownMenu.tsx +70 -0
  27. package/src/components/actions/Dropdown/DropdownMenuGroup.tsx +37 -0
  28. package/src/components/actions/Dropdown/DropdownMenuItem.tsx +128 -0
  29. package/src/components/actions/Dropdown/DropdownTrigger.tsx +87 -0
  30. package/src/components/actions/Dropdown/index.tsx +22 -0
  31. package/src/components/actions/Dropdown/useDropdown.tsx +89 -0
  32. package/src/components/actions/DropdownButton/DropdownButton.stories.tsx +88 -0
  33. package/src/components/actions/DropdownButton/index.tsx +128 -0
  34. package/src/components/actions/IconButton/IconButton.stories.tsx +54 -0
  35. package/src/components/actions/IconButton/IconButton.test.tsx +8 -0
  36. package/src/components/actions/IconButton/IconButton.test.tsx.snap +46 -0
  37. package/src/components/actions/IconButton/__snapshots__/IconButton.test.tsx.snap +18 -0
  38. package/src/components/actions/IconButton/getIconSize.ts +16 -0
  39. package/src/components/actions/IconButton/index.tsx +28 -0
  40. package/src/components/actions/IconButton/style.ts +51 -0
  41. package/src/components/actions/ToggleButton/ToggleButton.stories.tsx +85 -0
  42. package/src/components/actions/ToggleButton/ToggleButton.tsx +48 -0
  43. package/src/components/actions/ToggleButton/ToggleButtonGroup.tsx +107 -0
  44. package/src/components/actions/ToggleButton/index.tsx +2 -0
  45. package/src/components/actions/ToggleButton/style.ts +75 -0
  46. package/src/components/actions/index.ts +16 -0
  47. package/src/components/charts/AreaChart/AreaChart.stories.tsx +103 -0
  48. package/src/components/charts/AreaChart/index.tsx +428 -0
  49. package/src/components/charts/BarChart/BarChart.stories.tsx +55 -0
  50. package/src/components/charts/BarChart/index.tsx +420 -0
  51. package/src/components/charts/BrushHandle.tsx +21 -0
  52. package/src/components/charts/EmptyChart.tsx +45 -0
  53. package/src/components/charts/GeoMercator/GeoMercator.stories.tsx +77 -0
  54. package/src/components/charts/GeoMercator/index.tsx +228 -0
  55. package/src/components/charts/GeoMercator/iso3166-alpha2-to-alpha3.ts +250 -0
  56. package/src/components/charts/GeoMercator/world.d.ts +1 -0
  57. package/src/components/charts/GeoMercator/world.json +99818 -0
  58. package/src/components/charts/Heatmap/Heatmap.stories.tsx +189 -0
  59. package/src/components/charts/Heatmap/index.tsx +461 -0
  60. package/src/components/charts/LineChart/LineChart.stories.tsx +111 -0
  61. package/src/components/charts/LineChart/index.tsx +353 -0
  62. package/src/components/charts/PieChart/PieChart.stories.tsx +151 -0
  63. package/src/components/charts/PieChart/index.tsx +457 -0
  64. package/src/components/charts/PointHighlight.tsx +49 -0
  65. package/src/components/charts/RadarChart/RadarChart.stories.tsx +47 -0
  66. package/src/components/charts/RadarChart/generators.ts +30 -0
  67. package/src/components/charts/RadarChart/index.tsx +224 -0
  68. package/src/components/charts/RadialBarChart/RadialBarChart.stories.tsx +59 -0
  69. package/src/components/charts/RadialBarChart/index.tsx +231 -0
  70. package/src/components/charts/RadialLineChart/RadialLineChart.stories.tsx +43 -0
  71. package/src/components/charts/RadialLineChart/index.tsx +231 -0
  72. package/src/components/charts/ZoomControls.tsx +49 -0
  73. package/src/components/charts/index.tsx +26 -0
  74. package/src/components/charts/useGradients.tsx +37 -0
  75. package/src/components/charts/util.ts +78 -0
  76. package/src/components/data/Avatar/Avatar.stories.tsx +93 -0
  77. package/src/components/data/Avatar/context.tsx +20 -0
  78. package/src/components/data/Avatar/index.tsx +136 -0
  79. package/src/components/data/Avatar/style.ts +124 -0
  80. package/src/components/data/Avatar/useImageLoadingStatus.tsx +32 -0
  81. package/src/components/data/Chip/Chip.stories.tsx +67 -0
  82. package/src/components/data/Chip/Chip.test.tsx +8 -0
  83. package/src/components/data/Chip/Chip.test.tsx.snap +50 -0
  84. package/src/components/data/Chip/__snapshots__/Chip.test.tsx.snap +38 -0
  85. package/src/components/data/Chip/index.tsx +67 -0
  86. package/src/components/data/Chip/style.ts +49 -0
  87. package/src/components/data/Console/Console.stories.tsx +51 -0
  88. package/src/components/data/Console/Console.tsx +125 -0
  89. package/src/components/data/Console/ConsoleInput/index.tsx +87 -0
  90. package/src/components/data/Console/ConsoleInput/style.ts +41 -0
  91. package/src/components/data/Console/ConsoleLine/index.tsx +127 -0
  92. package/src/components/data/Console/ConsoleLine/style.ts +76 -0
  93. package/src/components/data/Console/MessageModel.ts +9 -0
  94. package/src/components/data/Console/constants.ts +6 -0
  95. package/src/components/data/Console/index.tsx +4 -0
  96. package/src/components/data/Console/style.ts +31 -0
  97. package/src/components/data/Console/useConsoleLiveMode.ts +42 -0
  98. package/src/components/data/CopyId/CopyId.stories.tsx +36 -0
  99. package/src/components/data/CopyId/index.tsx +107 -0
  100. package/src/components/data/CountryList/index.tsx +146 -0
  101. package/src/components/data/DateFormatter/DateFormatter.stories.tsx +26 -0
  102. package/src/components/data/DateFormatter/index.tsx +15 -0
  103. package/src/components/data/Drawer/Drawer.stories.tsx +155 -0
  104. package/src/components/data/Drawer/DrawerBody.tsx +22 -0
  105. package/src/components/data/Drawer/DrawerContent.tsx +169 -0
  106. package/src/components/data/Drawer/DrawerContext.tsx +21 -0
  107. package/src/components/data/Drawer/DrawerFooter.tsx +19 -0
  108. package/src/components/data/Drawer/DrawerHeading.tsx +50 -0
  109. package/src/components/data/Drawer/DrawerSkeleton.tsx +29 -0
  110. package/src/components/data/Drawer/index.tsx +25 -0
  111. package/src/components/data/Drawer/useDrawer.tsx +66 -0
  112. package/src/components/data/InfiniteScroll/InfiniteScroll.stories.tsx +33 -0
  113. package/src/components/data/InfiniteScroll/index.tsx +54 -0
  114. package/src/components/data/Stats/Sparkline.tsx +48 -0
  115. package/src/components/data/Stats/Stat.tsx +192 -0
  116. package/src/components/data/Stats/Stats.stories.tsx +196 -0
  117. package/src/components/data/Stats/context.tsx +18 -0
  118. package/src/components/data/Stats/index.tsx +62 -0
  119. package/src/components/data/Table/Table.stories.tsx +146 -0
  120. package/src/components/data/Table/index.tsx +492 -0
  121. package/src/components/data/Table/react-table.d.ts +14 -0
  122. package/src/components/data/Table/style.ts +97 -0
  123. package/src/components/data/Table/subcomponents/ColumnHeader/ColumnSettings.tsx +164 -0
  124. package/src/components/data/Table/subcomponents/ColumnHeader/index.tsx +207 -0
  125. package/src/components/data/Table/subcomponents/ColumnHeader/style.ts +90 -0
  126. package/src/components/data/Table/subcomponents/ColumnVisibility/index.tsx +70 -0
  127. package/src/components/data/Table/subcomponents/Filter/field.tsx +127 -0
  128. package/src/components/data/Table/subcomponents/Filter/index.tsx +228 -0
  129. package/src/components/data/Table/subcomponents/Filter/style.ts +26 -0
  130. package/src/components/data/Table/subcomponents/Filter/types.ts +10 -0
  131. package/src/components/data/Table/subcomponents/Pagination/PagePicker.tsx +109 -0
  132. package/src/components/data/Table/subcomponents/Pagination/PageSizeSelect.tsx +37 -0
  133. package/src/components/data/Table/subcomponents/Pagination/style.ts +49 -0
  134. package/src/components/data/index.ts +28 -0
  135. package/src/components/dialogs/Dialog/Dialog.stories.tsx +77 -0
  136. package/src/components/dialogs/Dialog/DialogBody.tsx +64 -0
  137. package/src/components/dialogs/Dialog/DialogContent.tsx +44 -0
  138. package/src/components/dialogs/Dialog/DialogContext.tsx +21 -0
  139. package/src/components/dialogs/Dialog/DialogHeading.tsx +56 -0
  140. package/src/components/dialogs/Dialog/index.tsx +20 -0
  141. package/src/components/dialogs/Dialog/useDialog.tsx +50 -0
  142. package/src/components/feedback/Alert/Alert.stories.tsx +75 -0
  143. package/src/components/feedback/Alert/Alert.test.tsx +8 -0
  144. package/src/components/feedback/Alert/Alert.test.tsx.snap +146 -0
  145. package/src/components/feedback/Alert/__snapshots__/Alert.test.tsx.snap +44 -0
  146. package/src/components/feedback/Alert/index.tsx +120 -0
  147. package/src/components/feedback/Alert/style.ts +97 -0
  148. package/src/components/feedback/Badge/Badge.stories.tsx +23 -0
  149. package/src/components/feedback/Badge/index.tsx +47 -0
  150. package/src/components/feedback/ErrorFallback/ErrorFallback.stories.tsx +10 -0
  151. package/src/components/feedback/ErrorFallback/index.tsx +49 -0
  152. package/src/components/feedback/ErrorPage/ErrorPage.stories.tsx +31 -0
  153. package/src/components/feedback/ErrorPage/index.tsx +193 -0
  154. package/src/components/feedback/FormError/FormError.stories.tsx +25 -0
  155. package/src/components/feedback/FormError/index.tsx +54 -0
  156. package/src/components/feedback/IconTooltip/IconTooltip.stories.tsx +22 -0
  157. package/src/components/feedback/IconTooltip/index.tsx +51 -0
  158. package/src/components/feedback/Loaders/Loaders.stories.tsx +28 -0
  159. package/src/components/feedback/Loaders/Loading.test.tsx +8 -0
  160. package/src/components/feedback/Loaders/Loading.test.tsx.snap +141 -0
  161. package/src/components/feedback/Loaders/Loading.tsx +107 -0
  162. package/src/components/feedback/Loaders/Spinner.test.tsx +8 -0
  163. package/src/components/feedback/Loaders/Spinner.test.tsx.snap +18 -0
  164. package/src/components/feedback/Loaders/Spinner.tsx +74 -0
  165. package/src/components/feedback/Loaders/__snapshots__/Loading.test.tsx.snap +141 -0
  166. package/src/components/feedback/Loaders/__snapshots__/Spinner.test.tsx.snap +10 -0
  167. package/src/components/feedback/Loaders/index.ts +2 -0
  168. package/src/components/feedback/NetworkDetector/NetworkDetector.stories.tsx +21 -0
  169. package/src/components/feedback/NetworkDetector/NetworkDetector.test.tsx +8 -0
  170. package/src/components/feedback/NetworkDetector/NetworkDetector.test.tsx.snap +3 -0
  171. package/src/components/feedback/NetworkDetector/__snapshots__/NetworkDetector.test.tsx.snap +3 -0
  172. package/src/components/feedback/NetworkDetector/index.tsx +41 -0
  173. package/src/components/feedback/NotificationBanner/NotificationBanner.stories.tsx +13 -0
  174. package/src/components/feedback/NotificationBanner/NotificationBanner.test.tsx +15 -0
  175. package/src/components/feedback/NotificationBanner/NotificationBanner.test.tsx.snap +3 -0
  176. package/src/components/feedback/NotificationBanner/__snapshots__/NotificationBanner.test.tsx.snap +3 -0
  177. package/src/components/feedback/NotificationBanner/index.tsx +78 -0
  178. package/src/components/feedback/Popover/Popover.stories.tsx +33 -0
  179. package/src/components/feedback/Popover/PopoverContent.tsx +46 -0
  180. package/src/components/feedback/Popover/PopoverContext.tsx +21 -0
  181. package/src/components/feedback/Popover/PopoverTrigger.tsx +45 -0
  182. package/src/components/feedback/Popover/index.tsx +22 -0
  183. package/src/components/feedback/Popover/usePopover.tsx +87 -0
  184. package/src/components/feedback/ProgressBar/ProgressBar.stories.tsx +38 -0
  185. package/src/components/feedback/ProgressBar/index.tsx +137 -0
  186. package/src/components/feedback/Skeleton/Skeleton.stories.tsx +33 -0
  187. package/src/components/feedback/Skeleton/Skeleton.test.tsx +8 -0
  188. package/src/components/feedback/Skeleton/Skeleton.test.tsx.snap +35 -0
  189. package/src/components/feedback/Skeleton/__snapshots__/Skeleton.test.tsx.snap +9 -0
  190. package/src/components/feedback/Skeleton/index.tsx +62 -0
  191. package/src/components/feedback/Tooltip/Tooltip.stories.tsx +69 -0
  192. package/src/components/feedback/Tooltip/TooltipContent.tsx +51 -0
  193. package/src/components/feedback/Tooltip/TooltipContext.tsx +13 -0
  194. package/src/components/feedback/Tooltip/TooltipTrigger.tsx +39 -0
  195. package/src/components/feedback/Tooltip/index.tsx +26 -0
  196. package/src/components/feedback/Tooltip/useTooltip.tsx +82 -0
  197. package/src/components/feedback/index.ts +37 -0
  198. package/src/components/feedback/snacks/CookieConsent/index.tsx +125 -0
  199. package/src/components/feedback/snacks/CookieConsent/style.ts +99 -0
  200. package/src/components/feedback/snacks/Default/default.stories.tsx +73 -0
  201. package/src/components/feedback/snacks/Default/index.tsx +78 -0
  202. package/src/components/feedback/snacks/Default/style.ts +58 -0
  203. package/src/components/feedback/snacks/Drawer/Drawer.stories.tsx +46 -0
  204. package/src/components/feedback/snacks/Drawer/index.tsx +85 -0
  205. package/src/components/feedback/snacks/NetworkDetector/index.tsx +73 -0
  206. package/src/components/feedback/snacks/index.d.ts +15 -0
  207. package/src/components/feedback/snacks/index.ts +8 -0
  208. package/src/components/index.ts +9 -0
  209. package/src/components/inputs/CheckBox/CheckBox.stories.tsx +64 -0
  210. package/src/components/inputs/CheckBox/Controlled.tsx +123 -0
  211. package/src/components/inputs/CheckBox/Generic.tsx +42 -0
  212. package/src/components/inputs/CheckBox/index.tsx +4 -0
  213. package/src/components/inputs/CheckBox/style.ts +56 -0
  214. package/src/components/inputs/CodeField/CodeField.stories.tsx +86 -0
  215. package/src/components/inputs/CodeField/index.tsx +174 -0
  216. package/src/components/inputs/CodeField/style.ts +50 -0
  217. package/src/components/inputs/Date/DatePicker/Controlled.tsx +103 -0
  218. package/src/components/inputs/Date/DatePicker/DatePicker.stories.tsx +267 -0
  219. package/src/components/inputs/Date/DatePicker/Generic.tsx +283 -0
  220. package/src/components/inputs/Date/DatePicker/formats.tsx +32 -0
  221. package/src/components/inputs/Date/DatePicker/style.ts +41 -0
  222. package/src/components/inputs/Date/DateRangePicker/Context.tsx +123 -0
  223. package/src/components/inputs/Date/DateRangePicker/Controlled.tsx +74 -0
  224. package/src/components/inputs/Date/DateRangePicker/DateRangePicker.stories.tsx +37 -0
  225. package/src/components/inputs/Date/DateRangePicker/DateSelector/Absolute.tsx +98 -0
  226. package/src/components/inputs/Date/DateRangePicker/DateSelector/Relative.tsx +54 -0
  227. package/src/components/inputs/Date/DateRangePicker/DateSelector/index.tsx +49 -0
  228. package/src/components/inputs/Date/DateRangePicker/Generic.tsx +167 -0
  229. package/src/components/inputs/Date/DateRangePicker/QuickSelect/index.tsx +254 -0
  230. package/src/components/inputs/Date/DateRangePicker/QuickSelect/style.ts +40 -0
  231. package/src/components/inputs/Date/DateRangePicker/style.ts +65 -0
  232. package/src/components/inputs/Date/subcomponents/Calendar/index.tsx +150 -0
  233. package/src/components/inputs/Date/subcomponents/Calendar/style.ts +61 -0
  234. package/src/components/inputs/Date/subcomponents/RelativePicker/index.tsx +170 -0
  235. package/src/components/inputs/Date/subcomponents/RelativePicker/style.ts +50 -0
  236. package/src/components/inputs/Date/subcomponents/TimePicker/TimePicker.stories.tsx +25 -0
  237. package/src/components/inputs/Date/subcomponents/TimePicker/index.tsx +40 -0
  238. package/src/components/inputs/Date/subcomponents/TimePicker/style.ts +34 -0
  239. package/src/components/inputs/Date/types.ts +14 -0
  240. package/src/components/inputs/DurationField/Controlled.tsx +69 -0
  241. package/src/components/inputs/DurationField/Duration.stories.tsx +57 -0
  242. package/src/components/inputs/DurationField/Generic.tsx +197 -0
  243. package/src/components/inputs/DurationField/__tests__/Generic.test.tsx +12 -0
  244. package/src/components/inputs/DurationField/index.tsx +5 -0
  245. package/src/components/inputs/DurationField/style.ts +42 -0
  246. package/src/components/inputs/EditableField/EditableField.stories.tsx +65 -0
  247. package/src/components/inputs/EditableField/index.tsx +135 -0
  248. package/src/components/inputs/EditableField/style.ts +11 -0
  249. package/src/components/inputs/FileField/Controlled.tsx +104 -0
  250. package/src/components/inputs/FileField/FileField.stories.tsx +210 -0
  251. package/src/components/inputs/FileField/Generic.tsx +133 -0
  252. package/src/components/inputs/FileField/index.tsx +5 -0
  253. package/src/components/inputs/FileField/style.ts +34 -0
  254. package/src/components/inputs/InputProps.ts +59 -0
  255. package/src/components/inputs/RadioGroup/Controlled.tsx +45 -0
  256. package/src/components/inputs/RadioGroup/Generic.tsx +34 -0
  257. package/src/components/inputs/RadioGroup/RadioGroup.stories.tsx +118 -0
  258. package/src/components/inputs/RadioGroup/RadioItem.tsx +130 -0
  259. package/src/components/inputs/RadioGroup/context.tsx +20 -0
  260. package/src/components/inputs/RadioGroup/index.ts +5 -0
  261. package/src/components/inputs/RadioGroup/style.ts +3 -0
  262. package/src/components/inputs/Switch/Controlled.tsx +57 -0
  263. package/src/components/inputs/Switch/Generic.tsx +40 -0
  264. package/src/components/inputs/Switch/Switch.stories.tsx +89 -0
  265. package/src/components/inputs/Switch/index.ts +5 -0
  266. package/src/components/inputs/Switch/style.ts +62 -0
  267. package/src/components/inputs/TagField/Controlled.tsx +103 -0
  268. package/src/components/inputs/TagField/Generic.tsx +138 -0
  269. package/src/components/inputs/TagField/TagField.stories.tsx +68 -0
  270. package/src/components/inputs/TagField/index.ts +5 -0
  271. package/src/components/inputs/TagField/style.ts +25 -0
  272. package/src/components/inputs/TagField/util.ts +34 -0
  273. package/src/components/inputs/TextAreaField/Controlled.tsx +101 -0
  274. package/src/components/inputs/TextAreaField/Generic.tsx +58 -0
  275. package/src/components/inputs/TextAreaField/TextAreaField.stories.tsx +99 -0
  276. package/src/components/inputs/TextAreaField/index.ts +5 -0
  277. package/src/components/inputs/TextAreaField/style.ts +28 -0
  278. package/src/components/inputs/TextField/Controlled.tsx +120 -0
  279. package/src/components/inputs/TextField/Generic.tsx +138 -0
  280. package/src/components/inputs/TextField/TextField.stories.tsx +217 -0
  281. package/src/components/inputs/TextField/index.ts +5 -0
  282. package/src/components/inputs/TextField/style.ts +103 -0
  283. package/src/components/inputs/TextField/util.ts +24 -0
  284. package/src/components/inputs/ValueConfirmationField/ValueConfirmationField.stories.tsx +33 -0
  285. package/src/components/inputs/ValueConfirmationField/index.tsx +54 -0
  286. package/src/components/inputs/index.ts +72 -0
  287. package/src/components/inputs/layout/Description.tsx +33 -0
  288. package/src/components/inputs/layout/ErrorMessage/ErrorMessage.stories.tsx +28 -0
  289. package/src/components/inputs/layout/ErrorMessage/index.tsx +63 -0
  290. package/src/components/inputs/layout/InputWrapper.ts +6 -0
  291. package/src/components/inputs/layout/Label/index.tsx +71 -0
  292. package/src/components/inputs/layout/Label/style.ts +50 -0
  293. package/src/components/inputs/layout/index.ts +8 -0
  294. package/src/components/inputs/layout/setAriaDescribedBy.ts +3 -0
  295. package/src/components/inputs/selects/SelectField/Controlled.tsx +127 -0
  296. package/src/components/inputs/selects/SelectField/Generic/FilterInput.tsx +48 -0
  297. package/src/components/inputs/selects/SelectField/Generic/index.tsx +299 -0
  298. package/src/components/inputs/selects/SelectField/SelectField.stories.tsx +252 -0
  299. package/src/components/inputs/selects/SelectField/index.ts +5 -0
  300. package/src/components/inputs/selects/SelectField/style.ts +29 -0
  301. package/src/components/inputs/selects/SelectQueryField/Controlled.tsx +110 -0
  302. package/src/components/inputs/selects/SelectQueryField/Generic/index.tsx +401 -0
  303. package/src/components/inputs/selects/SelectQueryField/SelectQueryField.stories.tsx +280 -0
  304. package/src/components/inputs/selects/SelectQueryField/index.tsx +5 -0
  305. package/src/components/inputs/selects/SelectQueryField/style.ts +13 -0
  306. package/src/components/inputs/selects/SubComponents/Option.tsx +114 -0
  307. package/src/components/inputs/selects/SubComponents/OptionGroup.tsx +18 -0
  308. package/src/components/inputs/selects/SubComponents/index.ts +10 -0
  309. package/src/components/inputs/selects/SubComponents/style.ts +51 -0
  310. package/src/components/inputs/selects/data.ts +123 -0
  311. package/src/components/inputs/selects/index.tsx +49 -0
  312. package/src/components/inputs/selects/sharedStyle.ts +76 -0
  313. package/src/components/layout/Container/index.ts +21 -0
  314. package/src/components/layout/index.ts +1 -0
  315. package/src/components/navigation/HorizontalNav/HorizontalNav.stories.tsx +29 -0
  316. package/src/components/navigation/HorizontalNav/index.tsx +13 -0
  317. package/src/components/navigation/HorizontalNav/style.ts +93 -0
  318. package/src/components/navigation/IconNav/IconNav.stories.tsx +46 -0
  319. package/src/components/navigation/IconNav/index.tsx +50 -0
  320. package/src/components/navigation/Steppers/SlimStepper/Stepper.stories.tsx +90 -0
  321. package/src/components/navigation/Steppers/SlimStepper/index.tsx +104 -0
  322. package/src/components/navigation/Steppers/SlimStepper/style.ts +85 -0
  323. package/src/components/navigation/Steppers/Stepper/Stepper.stories.tsx +88 -0
  324. package/src/components/navigation/Steppers/Stepper/index.tsx +114 -0
  325. package/src/components/navigation/Steppers/Stepper/style.ts +106 -0
  326. package/src/components/navigation/Steppers/context.tsx +2 -0
  327. package/src/components/navigation/Steppers/provider.tsx +18 -0
  328. package/src/components/navigation/Steppers/reducer.ts +51 -0
  329. package/src/components/navigation/Steppers/stepStates.ts +5 -0
  330. package/src/components/navigation/Steppers/useStepper.ts +34 -0
  331. package/src/components/navigation/Tabs/Content.tsx +39 -0
  332. package/src/components/navigation/Tabs/Context.tsx +21 -0
  333. package/src/components/navigation/Tabs/List.tsx +17 -0
  334. package/src/components/navigation/Tabs/Tabs.stories.tsx +119 -0
  335. package/src/components/navigation/Tabs/Trigger.tsx +66 -0
  336. package/src/components/navigation/Tabs/index.tsx +35 -0
  337. package/src/components/navigation/Tabs/useTabs.tsx +28 -0
  338. package/src/components/navigation/index.ts +17 -0
  339. package/src/components/other/ActionMenu/ActionMenu.stories.tsx +81 -0
  340. package/src/components/other/ActionMenu/index.tsx +62 -0
  341. package/src/components/other/ActionMenu/style.ts +47 -0
  342. package/src/components/other/ClipBoard/ClipBoard.stories.tsx +14 -0
  343. package/src/components/other/ClipBoard/ClipBoard.test.tsx +8 -0
  344. package/src/components/other/ClipBoard/ClipBoard.test.tsx.snap +70 -0
  345. package/src/components/other/ClipBoard/__snapshots__/ClipBoard.test.tsx.snap +36 -0
  346. package/src/components/other/ClipBoard/index.tsx +70 -0
  347. package/src/components/other/CollapseList/CollapseList.stories.tsx +21 -0
  348. package/src/components/other/CollapseList/index.tsx +110 -0
  349. package/src/components/other/Collapsible/Collapsible.stories.tsx +19 -0
  350. package/src/components/other/Collapsible/CollapsibleContent.tsx +29 -0
  351. package/src/components/other/Collapsible/CollapsibleContext.tsx +17 -0
  352. package/src/components/other/Collapsible/CollapsibleTrigger.tsx +83 -0
  353. package/src/components/other/Collapsible/index.tsx +21 -0
  354. package/src/components/other/Company/index.tsx +44 -0
  355. package/src/components/other/Company/style.ts +58 -0
  356. package/src/components/other/Empty/Empty.stories.tsx +28 -0
  357. package/src/components/other/Empty/Empty.test.tsx +10 -0
  358. package/src/components/other/Empty/Empty.test.tsx.snap +85 -0
  359. package/src/components/other/Empty/__snapshots__/Empty.test.tsx.snap +21 -0
  360. package/src/components/other/Empty/index.tsx +85 -0
  361. package/src/components/other/PermissionsGuard/PermissionsGuard.stories.tsx +55 -0
  362. package/src/components/other/PermissionsGuard/hasPermissionsHelper.ts +18 -0
  363. package/src/components/other/PermissionsGuard/index.tsx +27 -0
  364. package/src/components/other/Plan/Plan.stories.tsx +21 -0
  365. package/src/components/other/Plan/index.tsx +92 -0
  366. package/src/components/other/Plan/style.ts +61 -0
  367. package/src/components/other/Usage/Usage.stories.tsx +21 -0
  368. package/src/components/other/Usage/Usage.tsx +35 -0
  369. package/src/components/other/Usage/UsageCard.stories.tsx +31 -0
  370. package/src/components/other/Usage/UsageCard.tsx +88 -0
  371. package/src/components/other/index.ts +27 -0
  372. package/src/components/visual/Card/Card.stories.tsx +22 -0
  373. package/src/components/visual/Card/CardBody.tsx +11 -0
  374. package/src/components/visual/Card/CardTitle.tsx +29 -0
  375. package/src/components/visual/Card/index.tsx +58 -0
  376. package/src/components/visual/Divider/Divider.stories.tsx +19 -0
  377. package/src/components/visual/Divider/Divider.test.tsx +8 -0
  378. package/src/components/visual/Divider/Divider.test.tsx.snap +35 -0
  379. package/src/components/visual/Divider/__snapshots__/Divider.test.tsx.snap +13 -0
  380. package/src/components/visual/Divider/index.tsx +88 -0
  381. package/src/components/visual/Flag/index.tsx +61 -0
  382. package/src/components/visual/index.ts +8 -0
  383. package/src/errors/base.ts +14 -0
  384. package/src/errors/errors.ts +126 -0
  385. package/src/errors/index.ts +14 -0
  386. package/src/helpers/camelCaseToSpaces.ts +5 -0
  387. package/src/helpers/formatNumber.ts +6 -0
  388. package/src/helpers/getInitials.ts +16 -0
  389. package/src/helpers/getSnackbarProvider.tsx +57 -0
  390. package/src/helpers/getTransition.ts +9 -0
  391. package/src/helpers/index.ts +6 -0
  392. package/src/helpers/makeData.ts +34 -0
  393. package/src/helpers/regexprs.ts +9 -0
  394. package/src/hooks/index.ts +9 -0
  395. package/src/hooks/useCallbackRef.tsx +17 -0
  396. package/src/hooks/useDebounce.tsx +22 -0
  397. package/src/hooks/useFocus.tsx +12 -0
  398. package/src/hooks/useLocalStorage.tsx +35 -0
  399. package/src/hooks/useLockScroll.ts +26 -0
  400. package/src/hooks/useOnScreen.ts +24 -0
  401. package/src/hooks/useOutsideAlerter.tsx +15 -0
  402. package/src/hooks/useTableActions.ts +61 -0
  403. package/src/hooks/useTheme.tsx +7 -0
  404. package/src/images/company-icon-primary.svg +3 -0
  405. package/src/images/company-icon-secondary.svg +3 -0
  406. package/src/images/index.ts +4 -0
  407. package/src/index.ts +9 -0
  408. package/src/stories/Colors.mdx +35 -0
  409. package/src/stories/Introduction.mdx +17 -0
  410. package/src/stories/Spacing.mdx +25 -0
  411. package/src/styled/GlobalStyle.ts +209 -0
  412. package/src/styled/Snackbar.tsx +41 -0
  413. package/src/styled/animations.ts +36 -0
  414. package/src/styled/breakpoint.ts +7 -0
  415. package/src/styled/device.ts +10 -0
  416. package/src/styled/index.ts +10 -0
  417. package/src/styled/spacing.ts +38 -0
  418. package/src/styled/theme.tsx +110 -0
  419. package/src/styled/types.ts +5 -0
  420. package/src/styled/zIndex.ts +31 -0
  421. package/src/test/__mocks__/fileMock.ts +2 -0
  422. package/src/test/setupTests.ts +3 -0
  423. package/src/test/snapshotResolver.js +21 -0
  424. package/src/test/testUtils.tsx +34 -0
  425. package/src/types/index.ts +1 -0
  426. package/src/types/json.ts +5 -0
  427. package/src/views/LoadingPage.tsx +36 -0
  428. package/src/views/index.ts +1 -0
  429. package/tsconfig.json +14 -0
  430. package/vite.config.mts +17 -0
@@ -0,0 +1,401 @@
1
+ import {
2
+ forwardRef,
3
+ useEffect,
4
+ useRef,
5
+ useState,
6
+ Children,
7
+ PropsWithChildren,
8
+ isValidElement,
9
+ cloneElement,
10
+ useMemo,
11
+ MouseEvent,
12
+ } from 'react';
13
+ import {
14
+ autoUpdate,
15
+ FloatingFocusManager,
16
+ FloatingPortal,
17
+ size,
18
+ useDismiss,
19
+ flip,
20
+ useFloating,
21
+ useInteractions,
22
+ useRole,
23
+ offset,
24
+ useClick,
25
+ } from '@floating-ui/react';
26
+ import { AiOutlineSearch as SearchIcon, AiOutlineClose as ClearIcon } from 'react-icons/ai';
27
+ import { defaultInputProps, defaultInputPropsFactory, GenericInputPropsFunctionHandlers } from '../../../InputProps';
28
+ import { useDebounce } from '../../../../../hooks';
29
+ import { setAriaDescribedBy } from '../../../layout';
30
+ import { FeedBackContainer } from '../style';
31
+ import { SelectItem, SelectContext, getLabelFromChildren } from '../../';
32
+ import { PaginationProps } from '../../../';
33
+
34
+ /* The SearchField depends on a few things of <Select/> */
35
+ import { GroupLabel } from '../../SelectField/style';
36
+ import { SelectContainer, SelectButton, StyledArrowIcon } from '../../sharedStyle';
37
+ import { IconButton, InfiniteScroll, Spinner } from '../../../../../components';
38
+ import { GenericTextField } from '../../../TextField/Generic';
39
+ import { Option, OptionGroup, SubComponentTypes } from '../../SubComponents';
40
+
41
+ interface SharedSelectQueryFieldProps extends PaginationProps {
42
+ // Enables loading data feedback for user
43
+ isLoadingData?: boolean;
44
+ /// The placeholder text to show when the input is empty
45
+ placeholder?: string;
46
+ /// Debounce time in milliseconds (when clientside data it should be 0)
47
+ debounce?: number;
48
+ /// Triggered whenever the input value changes.
49
+ /// This is used to trigger the API call to get the new options
50
+ handleInputValueChange?: (value: string) => void;
51
+
52
+ /// When true, The select icon will be replaced by a cross icon to clear the selected value.
53
+ canClear?: boolean;
54
+
55
+ /// The selected items shown in the select field
56
+ render?: (selectedItems: SelectItem[]) => React.ReactNode;
57
+
58
+ /// Callback to be called when the select field is opened or closed
59
+ onOpenChange?: (open: boolean) => void;
60
+
61
+ /// The total options that will be visible when fully loaded
62
+ optionCount?: number;
63
+ }
64
+
65
+ interface SingleSelectQueryFieldProps extends SharedSelectQueryFieldProps {
66
+ multiple?: false;
67
+ }
68
+ interface MultiSelectQueryFieldProps extends SharedSelectQueryFieldProps {
69
+ multiple: true;
70
+ }
71
+
72
+ interface SingleSelectQueryFieldHandlers extends GenericInputPropsFunctionHandlers<string, HTMLDivElement> {
73
+ onChange: (val: string) => void;
74
+ }
75
+
76
+ interface MultiSelectQueryFieldHandlers extends GenericInputPropsFunctionHandlers<string[], HTMLDivElement> {
77
+ onChange: (val: string[]) => void;
78
+ }
79
+
80
+ export type SelectQueryFieldProps = SingleSelectQueryFieldProps | MultiSelectQueryFieldProps;
81
+ export type GenericSelectQueryFieldProps = PropsWithChildren<
82
+ | (SingleSelectQueryFieldProps & SingleSelectQueryFieldHandlers)
83
+ | (MultiSelectQueryFieldProps & MultiSelectQueryFieldHandlers)
84
+ >;
85
+ const defaultsApplier = defaultInputPropsFactory<GenericSelectQueryFieldProps>(defaultInputProps);
86
+
87
+ export interface InputValue {
88
+ value: string;
89
+ label: string;
90
+ /// When the user selects an option from the list, there is no need to do another API call
91
+ shouldUpdate: boolean;
92
+ }
93
+
94
+ export const _GenericSelectQueryField = forwardRef<HTMLInputElement, GenericSelectQueryFieldProps>(
95
+ function GenericSelectQueryField(props, ref) {
96
+ const {
97
+ onBlur = () => {},
98
+ onFocus = () => {},
99
+ onChange,
100
+ name,
101
+ disabled,
102
+ /// Value are the selected items (most cases these are a list of IDs only)
103
+ value,
104
+ id,
105
+ placeholder = 'Search field',
106
+ hasDescription,
107
+ hasError,
108
+ children,
109
+ readOnly,
110
+ isFetchingNextPage,
111
+ isFetching,
112
+ fetchNextPage,
113
+ hasNextPage,
114
+ render,
115
+ multiple = false,
116
+ canClear = false,
117
+ debounce = 250,
118
+ isLoadingData = false,
119
+ handleInputValueChange,
120
+ onOpenChange,
121
+ optionCount,
122
+ } = defaultsApplier(props);
123
+
124
+ const [open, setOpen] = useState<boolean>(false);
125
+ const [inputValue, setInputValue] = useState<InputValue>({ value: '', shouldUpdate: false, label: '' });
126
+ const [activeIndex, setActiveIndex] = useState<number | null>(null);
127
+ const [currentSelectedItems, setCurrentSelectedItems] = useState<SelectItem[]>([]);
128
+ const [persistedItems, setPersistedItems] = useState<SelectItem[]>([]);
129
+
130
+ const debouncedValue = useDebounce(inputValue.value, debounce);
131
+ const listItemsRef = useRef<Array<HTMLLIElement | null>>([]);
132
+
133
+ useEffect(() => {
134
+ if (handleInputValueChange) {
135
+ if ((inputValue.shouldUpdate && debouncedValue) || (inputValue && debouncedValue === ''))
136
+ handleInputValueChange(debouncedValue);
137
+ }
138
+ }, [debouncedValue]);
139
+
140
+ useEffect(() => {
141
+ if (onOpenChange) {
142
+ onOpenChange(open);
143
+ }
144
+ }, [open]);
145
+
146
+ const { refs, strategy, x, y, context } = useFloating<HTMLInputElement>({
147
+ whileElementsMounted: autoUpdate,
148
+ open,
149
+ onOpenChange: readOnly || disabled ? () => {} : setOpen,
150
+ middleware: [
151
+ offset(5),
152
+ size({
153
+ apply({ availableHeight, elements, availableWidth }) {
154
+ const refWidth = elements.reference.getBoundingClientRect().width;
155
+ const floatingContentWidth = elements.floating.scrollWidth;
156
+
157
+ const width =
158
+ availableWidth > refWidth
159
+ ? `${Math.min(availableWidth, 500)}px`
160
+ : `${Math.max(refWidth, floatingContentWidth)}px`;
161
+
162
+ Object.assign(elements.floating.style, {
163
+ // Note: we cannot use the rects.reference.width here because if the referenced item is very small compared to the other options, there will be horizontal overflow.
164
+ // fit-content isn't the perfect solution either, because if there is no space available it might render outside the viewport.
165
+ width,
166
+ maxHeight: `${Math.max(150, availableHeight)}px`,
167
+ });
168
+ },
169
+ }),
170
+ flip({
171
+ fallbackStrategy: 'bestFit',
172
+ fallbackPlacements: ['top', 'bottom'],
173
+ }),
174
+ ],
175
+ });
176
+
177
+ const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
178
+ useClick(context),
179
+ useRole(context, { role: 'listbox' }),
180
+ useDismiss(context),
181
+ ]);
182
+
183
+ function onInputChange(event: React.ChangeEvent<HTMLInputElement>) {
184
+ const value = event.target.value;
185
+ setInputValue({ value, shouldUpdate: true, label: value });
186
+ if (value) {
187
+ setActiveIndex(0);
188
+ }
189
+ }
190
+
191
+ const handleClear = (e: MouseEvent) => {
192
+ e.preventDefault();
193
+ e.stopPropagation();
194
+ setCurrentSelectedItems([]);
195
+ setPersistedItems([]);
196
+
197
+ // the undefined is an expection
198
+ if (onChange) onChange(multiple ? ([] as string[]) : (undefined as any));
199
+ };
200
+
201
+ /* This handles the case where the value is changed externally (e.g. from a parent component) */
202
+ /* onChange propagates the value to the parent component, but since the value prop is not a required prop, the parent might not reflect the change
203
+ * which ends up not running this useEffect. Meaning we still need to update the selectedIndex when clicked on an option.
204
+ */
205
+ useEffect(() => {
206
+ /// Value only contains the ids of the selected items, not their labels, The labels are fetched from the items found in the list of options.
207
+ /// One caveat is that the list of options might change due to the search query, so the labels might not be found.
208
+ const createItem = (v: string) => ({ value: v, label: getLabelFromChildren(children, v) as unknown as string });
209
+
210
+ if (Array.isArray(value)) {
211
+ // first we divide the value array into two arrays, one that are already in preserved (so we don't need to fetch the label again)
212
+ // and the other one that are not in the preserved array (so we need to fetch the label)
213
+ const [preserved, toFetch] = value.reduce(
214
+ (acc, v) => {
215
+ if (persistedItems.find((item) => item.value === v)) {
216
+ acc[0].push(v);
217
+ } else {
218
+ acc[1].push(v);
219
+ }
220
+ return acc;
221
+ },
222
+ [[], []] as [string[], string[]],
223
+ );
224
+
225
+ const fetched = toFetch.map(createItem);
226
+ const items = [...persistedItems.filter((item) => preserved.includes(item.value)), ...fetched];
227
+ setPersistedItems(items);
228
+ setCurrentSelectedItems(items);
229
+ } else if (typeof value === 'string' && value !== '') {
230
+ // check if value is already part of the persisted items
231
+ const item = persistedItems.find((item) => item.value === value);
232
+ // if yes, then we don't need to fetch the label again
233
+ if (item) {
234
+ setCurrentSelectedItems([item]);
235
+ } else {
236
+ setCurrentSelectedItems([createItem(value)]);
237
+ }
238
+ setCurrentSelectedItems([createItem(value)]);
239
+ }
240
+ }, [value, children]);
241
+
242
+ const renderSelect = () => {
243
+ const hasOptions =
244
+ options &&
245
+ options.some((optionGroup) =>
246
+ Children.toArray(optionGroup?.props?.children).some(
247
+ (option) => isValidElement(option) && option.props?.children,
248
+ ),
249
+ );
250
+
251
+ // initialFocus=-1 is used to prevent the first item from being focused when the list opens
252
+ return (
253
+ <FloatingFocusManager context={context} visuallyHiddenDismiss initialFocus={-1}>
254
+ <SelectContainer
255
+ {...getFloatingProps({
256
+ ref: refs.setFloating,
257
+ style: {
258
+ position: strategy,
259
+ top: y ?? 0,
260
+ left: x ?? 0,
261
+ overflow: 'auto',
262
+ },
263
+ })}
264
+ >
265
+ {' '}
266
+ {handleInputValueChange && (
267
+ <GenericTextField
268
+ id={`${name}-input`}
269
+ name={`${name}-input`}
270
+ hasDescription={false}
271
+ icon={<SearchIcon />}
272
+ suffix={isLoadingData ? 'Loading' : optionCount !== undefined ? `Result: ${optionCount}` : undefined}
273
+ hasError={hasError}
274
+ value={inputValue.value}
275
+ onChange={onInputChange}
276
+ placeholder={placeholder}
277
+ ref={ref}
278
+ />
279
+ )}
280
+ {/* it will always contain 1 because of the group label */}
281
+ {isLoadingData && (
282
+ <FeedBackContainer>
283
+ <Spinner size="small" />
284
+ <span style={{ marginLeft: '10px' }}>loading results</span>
285
+ </FeedBackContainer>
286
+ )}
287
+ {/* show options if they exist*/}
288
+ {hasOptions && options}
289
+ {/* Add an infinite scroll component add the bottom when there is data, and we are not already loading */}
290
+ {hasOptions && !isLoadingData && (
291
+ <InfiniteScroll
292
+ isFetching={isFetching}
293
+ hasNextPage={hasNextPage}
294
+ fetchNextPage={fetchNextPage}
295
+ isFetchingNextPage={isFetchingNextPage}
296
+ />
297
+ )}
298
+ {/* Basically first interaction */}
299
+ {!hasOptions && inputValue.value === '' && handleInputValueChange && (
300
+ <FeedBackContainer>Start typing to search</FeedBackContainer>
301
+ )}
302
+ {/* When there is no result */}
303
+ {!hasOptions && !isLoadingData && <FeedBackContainer>No results found</FeedBackContainer>}
304
+ </SelectContainer>
305
+ </FloatingFocusManager>
306
+ );
307
+ };
308
+
309
+ const options = useMemo(() => {
310
+ return [
311
+ /* this is needed, but we need to get rid of the items that are already present in the options that were actually loaded
312
+ persistedItems.length > 0 && (
313
+ <ul key={`selected-items-${name}`} role="group" aria-labelledby={'select-items-list'}>
314
+ <GroupLabel role="presentation" id={'select-group-label'} aria-hidden="false">
315
+ Selected items
316
+ </GroupLabel>
317
+ {persistedItems.map((item) => (
318
+ <Option key={`${name}-${item.value}`} value={item.value} label={item.label} onChange={onChange as any}>
319
+ {item.label}
320
+ </Option>
321
+ ))}
322
+ </ul>
323
+ ),
324
+ */
325
+
326
+ ...(Children.map(
327
+ // children here is an <OptionGroup/>
328
+ children,
329
+ (child) =>
330
+ isValidElement(child) && (
331
+ <ul key={child.props.label} role="group" aria-labelledby={`select-${child.props.label}`}>
332
+ {child.props.label && (
333
+ <GroupLabel role="presentation" id={`select-${child.props.label}`} aria-hidden="true">
334
+ {child.props.label}
335
+ </GroupLabel>
336
+ )}
337
+ {Children.map(child.props.children, (option) => {
338
+ return cloneElement(option, {
339
+ onChange: onChange,
340
+ });
341
+ })}
342
+ </ul>
343
+ ),
344
+ )?.filter(Boolean) ?? []),
345
+ ];
346
+ }, [children, persistedItems]);
347
+
348
+ return (
349
+ <SelectContext.Provider
350
+ value={{
351
+ listRef: listItemsRef,
352
+ setOpen,
353
+ getItemProps,
354
+ setActiveIndex,
355
+ activeIndex,
356
+ dataRef: context.dataRef,
357
+ multiple,
358
+ selectedItems: currentSelectedItems,
359
+ setSelectedItems: setCurrentSelectedItems,
360
+ name,
361
+ }}
362
+ >
363
+ <SelectButton
364
+ id={id}
365
+ ref={refs.setReference}
366
+ disabled={disabled}
367
+ readOnly={readOnly}
368
+ onBlur={onBlur}
369
+ onFocus={onFocus}
370
+ isOpen={open}
371
+ tabIndex={disabled ? -1 : 0}
372
+ hasError={hasError}
373
+ aria-describedby={setAriaDescribedBy(name, hasDescription)}
374
+ {...getReferenceProps()}
375
+ >
376
+ {render ? (
377
+ render(currentSelectedItems)
378
+ ) : (
379
+ <div>
380
+ {currentSelectedItems.length === 0 ? 'Select' : currentSelectedItems.map((item) => item.label).join(', ')}
381
+ </div>
382
+ )}
383
+
384
+ {!readOnly && canClear && currentSelectedItems.length > 0 && !open ? (
385
+ <IconButton size="tiny" icon={<ClearIcon />} ariaLabel="clear" onClick={(e) => handleClear(e)} />
386
+ ) : (
387
+ <StyledArrowIcon size={16} />
388
+ )}
389
+ </SelectButton>
390
+ {open && <FloatingPortal>{renderSelect()}</FloatingPortal>}
391
+ </SelectContext.Provider>
392
+ );
393
+ },
394
+ );
395
+
396
+ // TODO: type it correctly instead
397
+ type GenericSelectQueryFieldType = typeof _GenericSelectQueryField & SubComponentTypes;
398
+ export const GenericSelectQueryField = _GenericSelectQueryField as GenericSelectQueryFieldType;
399
+
400
+ GenericSelectQueryField.Option = Option;
401
+ GenericSelectQueryField.OptionGroup = OptionGroup;
@@ -0,0 +1,280 @@
1
+ import React, { useState } from 'react';
2
+ import { Meta, StoryFn } from '@storybook/react';
3
+ import { SubmitHandler, useForm } from 'react-hook-form';
4
+ import { Button, SelectQueryField, SelectQueryFieldProps } from '../../../../components';
5
+ import { films } from '../data';
6
+ import { z } from 'zod';
7
+ import { zodResolver } from '@hookform/resolvers/zod';
8
+ import { GenericSelectQueryField } from './Generic';
9
+
10
+ interface Film {
11
+ name: string;
12
+ decade: string;
13
+ icon: string;
14
+ }
15
+
16
+ export default {
17
+ title: 'Inputs/SelectQueryField',
18
+ args: {
19
+ placeholder: 'Search for a film',
20
+ label: 'Film',
21
+ debounce: 250,
22
+ readOnly: false,
23
+ canClear: false,
24
+ },
25
+ } as Meta<SelectQueryFieldProps>;
26
+
27
+ export const ServerSideSubmit: StoryFn<SelectQueryFieldProps> = (args) => {
28
+ interface FormValues {
29
+ film: string;
30
+ }
31
+
32
+ const { control, handleSubmit } = useForm<FormValues>();
33
+ const [loading, setLoading] = useState<boolean>(false);
34
+ const [options, setOptions] = useState<Film[]>();
35
+ const [result, setResult] = useState<string>('');
36
+
37
+ // Function to handle the simulated API call
38
+ // This function will be called each time the input changes
39
+ const mockAPICall = (debouncedValue: string) => {
40
+ // Start loading
41
+ setLoading(true);
42
+
43
+ setTimeout(() => {
44
+ const filteredOptions = films.filter((film) =>
45
+ film.name.toLowerCase().trim().includes(debouncedValue.toLowerCase()),
46
+ );
47
+ setOptions(filteredOptions);
48
+ setLoading(false);
49
+ }, 1000);
50
+ };
51
+
52
+ const onSubmit: SubmitHandler<FormValues> = ({ film }) => {
53
+ setResult(film);
54
+ };
55
+
56
+ return (
57
+ <>
58
+ it is important to note that it is required for the user to select an option from the list. If the user types
59
+ something, but does not select an item from the list, the input will be reset.
60
+ <form onSubmit={handleSubmit(onSubmit)}>
61
+ <SelectQueryField
62
+ debounce={args.debounce}
63
+ control={control}
64
+ loading={loading}
65
+ canClear={args.canClear}
66
+ placeholder={args.placeholder}
67
+ label={args.placeholder}
68
+ /* The onChange returns the not debounced value, probably never needed, but is inherited by all inputFields */
69
+ handleInputValueChange={mockAPICall}
70
+ isLoadingData={loading}
71
+ required={false}
72
+ hasNextPage={false}
73
+ optionCount={10}
74
+ isFetching={false}
75
+ isFetchingNextPage={false}
76
+ fetchNextPage={() => {}}
77
+ name="film"
78
+ >
79
+ {/* In this case the label is the same as the value but ofcourse that can differ*/}
80
+ <SelectQueryField.OptionGroup>
81
+ {options?.map(({ name, icon }) => (
82
+ <SelectQueryField.Option key={name} value={name} label={name}>
83
+ <div style={{ display: 'flex', alignItems: 'center' }}>
84
+ <img src={icon} width="20px" height="20px" style={{ borderRadius: '50%', marginRight: '10px' }} />
85
+ <span>{name}</span>
86
+ </div>
87
+ </SelectQueryField.Option>
88
+ ))}
89
+ </SelectQueryField.OptionGroup>
90
+ </SelectQueryField>
91
+ <Button type="submit">Submit form</Button>
92
+ </form>
93
+ This is the submitted value:
94
+ <div>{result}</div>
95
+ </>
96
+ );
97
+ };
98
+
99
+ export const ClientSideSubmit: StoryFn<SelectQueryFieldProps> = (args) => {
100
+ interface FormValues {
101
+ film: string;
102
+ }
103
+
104
+ const { control, handleSubmit } = useForm<FormValues>();
105
+ const [options, setOptions] = useState<Film[]>();
106
+ const [result, setResult] = useState<string>('');
107
+
108
+ // Function to handle the simulated API call
109
+ // This function will be called each time the input changes
110
+ const handleInputChange = (value: string) => {
111
+ // Start loading
112
+ const filteredOptions = films.filter((film) => film.name.toLowerCase().trim().includes(value.toLowerCase()));
113
+ setOptions(filteredOptions);
114
+ };
115
+
116
+ const onSubmit: SubmitHandler<FormValues> = ({ film }) => {
117
+ setResult(film);
118
+ };
119
+
120
+ return (
121
+ <>
122
+ <form onSubmit={handleSubmit(onSubmit)}>
123
+ <SelectQueryField
124
+ control={control}
125
+ placeholder="Search for a film"
126
+ label="Film"
127
+ canClear={args.canClear}
128
+ /* The onChange returns the not debounced value, probably never needed, but is inherited by all inputFields */
129
+ handleInputValueChange={handleInputChange}
130
+ required={false}
131
+ debounce={0}
132
+ hasNextPage={false}
133
+ optionCount={10}
134
+ isFetching={false}
135
+ isFetchingNextPage={false}
136
+ fetchNextPage={() => {}}
137
+ name="film"
138
+ >
139
+ {/* In this case the label is the same as the value but ofcourse that can differ*/}
140
+ <SelectQueryField.OptionGroup>
141
+ {options?.map(({ name, icon, decade }) => (
142
+ <SelectQueryField.Option key={name} value={decade} label={name}>
143
+ <div style={{ display: 'flex', alignItems: 'center' }}>
144
+ <img src={icon} width="20px" height="20px" style={{ borderRadius: '50%', marginRight: '10px' }} />
145
+ <span>{name}</span>
146
+ </div>
147
+ </SelectQueryField.Option>
148
+ ))}
149
+ </SelectQueryField.OptionGroup>
150
+ </SelectQueryField>
151
+ <Button type="submit">Submit form</Button>
152
+ </form>
153
+ The result returns the decade of the film:
154
+ <div>{result}</div>
155
+ </>
156
+ );
157
+ };
158
+
159
+ export const ClientSideMultiSelectSubmit: StoryFn<SelectQueryFieldProps> = (args) => {
160
+ interface FormValues {
161
+ films: string[];
162
+ }
163
+
164
+ const validationSchema = z.object({
165
+ films: z.array(z.string()).nonempty(),
166
+ });
167
+
168
+ const { control, handleSubmit } = useForm<FormValues>({
169
+ resolver: zodResolver(validationSchema),
170
+ });
171
+ const [options, setOptions] = useState<Film[]>();
172
+ const [result, setResult] = useState<string[]>([]);
173
+
174
+ // Function to handle the simulated API call
175
+ // This function will be called each time the input changes
176
+ const handleInputChange = (value: string) => {
177
+ // Start loading
178
+ const filteredOptions = films.filter((film) => film.name.toLowerCase().trim().includes(value.toLowerCase()));
179
+ setOptions(filteredOptions);
180
+ };
181
+
182
+ const onSubmit: SubmitHandler<FormValues> = ({ films }) => {
183
+ if (films && films.length === 0) return;
184
+ setResult(films);
185
+ };
186
+
187
+ return (
188
+ <>
189
+ <form onSubmit={handleSubmit(onSubmit)}>
190
+ <SelectQueryField
191
+ control={control}
192
+ placeholder="Search for a film"
193
+ label="Film"
194
+ /* The onChange returns the not debounced value, probably never needed, but is inherited by all inputFields */
195
+ handleInputValueChange={handleInputChange}
196
+ required={false}
197
+ canClear={args.canClear}
198
+ debounce={0}
199
+ hasNextPage={false}
200
+ optionCount={10}
201
+ isFetching={false}
202
+ isFetchingNextPage={false}
203
+ fetchNextPage={() => {}}
204
+ multiple
205
+ name="films"
206
+ >
207
+ {/* In this case the label is the same as the value but ofcourse that can differ*/}
208
+ <SelectQueryField.OptionGroup>
209
+ {options?.map(({ name, icon }) => (
210
+ <SelectQueryField.Option key={name} value={name} label={name}>
211
+ <div style={{ display: 'flex', alignItems: 'center' }}>
212
+ <img src={icon} width="20px" height="20px" style={{ borderRadius: '50%', marginRight: '10px' }} />
213
+ <span>{name}</span>
214
+ </div>
215
+ </SelectQueryField.Option>
216
+ ))}
217
+ </SelectQueryField.OptionGroup>
218
+ </SelectQueryField>
219
+ <Button type="submit">Submit form</Button>
220
+ </form>
221
+ Selected films:
222
+ <div>{result && result.join(',')}</div>
223
+ </>
224
+ );
225
+ };
226
+
227
+ export const Generic: StoryFn<SelectQueryFieldProps> = () => {
228
+ const [options, setOptions] = useState<Film[]>();
229
+ const [result, setResult] = useState<string[]>([]);
230
+
231
+ // Function to handle the simulated API call
232
+ // This function will be called each time the input changes
233
+ const handleInputChange = (value: string) => {
234
+ // Start loading
235
+ const filteredOptions = films.filter((film) => film.name.toLowerCase().trim().includes(value.toLowerCase()));
236
+ setOptions(filteredOptions);
237
+ };
238
+
239
+ const onChange = (values: string[]) => {
240
+ setResult(values);
241
+ };
242
+
243
+ return (
244
+ <>
245
+ <GenericSelectQueryField
246
+ id="films"
247
+ onChange={onChange}
248
+ placeholder="Search for a film"
249
+ /* The onChange returns the not debounced value, probably never needed, but is inherited by all inputFields */
250
+ handleInputValueChange={handleInputChange}
251
+ required={false}
252
+ debounce={0}
253
+ multiple
254
+ hasError={false}
255
+ hasDescription={false}
256
+ value={result}
257
+ name="film"
258
+ hasNextPage={false}
259
+ optionCount={10}
260
+ isFetching={false}
261
+ isFetchingNextPage={false}
262
+ fetchNextPage={() => {}}
263
+ >
264
+ {/* In this case the label is the same as the value but ofcourse that can differ*/}
265
+ <SelectQueryField.OptionGroup>
266
+ {options?.map(({ name, icon }) => (
267
+ <SelectQueryField.Option key={name} value={name} label={name}>
268
+ <div style={{ display: 'flex', alignItems: 'center' }}>
269
+ <img src={icon} width="20px" height="20px" style={{ borderRadius: '50%', marginRight: '10px' }} />
270
+ <span>{name}</span>
271
+ </div>
272
+ </SelectQueryField.Option>
273
+ ))}
274
+ </SelectQueryField.OptionGroup>
275
+ </GenericSelectQueryField>
276
+ Selected films:
277
+ <div>{result.map((film) => film).join(',')}</div>
278
+ </>
279
+ );
280
+ };
@@ -0,0 +1,5 @@
1
+ export { GenericSelectQueryField } from '../SelectQueryField/Generic';
2
+ export type { SelectQueryFieldProps, GenericSelectQueryFieldProps } from '../SelectQueryField/Generic';
3
+
4
+ export { ControlledSelectQueryField } from './Controlled';
5
+ export type { ControlledSelectQueryFieldProps } from './Controlled';
@@ -0,0 +1,13 @@
1
+ import { styled } from '../../../../styled';
2
+
3
+ export const FeedBackContainer = styled.div`
4
+ display: flex;
5
+ flex-direciton: row;
6
+ align-items: center;
7
+ justify-content: center;
8
+
9
+ // loading
10
+ span {
11
+ margin-left: ${({ theme }) => theme.spacing['1']};
12
+ }
13
+ `;