@takaro/lib-components 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) 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 +76 -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 +170 -0
  15. package/src/components/actions/Button/Button.test.tsx +7 -0
  16. package/src/components/actions/Button/Button.test.tsx.snap +89 -0
  17. package/src/components/actions/Button/index.tsx +99 -0
  18. package/src/components/actions/Button/style.ts +148 -0
  19. package/src/components/actions/ContextMenu/ContextMenu.stories.tsx +40 -0
  20. package/src/components/actions/ContextMenu/Group.tsx +34 -0
  21. package/src/components/actions/ContextMenu/MenuItem.tsx +66 -0
  22. package/src/components/actions/ContextMenu/index.tsx +217 -0
  23. package/src/components/actions/Dropdown/Dropdown.stories.tsx +88 -0
  24. package/src/components/actions/Dropdown/DropdownContext.tsx +21 -0
  25. package/src/components/actions/Dropdown/DropdownMenu.tsx +67 -0
  26. package/src/components/actions/Dropdown/DropdownMenuGroup.tsx +37 -0
  27. package/src/components/actions/Dropdown/DropdownMenuItem.tsx +128 -0
  28. package/src/components/actions/Dropdown/DropdownTrigger.tsx +89 -0
  29. package/src/components/actions/Dropdown/index.tsx +22 -0
  30. package/src/components/actions/Dropdown/useDropdown.tsx +82 -0
  31. package/src/components/actions/DropdownButton/DropdownButton.stories.tsx +88 -0
  32. package/src/components/actions/DropdownButton/index.tsx +113 -0
  33. package/src/components/actions/IconButton/IconButton.stories.tsx +54 -0
  34. package/src/components/actions/IconButton/IconButton.test.tsx +7 -0
  35. package/src/components/actions/IconButton/IconButton.test.tsx.snap +46 -0
  36. package/src/components/actions/IconButton/index.tsx +40 -0
  37. package/src/components/actions/IconButton/style.ts +75 -0
  38. package/src/components/actions/ToggleButton/ToggleButton.stories.tsx +84 -0
  39. package/src/components/actions/ToggleButton/ToggleButton.tsx +48 -0
  40. package/src/components/actions/ToggleButton/ToggleButtonGroup.tsx +99 -0
  41. package/src/components/actions/ToggleButton/index.tsx +2 -0
  42. package/src/components/actions/ToggleButton/style.ts +76 -0
  43. package/src/components/actions/index.ts +16 -0
  44. package/src/components/charts/AreaChart/AreaChart.stories.tsx +104 -0
  45. package/src/components/charts/AreaChart/index.tsx +379 -0
  46. package/src/components/charts/BarChart/BarChart.stories.tsx +32 -0
  47. package/src/components/charts/BarChart/index.tsx +287 -0
  48. package/src/components/charts/BrushHandle.tsx +21 -0
  49. package/src/components/charts/GeoMercator/GeoMercator.stories.tsx +65 -0
  50. package/src/components/charts/GeoMercator/index.tsx +141 -0
  51. package/src/components/charts/GeoMercator/world.d.ts +1 -0
  52. package/src/components/charts/GeoMercator/world.json +99485 -0
  53. package/src/components/charts/Heatmap/Heatmap.stories.tsx +55 -0
  54. package/src/components/charts/Heatmap/index.tsx +228 -0
  55. package/src/components/charts/LineChart/LineChart.stories.tsx +37 -0
  56. package/src/components/charts/LineChart/index.tsx +233 -0
  57. package/src/components/charts/PieChart/PieChart.stories.tsx +43 -0
  58. package/src/components/charts/PieChart/index.tsx +163 -0
  59. package/src/components/charts/PointHighlight.tsx +49 -0
  60. package/src/components/charts/RadarChart/RadarChart.stories.tsx +38 -0
  61. package/src/components/charts/RadarChart/generators.ts +30 -0
  62. package/src/components/charts/RadarChart/index.tsx +175 -0
  63. package/src/components/charts/RadialBarChart/RadialBarChart.stories.tsx +34 -0
  64. package/src/components/charts/RadialBarChart/index.tsx +165 -0
  65. package/src/components/charts/RadialLineChart/RadialLineChart.stories.tsx +26 -0
  66. package/src/components/charts/RadialLineChart/index.tsx +141 -0
  67. package/src/components/charts/index.tsx +20 -0
  68. package/src/components/charts/useGradients.tsx +37 -0
  69. package/src/components/charts/util.ts +40 -0
  70. package/src/components/data/Avatar/Avatar.stories.tsx +93 -0
  71. package/src/components/data/Avatar/context.tsx +20 -0
  72. package/src/components/data/Avatar/index.tsx +132 -0
  73. package/src/components/data/Avatar/style.ts +124 -0
  74. package/src/components/data/Avatar/useImageLoadingStatus.tsx +32 -0
  75. package/src/components/data/Chip/Chip.stories.tsx +67 -0
  76. package/src/components/data/Chip/Chip.test.tsx +7 -0
  77. package/src/components/data/Chip/Chip.test.tsx.snap +50 -0
  78. package/src/components/data/Chip/index.tsx +76 -0
  79. package/src/components/data/Chip/style.ts +84 -0
  80. package/src/components/data/Console/Console.stories.tsx +51 -0
  81. package/src/components/data/Console/Console.tsx +125 -0
  82. package/src/components/data/Console/ConsoleInput/index.tsx +87 -0
  83. package/src/components/data/Console/ConsoleInput/style.ts +41 -0
  84. package/src/components/data/Console/ConsoleLine/index.tsx +127 -0
  85. package/src/components/data/Console/ConsoleLine/style.ts +76 -0
  86. package/src/components/data/Console/MessageModel.ts +9 -0
  87. package/src/components/data/Console/index.tsx +4 -0
  88. package/src/components/data/Console/style.ts +31 -0
  89. package/src/components/data/Console/useConsoleLiveMode.ts +42 -0
  90. package/src/components/data/CopyId/CopyId.stories.tsx +36 -0
  91. package/src/components/data/CopyId/index.tsx +38 -0
  92. package/src/components/data/DateFormatter/DateFormatter.stories.tsx +26 -0
  93. package/src/components/data/DateFormatter/index.tsx +15 -0
  94. package/src/components/data/Drawer/Drawer.stories.tsx +144 -0
  95. package/src/components/data/Drawer/DrawerBody.tsx +22 -0
  96. package/src/components/data/Drawer/DrawerContent.tsx +110 -0
  97. package/src/components/data/Drawer/DrawerContext.tsx +21 -0
  98. package/src/components/data/Drawer/DrawerFooter.tsx +19 -0
  99. package/src/components/data/Drawer/DrawerHeading.tsx +49 -0
  100. package/src/components/data/Drawer/DrawerSkeleton.tsx +29 -0
  101. package/src/components/data/Drawer/index.tsx +25 -0
  102. package/src/components/data/Drawer/useDrawer.tsx +52 -0
  103. package/src/components/data/InfiniteScroll/InfiniteScroll.stories.tsx +33 -0
  104. package/src/components/data/InfiniteScroll/index.tsx +51 -0
  105. package/src/components/data/LinkCard/index.tsx +28 -0
  106. package/src/components/data/Stats/Stat.tsx +99 -0
  107. package/src/components/data/Stats/Stats.stories.tsx +72 -0
  108. package/src/components/data/Stats/context.tsx +11 -0
  109. package/src/components/data/Stats/index.tsx +50 -0
  110. package/src/components/data/Table/Table.stories.tsx +142 -0
  111. package/src/components/data/Table/index.tsx +365 -0
  112. package/src/components/data/Table/react-table.d.ts +11 -0
  113. package/src/components/data/Table/style.ts +75 -0
  114. package/src/components/data/Table/subcomponents/ColumnHeader/ColumnSettings.tsx +161 -0
  115. package/src/components/data/Table/subcomponents/ColumnHeader/index.tsx +207 -0
  116. package/src/components/data/Table/subcomponents/ColumnHeader/style.ts +89 -0
  117. package/src/components/data/Table/subcomponents/ColumnVisibility/index.tsx +61 -0
  118. package/src/components/data/Table/subcomponents/Filter/field.tsx +129 -0
  119. package/src/components/data/Table/subcomponents/Filter/index.tsx +239 -0
  120. package/src/components/data/Table/subcomponents/Filter/style.ts +26 -0
  121. package/src/components/data/Table/subcomponents/Pagination/index.tsx +108 -0
  122. package/src/components/data/Table/subcomponents/Pagination/style.ts +49 -0
  123. package/src/components/data/Table/subcomponents/index.ts +4 -0
  124. package/src/components/data/index.ts +28 -0
  125. package/src/components/dialogs/Dialog/Dialog.stories.tsx +74 -0
  126. package/src/components/dialogs/Dialog/DialogBody.tsx +62 -0
  127. package/src/components/dialogs/Dialog/DialogContent.tsx +46 -0
  128. package/src/components/dialogs/Dialog/DialogContext.tsx +21 -0
  129. package/src/components/dialogs/Dialog/DialogHeading.tsx +56 -0
  130. package/src/components/dialogs/Dialog/index.tsx +20 -0
  131. package/src/components/dialogs/Dialog/useDialog.tsx +50 -0
  132. package/src/components/feedback/Alert/Alert.stories.tsx +77 -0
  133. package/src/components/feedback/Alert/Alert.test.tsx +7 -0
  134. package/src/components/feedback/Alert/Alert.test.tsx.snap +146 -0
  135. package/src/components/feedback/Alert/index.tsx +109 -0
  136. package/src/components/feedback/Alert/style.ts +87 -0
  137. package/src/components/feedback/ErrorFallback/ErrorFallback.stories.tsx +10 -0
  138. package/src/components/feedback/ErrorFallback/index.tsx +48 -0
  139. package/src/components/feedback/ErrorPage/ErrorPage.stories.tsx +31 -0
  140. package/src/components/feedback/ErrorPage/index.tsx +193 -0
  141. package/src/components/feedback/FormError/FormError.stories.tsx +25 -0
  142. package/src/components/feedback/FormError/index.tsx +54 -0
  143. package/src/components/feedback/Loaders/Loaders.stories.tsx +28 -0
  144. package/src/components/feedback/Loaders/Loading.test.tsx +7 -0
  145. package/src/components/feedback/Loaders/Loading.test.tsx.snap +141 -0
  146. package/src/components/feedback/Loaders/Loading.tsx +107 -0
  147. package/src/components/feedback/Loaders/Spinner.test.tsx +7 -0
  148. package/src/components/feedback/Loaders/Spinner.test.tsx.snap +18 -0
  149. package/src/components/feedback/Loaders/Spinner.tsx +74 -0
  150. package/src/components/feedback/Loaders/index.ts +2 -0
  151. package/src/components/feedback/NetworkDetector/NetworkDetector.stories.tsx +21 -0
  152. package/src/components/feedback/NetworkDetector/NetworkDetector.test.tsx +7 -0
  153. package/src/components/feedback/NetworkDetector/NetworkDetector.test.tsx.snap +3 -0
  154. package/src/components/feedback/NetworkDetector/index.tsx +41 -0
  155. package/src/components/feedback/NotificationBanner/NotificationBanner.stories.tsx +13 -0
  156. package/src/components/feedback/NotificationBanner/NotificationBanner.test.tsx +14 -0
  157. package/src/components/feedback/NotificationBanner/NotificationBanner.test.tsx.snap +3 -0
  158. package/src/components/feedback/NotificationBanner/index.tsx +79 -0
  159. package/src/components/feedback/Popover/Popover.stories.tsx +33 -0
  160. package/src/components/feedback/Popover/PopoverContent.tsx +43 -0
  161. package/src/components/feedback/Popover/PopoverContext.tsx +21 -0
  162. package/src/components/feedback/Popover/PopoverTrigger.tsx +43 -0
  163. package/src/components/feedback/Popover/index.tsx +22 -0
  164. package/src/components/feedback/Popover/usePopover.tsx +87 -0
  165. package/src/components/feedback/ProgressBar/ProgressBar.stories.tsx +38 -0
  166. package/src/components/feedback/ProgressBar/index.tsx +103 -0
  167. package/src/components/feedback/QuestionTooltip/QuestionTooltip.stories.tsx +20 -0
  168. package/src/components/feedback/QuestionTooltip/index.tsx +36 -0
  169. package/src/components/feedback/Skeleton/Skeleton.stories.tsx +33 -0
  170. package/src/components/feedback/Skeleton/Skeleton.test.tsx +7 -0
  171. package/src/components/feedback/Skeleton/Skeleton.test.tsx.snap +35 -0
  172. package/src/components/feedback/Skeleton/index.tsx +62 -0
  173. package/src/components/feedback/Tooltip/Tooltip.stories.tsx +69 -0
  174. package/src/components/feedback/Tooltip/TooltipContent.tsx +50 -0
  175. package/src/components/feedback/Tooltip/TooltipContext.tsx +13 -0
  176. package/src/components/feedback/Tooltip/TooltipTrigger.tsx +39 -0
  177. package/src/components/feedback/Tooltip/index.tsx +26 -0
  178. package/src/components/feedback/Tooltip/useTooltip.tsx +79 -0
  179. package/src/components/feedback/index.ts +33 -0
  180. package/src/components/feedback/snacks/CookieConsent/index.tsx +122 -0
  181. package/src/components/feedback/snacks/CookieConsent/style.ts +100 -0
  182. package/src/components/feedback/snacks/Default/default.stories.tsx +72 -0
  183. package/src/components/feedback/snacks/Default/index.tsx +77 -0
  184. package/src/components/feedback/snacks/Default/style.ts +59 -0
  185. package/src/components/feedback/snacks/Drawer/Drawer.stories.tsx +46 -0
  186. package/src/components/feedback/snacks/Drawer/index.tsx +70 -0
  187. package/src/components/feedback/snacks/NetworkDetector/index.tsx +70 -0
  188. package/src/components/feedback/snacks/index.d.ts +15 -0
  189. package/src/components/feedback/snacks/index.ts +8 -0
  190. package/src/components/index.ts +9 -0
  191. package/src/components/inputs/CheckBox/CheckBox.stories.tsx +64 -0
  192. package/src/components/inputs/CheckBox/Controlled.tsx +124 -0
  193. package/src/components/inputs/CheckBox/Generic.tsx +96 -0
  194. package/src/components/inputs/CheckBox/index.tsx +4 -0
  195. package/src/components/inputs/CheckBox/style.ts +113 -0
  196. package/src/components/inputs/CodeField/CodeField.stories.tsx +87 -0
  197. package/src/components/inputs/CodeField/index.tsx +173 -0
  198. package/src/components/inputs/CodeField/style.ts +50 -0
  199. package/src/components/inputs/Date/DatePicker/Controlled.tsx +101 -0
  200. package/src/components/inputs/Date/DatePicker/DatePicker.stories.tsx +234 -0
  201. package/src/components/inputs/Date/DatePicker/Generic.tsx +253 -0
  202. package/src/components/inputs/Date/DatePicker/formats.tsx +32 -0
  203. package/src/components/inputs/Date/DatePicker/style.ts +43 -0
  204. package/src/components/inputs/Date/DateRangePicker/Context.tsx +112 -0
  205. package/src/components/inputs/Date/DateRangePicker/DateRangePicker.stories.tsx +32 -0
  206. package/src/components/inputs/Date/DateRangePicker/DateSelector/Absolute.tsx +98 -0
  207. package/src/components/inputs/Date/DateRangePicker/DateSelector/Relative.tsx +54 -0
  208. package/src/components/inputs/Date/DateRangePicker/DateSelector/index.tsx +49 -0
  209. package/src/components/inputs/Date/DateRangePicker/QuickSelect/index.tsx +270 -0
  210. package/src/components/inputs/Date/DateRangePicker/QuickSelect/style.ts +40 -0
  211. package/src/components/inputs/Date/DateRangePicker/index.tsx +134 -0
  212. package/src/components/inputs/Date/DateRangePicker/style.ts +51 -0
  213. package/src/components/inputs/Date/subcomponents/Calendar/index.tsx +150 -0
  214. package/src/components/inputs/Date/subcomponents/Calendar/style.ts +59 -0
  215. package/src/components/inputs/Date/subcomponents/RelativePicker/index.tsx +186 -0
  216. package/src/components/inputs/Date/subcomponents/RelativePicker/style.ts +50 -0
  217. package/src/components/inputs/Date/subcomponents/TimePicker/TimePicker.stories.tsx +25 -0
  218. package/src/components/inputs/Date/subcomponents/TimePicker/index.tsx +40 -0
  219. package/src/components/inputs/Date/subcomponents/TimePicker/style.ts +32 -0
  220. package/src/components/inputs/DurationField/Controlled.tsx +69 -0
  221. package/src/components/inputs/DurationField/Duration.stories.tsx +54 -0
  222. package/src/components/inputs/DurationField/Generic.tsx +200 -0
  223. package/src/components/inputs/DurationField/index.tsx +5 -0
  224. package/src/components/inputs/DurationField/style.ts +42 -0
  225. package/src/components/inputs/EditableField/EditableField.stories.tsx +65 -0
  226. package/src/components/inputs/EditableField/index.tsx +135 -0
  227. package/src/components/inputs/EditableField/style.ts +11 -0
  228. package/src/components/inputs/FileField/Controlled.tsx +104 -0
  229. package/src/components/inputs/FileField/FileField.stories.tsx +211 -0
  230. package/src/components/inputs/FileField/Generic.tsx +131 -0
  231. package/src/components/inputs/FileField/index.tsx +5 -0
  232. package/src/components/inputs/FileField/style.ts +34 -0
  233. package/src/components/inputs/InputProps.ts +61 -0
  234. package/src/components/inputs/RadioGroup/Controlled.tsx +46 -0
  235. package/src/components/inputs/RadioGroup/Generic.tsx +34 -0
  236. package/src/components/inputs/RadioGroup/RadioGroup.stories.tsx +116 -0
  237. package/src/components/inputs/RadioGroup/RadioItem.tsx +129 -0
  238. package/src/components/inputs/RadioGroup/context.tsx +20 -0
  239. package/src/components/inputs/RadioGroup/index.ts +5 -0
  240. package/src/components/inputs/RadioGroup/style.ts +3 -0
  241. package/src/components/inputs/Slider/Controlled.tsx +87 -0
  242. package/src/components/inputs/Slider/Generic.tsx +73 -0
  243. package/src/components/inputs/Slider/Slider.stories.tsx +101 -0
  244. package/src/components/inputs/Slider/handle.tsx +31 -0
  245. package/src/components/inputs/Slider/index.tsx +5 -0
  246. package/src/components/inputs/Slider/style.ts +140 -0
  247. package/src/components/inputs/Switch/Controlled.tsx +58 -0
  248. package/src/components/inputs/Switch/Generic.tsx +67 -0
  249. package/src/components/inputs/Switch/Switch.stories.tsx +91 -0
  250. package/src/components/inputs/Switch/index.ts +5 -0
  251. package/src/components/inputs/Switch/style.ts +56 -0
  252. package/src/components/inputs/TagField/Controlled.tsx +103 -0
  253. package/src/components/inputs/TagField/Generic.tsx +138 -0
  254. package/src/components/inputs/TagField/TagField.stories.tsx +68 -0
  255. package/src/components/inputs/TagField/index.ts +5 -0
  256. package/src/components/inputs/TagField/style.ts +25 -0
  257. package/src/components/inputs/TagField/util.ts +34 -0
  258. package/src/components/inputs/TextAreaField/Controlled.tsx +101 -0
  259. package/src/components/inputs/TextAreaField/Generic.tsx +56 -0
  260. package/src/components/inputs/TextAreaField/TextAreaField.stories.tsx +98 -0
  261. package/src/components/inputs/TextAreaField/index.ts +5 -0
  262. package/src/components/inputs/TextAreaField/style.ts +28 -0
  263. package/src/components/inputs/TextField/Controlled.tsx +120 -0
  264. package/src/components/inputs/TextField/Generic.tsx +113 -0
  265. package/src/components/inputs/TextField/TextField.stories.tsx +196 -0
  266. package/src/components/inputs/TextField/index.ts +5 -0
  267. package/src/components/inputs/TextField/style.ts +97 -0
  268. package/src/components/inputs/TextField/util.ts +19 -0
  269. package/src/components/inputs/ValueConfirmationField/ValueConfirmationField.stories.tsx +33 -0
  270. package/src/components/inputs/ValueConfirmationField/index.tsx +54 -0
  271. package/src/components/inputs/index.ts +67 -0
  272. package/src/components/inputs/layout/Description.tsx +40 -0
  273. package/src/components/inputs/layout/ErrorMessage/ErrorMessage.stories.tsx +28 -0
  274. package/src/components/inputs/layout/ErrorMessage/index.tsx +63 -0
  275. package/src/components/inputs/layout/InputWrapper.ts +6 -0
  276. package/src/components/inputs/layout/Label/index.tsx +71 -0
  277. package/src/components/inputs/layout/Label/style.ts +51 -0
  278. package/src/components/inputs/layout/index.ts +6 -0
  279. package/src/components/inputs/selects/SelectField/Controlled.tsx +130 -0
  280. package/src/components/inputs/selects/SelectField/Generic/FilterInput.tsx +45 -0
  281. package/src/components/inputs/selects/SelectField/Generic/index.tsx +302 -0
  282. package/src/components/inputs/selects/SelectField/SelectField.stories.tsx +253 -0
  283. package/src/components/inputs/selects/SelectField/index.ts +5 -0
  284. package/src/components/inputs/selects/SelectField/style.ts +29 -0
  285. package/src/components/inputs/selects/SelectQueryField/Controlled.tsx +100 -0
  286. package/src/components/inputs/selects/SelectQueryField/Generic/index.tsx +300 -0
  287. package/src/components/inputs/selects/SelectQueryField/SelectQueryField.stories.tsx +260 -0
  288. package/src/components/inputs/selects/SelectQueryField/index.tsx +5 -0
  289. package/src/components/inputs/selects/SelectQueryField/style.ts +14 -0
  290. package/src/components/inputs/selects/SubComponents/Option.tsx +114 -0
  291. package/src/components/inputs/selects/SubComponents/OptionGroup.tsx +16 -0
  292. package/src/components/inputs/selects/SubComponents/index.ts +10 -0
  293. package/src/components/inputs/selects/SubComponents/style.ts +39 -0
  294. package/src/components/inputs/selects/data.ts +123 -0
  295. package/src/components/inputs/selects/index.tsx +47 -0
  296. package/src/components/inputs/selects/sharedStyle.ts +78 -0
  297. package/src/components/layout/Container/index.ts +21 -0
  298. package/src/components/layout/index.ts +1 -0
  299. package/src/components/navigation/HorizontalNav/HorizontalNav.stories.tsx +45 -0
  300. package/src/components/navigation/HorizontalNav/index.tsx +40 -0
  301. package/src/components/navigation/HorizontalNav/style.ts +83 -0
  302. package/src/components/navigation/IconNav/IconNav.stories.tsx +46 -0
  303. package/src/components/navigation/IconNav/index.tsx +49 -0
  304. package/src/components/navigation/Steppers/SlimStepper/Stepper.stories.tsx +89 -0
  305. package/src/components/navigation/Steppers/SlimStepper/index.tsx +104 -0
  306. package/src/components/navigation/Steppers/SlimStepper/style.ts +86 -0
  307. package/src/components/navigation/Steppers/Stepper/Stepper.stories.tsx +87 -0
  308. package/src/components/navigation/Steppers/Stepper/index.tsx +114 -0
  309. package/src/components/navigation/Steppers/Stepper/style.ts +105 -0
  310. package/src/components/navigation/Steppers/context.tsx +49 -0
  311. package/src/components/navigation/Steppers/reducer.ts +51 -0
  312. package/src/components/navigation/Steppers/stepStates.ts +5 -0
  313. package/src/components/navigation/Tabs/Content.tsx +36 -0
  314. package/src/components/navigation/Tabs/Context.tsx +21 -0
  315. package/src/components/navigation/Tabs/List.tsx +17 -0
  316. package/src/components/navigation/Tabs/Tabs.stories.tsx +119 -0
  317. package/src/components/navigation/Tabs/Trigger.tsx +65 -0
  318. package/src/components/navigation/Tabs/index.tsx +35 -0
  319. package/src/components/navigation/Tabs/useTabs.tsx +28 -0
  320. package/src/components/navigation/index.ts +16 -0
  321. package/src/components/other/ActionMenu/ActionMenu.stories.tsx +86 -0
  322. package/src/components/other/ActionMenu/index.tsx +55 -0
  323. package/src/components/other/ActionMenu/style.ts +48 -0
  324. package/src/components/other/ClipBoard/ClipBoard.stories.tsx +14 -0
  325. package/src/components/other/ClipBoard/ClipBoard.test.tsx +7 -0
  326. package/src/components/other/ClipBoard/ClipBoard.test.tsx.snap +70 -0
  327. package/src/components/other/ClipBoard/index.tsx +70 -0
  328. package/src/components/other/CollapseList/CollapseList.stories.tsx +21 -0
  329. package/src/components/other/CollapseList/index.tsx +115 -0
  330. package/src/components/other/Collapsible/Collapsible.stories.tsx +19 -0
  331. package/src/components/other/Collapsible/CollapsibleContent.tsx +22 -0
  332. package/src/components/other/Collapsible/CollapsibleContext.tsx +17 -0
  333. package/src/components/other/Collapsible/CollapsibleTrigger.tsx +67 -0
  334. package/src/components/other/Collapsible/index.tsx +21 -0
  335. package/src/components/other/Company/index.tsx +45 -0
  336. package/src/components/other/Company/style.ts +58 -0
  337. package/src/components/other/Empty/Empty.stories.tsx +24 -0
  338. package/src/components/other/Empty/Empty.test.tsx +7 -0
  339. package/src/components/other/Empty/Empty.test.tsx.snap +85 -0
  340. package/src/components/other/Empty/index.tsx +87 -0
  341. package/src/components/other/PermissionsGuard/PermissionsGuard.stories.tsx +54 -0
  342. package/src/components/other/PermissionsGuard/index.tsx +43 -0
  343. package/src/components/other/index.ts +19 -0
  344. package/src/components/visual/Card/Card.stories.tsx +19 -0
  345. package/src/components/visual/Card/index.tsx +49 -0
  346. package/src/components/visual/Divider/Divider.stories.tsx +19 -0
  347. package/src/components/visual/Divider/Divider.test.tsx +7 -0
  348. package/src/components/visual/Divider/Divider.test.tsx.snap +35 -0
  349. package/src/components/visual/Divider/index.tsx +85 -0
  350. package/src/components/visual/index.ts +5 -0
  351. package/src/errors/base.ts +11 -0
  352. package/src/errors/errors.ts +109 -0
  353. package/src/errors/index.ts +14 -0
  354. package/src/helpers/camelCaseToSpaces.ts +5 -0
  355. package/src/helpers/getInitials.ts +15 -0
  356. package/src/helpers/getSnackbarProvider.tsx +57 -0
  357. package/src/helpers/getTransition.ts +9 -0
  358. package/src/helpers/index.ts +5 -0
  359. package/src/helpers/makeData.ts +34 -0
  360. package/src/helpers/regexprs.ts +7 -0
  361. package/src/hooks/index.ts +9 -0
  362. package/src/hooks/useCallbackRef.tsx +17 -0
  363. package/src/hooks/useDebounce.tsx +22 -0
  364. package/src/hooks/useFocus.tsx +10 -0
  365. package/src/hooks/useLocalStorage.tsx +38 -0
  366. package/src/hooks/useLockScroll.ts +26 -0
  367. package/src/hooks/useOnScreen.ts +24 -0
  368. package/src/hooks/useOutsideAlerter.tsx +15 -0
  369. package/src/hooks/useTableActions.ts +56 -0
  370. package/src/hooks/useTheme.tsx +7 -0
  371. package/src/images/company-icon-primary.svg +3 -0
  372. package/src/images/company-icon-secondary.svg +3 -0
  373. package/src/images/index.ts +4 -0
  374. package/src/index.ts +9 -0
  375. package/src/stories/Colors.stories.mdx +35 -0
  376. package/src/stories/Elevation.stories.mdx +56 -0
  377. package/src/stories/Introduction.stories.mdx +17 -0
  378. package/src/stories/Spacing.stories.mdx +25 -0
  379. package/src/styled/GlobalStyle.ts +207 -0
  380. package/src/styled/Snackbar.tsx +42 -0
  381. package/src/styled/animations.ts +36 -0
  382. package/src/styled/breakpoint.ts +7 -0
  383. package/src/styled/device.ts +10 -0
  384. package/src/styled/elevation.ts +20 -0
  385. package/src/styled/index.ts +11 -0
  386. package/src/styled/spacing.ts +38 -0
  387. package/src/styled/theme.ts +87 -0
  388. package/src/styled/types.ts +5 -0
  389. package/src/styled/zIndex.ts +31 -0
  390. package/src/test/__mocks__/fileMock.ts +2 -0
  391. package/src/test/setupTests.ts +3 -0
  392. package/src/test/snapshotResolver.js +21 -0
  393. package/src/test/testUtils.tsx +31 -0
  394. package/src/types/index.ts +1 -0
  395. package/src/types/json.ts +5 -0
  396. package/src/views/LoadingPage.tsx +36 -0
  397. package/src/views/index.ts +1 -0
  398. package/tsconfig.json +19 -0
@@ -0,0 +1,100 @@
1
+ import { FC, PropsWithChildren, useState } from 'react';
2
+ import { useController } from 'react-hook-form';
3
+ import { ControlledInputProps, defaultInputPropsFactory, defaultInputProps } from '../../InputProps';
4
+ import { GenericSelectQueryField, SelectQueryFieldProps } from './Generic';
5
+ import { Option, OptionGroup, SubComponentTypes } from '../SubComponents';
6
+ import { ErrorMessage, Label, InputWrapper, Description } from '../../layout';
7
+ import { Container } from '../sharedStyle';
8
+
9
+ export type ControlledSelectQueryFieldProps = PropsWithChildren<SelectQueryFieldProps & ControlledInputProps>;
10
+
11
+ const defaultsApplier = defaultInputPropsFactory<ControlledSelectQueryFieldProps>(defaultInputProps);
12
+
13
+ export const ControlledSelectQueryField: FC<ControlledSelectQueryFieldProps> & SubComponentTypes = (props) => {
14
+ const {
15
+ required,
16
+ size: componentSize,
17
+ label,
18
+ children,
19
+ placeholder,
20
+ readOnly,
21
+ render,
22
+ disabled,
23
+ hint,
24
+ description,
25
+ canClear,
26
+ name,
27
+ multiple,
28
+ control,
29
+ inPortal,
30
+ debounce,
31
+ isLoadingData,
32
+ handleInputValueChange,
33
+ } = defaultsApplier(props);
34
+
35
+ const {
36
+ field,
37
+ fieldState: { error },
38
+ } = useController({
39
+ name,
40
+ control,
41
+ });
42
+
43
+ const [showError, setShowError] = useState<boolean>(true);
44
+
45
+ const handleOnBlur = () => {
46
+ field.onBlur();
47
+ setShowError(true);
48
+ };
49
+
50
+ const handleOnFocus = () => {
51
+ setShowError(false);
52
+ };
53
+
54
+ return (
55
+ <InputWrapper>
56
+ <Container>
57
+ {label && (
58
+ <Label
59
+ error={!!error}
60
+ text={label}
61
+ required={required}
62
+ position="top"
63
+ size={componentSize}
64
+ disabled={disabled}
65
+ hint={hint}
66
+ />
67
+ )}
68
+ <GenericSelectQueryField
69
+ name={name}
70
+ id={name}
71
+ isLoadingData={isLoadingData}
72
+ hasError={!!error}
73
+ placeholder={placeholder}
74
+ hasDescription={!!description}
75
+ readOnly={readOnly}
76
+ render={render}
77
+ disabled={disabled}
78
+ multiple={multiple}
79
+ required={required}
80
+ size={componentSize}
81
+ inPortal={inPortal}
82
+ onChange={field.onChange}
83
+ onBlur={handleOnBlur}
84
+ canClear={canClear}
85
+ onFocus={handleOnFocus}
86
+ value={field.value}
87
+ debounce={debounce}
88
+ handleInputValueChange={handleInputValueChange}
89
+ >
90
+ {children}
91
+ </GenericSelectQueryField>
92
+ {error && error.message && showError && <ErrorMessage message={error.message} />}
93
+ </Container>
94
+ {description && <Description description={description} inputName={name} />}
95
+ </InputWrapper>
96
+ );
97
+ };
98
+
99
+ ControlledSelectQueryField.OptionGroup = OptionGroup;
100
+ ControlledSelectQueryField.Option = Option;
@@ -0,0 +1,300 @@
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
+ useFloating,
20
+ useInteractions,
21
+ useRole,
22
+ offset,
23
+ useClick,
24
+ } from '@floating-ui/react';
25
+ import { AiOutlineSearch as SearchIcon, AiOutlineClose as ClearIcon } from 'react-icons/ai';
26
+ import { defaultInputProps, defaultInputPropsFactory, GenericInputPropsFunctionHandlers } from '../../../InputProps';
27
+ import { useDebounce } from '../../../../../hooks';
28
+ import { setAriaDescribedBy } from '../../../layout';
29
+ import { FeedBackContainer } from '../style';
30
+ import { SelectItem, SelectContext, getLabelFromChildren } from '../../';
31
+
32
+ /* The SearchField depends on a few things of <Select/> */
33
+ import { GroupLabel } from '../../SelectField/style';
34
+ import { SelectContainer, SelectButton, StyledArrowIcon, StyledFloatingOverlay } from '../../sharedStyle';
35
+ import { IconButton, Spinner } from '../../../../../components';
36
+ import { GenericTextField } from '../../../TextField/Generic';
37
+
38
+ interface SharedSelectQueryFieldProps {
39
+ // Enables loading data feedback for user
40
+ isLoadingData?: boolean;
41
+ /// The placeholder text to show when the input is empty
42
+ placeholder?: string;
43
+ /// Debounce time in milliseconds (when clientside data it should be 0)
44
+ debounce?: number;
45
+ /// Triggered whenever the input value changes, debounced by 0.5 seconds.
46
+ /// This is used to trigger the API call to get the new options
47
+ handleInputValueChange: (value: string) => void;
48
+ /// render inPortal
49
+ inPortal?: boolean;
50
+
51
+ /// When true, The select icon will be replaced by a cross icon to clear the selected value.
52
+ canClear?: boolean;
53
+
54
+ /// The selected items shown in the select field
55
+ render?: (selectedItems: SelectItem[]) => React.ReactNode;
56
+ }
57
+
58
+ interface SingleSelectQueryFieldProps extends SharedSelectQueryFieldProps {
59
+ multiple?: false;
60
+ }
61
+ interface MultiSelectQueryFieldProps extends SharedSelectQueryFieldProps {
62
+ multiple: true;
63
+ }
64
+
65
+ interface SingleSelectQueryFieldHandlers extends GenericInputPropsFunctionHandlers<string, HTMLDivElement> {
66
+ onChange: (val: string) => void;
67
+ }
68
+
69
+ interface MultiSelectQueryFieldHandlers extends GenericInputPropsFunctionHandlers<string[], HTMLDivElement> {
70
+ onChange: (val: string[]) => void;
71
+ }
72
+
73
+ export type SelectQueryFieldProps = SingleSelectQueryFieldProps | MultiSelectQueryFieldProps;
74
+ export type GenericSelectQueryFieldProps = PropsWithChildren<
75
+ | (SingleSelectQueryFieldProps & SingleSelectQueryFieldHandlers)
76
+ | (MultiSelectQueryFieldProps & MultiSelectQueryFieldHandlers)
77
+ >;
78
+ const defaultsApplier = defaultInputPropsFactory<GenericSelectQueryFieldProps>(defaultInputProps);
79
+
80
+ export interface InputValue {
81
+ value: string;
82
+ label: string;
83
+ /// When the user selects an option from the list, there is no need to do another API call
84
+ shouldUpdate: boolean;
85
+ }
86
+
87
+ export const GenericSelectQueryField = forwardRef<HTMLInputElement, GenericSelectQueryFieldProps>((props, ref) => {
88
+ const {
89
+ onBlur = () => {},
90
+ onFocus = () => {},
91
+ onChange,
92
+ name,
93
+ disabled,
94
+ value,
95
+ id,
96
+ placeholder = 'Search field',
97
+ hasDescription,
98
+ inPortal = false,
99
+ hasError,
100
+ children,
101
+ readOnly,
102
+ render,
103
+ multiple = false,
104
+ canClear = false,
105
+ debounce = 250,
106
+ isLoadingData: isLoading = false,
107
+ handleInputValueChange,
108
+ } = defaultsApplier(props);
109
+
110
+ const [open, setOpen] = useState<boolean>(false);
111
+ const [inputValue, setInputValue] = useState<InputValue>({ value: '', shouldUpdate: false, label: '' });
112
+ const [activeIndex, setActiveIndex] = useState<number | null>(null);
113
+ const [selectedItems, setSelectedItems] = useState<SelectItem[]>([]);
114
+
115
+ const debouncedValue = useDebounce(inputValue.value, debounce);
116
+ const listItemsRef = useRef<Array<HTMLLIElement | null>>([]);
117
+
118
+ useEffect(() => {
119
+ if (debouncedValue && inputValue.shouldUpdate) handleInputValueChange(debouncedValue);
120
+ }, [debouncedValue]);
121
+
122
+ const { refs, strategy, x, y, context } = useFloating<HTMLInputElement>({
123
+ whileElementsMounted: autoUpdate,
124
+ open,
125
+ onOpenChange: readOnly || disabled ? () => {} : setOpen,
126
+ middleware: [
127
+ offset(5),
128
+ size({
129
+ apply({ rects, elements }) {
130
+ Object.assign(elements.floating.style, {
131
+ width: `${rects.reference.width}px`,
132
+ maxHeight: '255px',
133
+ });
134
+ },
135
+ padding: 10,
136
+ }),
137
+ ],
138
+ });
139
+
140
+ const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
141
+ useClick(context),
142
+ useRole(context, { role: 'listbox' }),
143
+ useDismiss(context),
144
+ ]);
145
+
146
+ function onInputChange(event: React.ChangeEvent<HTMLInputElement>) {
147
+ const value = event.target.value;
148
+ setInputValue({ value, shouldUpdate: true, label: value });
149
+ if (value) {
150
+ setActiveIndex(0);
151
+ }
152
+ }
153
+
154
+ const handleClear = (e: MouseEvent) => {
155
+ e.preventDefault();
156
+ e.stopPropagation();
157
+ setSelectedItems([]);
158
+
159
+ // the undefined is an expection
160
+ if (onChange) onChange(multiple ? ([] as string[]) : (undefined as any));
161
+ };
162
+
163
+ /* This handles the case where the value is changed externally (e.g. from a parent component) */
164
+ /* 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
165
+ * which ends up not running this useEffect. Meaning we still need to update the selectedIndex when clicked on an option.
166
+ */
167
+ useEffect(() => {
168
+ // Function to create an item with a value and label
169
+ const createItem = (v: string) => ({ value: v, label: getLabelFromChildren(children, v) as unknown as string });
170
+
171
+ if (Array.isArray(value)) {
172
+ const items = value.map(createItem);
173
+ setSelectedItems(items);
174
+ } else if (typeof value === 'string' && value !== '') {
175
+ setSelectedItems([createItem(value)]);
176
+ }
177
+ }, [value, children]);
178
+
179
+ const renderSelect = () => {
180
+ const hasOptions = options && Children.count(options[0].props.children) > 1;
181
+
182
+ // initialFocus=-1 is used to prevent the first item from being focused when the list opens
183
+ return (
184
+ <FloatingFocusManager context={context} visuallyHiddenDismiss initialFocus={-1}>
185
+ <SelectContainer
186
+ {...getFloatingProps({
187
+ ref: refs.setFloating,
188
+ style: {
189
+ position: strategy,
190
+ top: y ?? 0,
191
+ left: x ?? 0,
192
+ overflow: 'auto',
193
+ borderBottom: '10px solid transparent',
194
+ },
195
+ })}
196
+ >
197
+ <GenericTextField
198
+ id={`${name}-input`}
199
+ name={`${name}-input`}
200
+ hasDescription={false}
201
+ icon={<SearchIcon />}
202
+ hasError={hasError}
203
+ value={inputValue.value}
204
+ onChange={onInputChange}
205
+ placeholder={placeholder}
206
+ ref={ref}
207
+ />
208
+ {/* it will always contain 1 because of the group label */}
209
+ {isLoading && (
210
+ <FeedBackContainer>
211
+ <Spinner size="small" />
212
+ <span style={{ marginLeft: '10px' }}>loading results</span>
213
+ </FeedBackContainer>
214
+ )}
215
+ {hasOptions && options}
216
+ {/* Basically first interaction */}
217
+ {!hasOptions && inputValue.value === '' && <FeedBackContainer>Start typing to search</FeedBackContainer>}
218
+ {/* When there is no result */}
219
+ {!hasOptions && !isLoading && inputValue.value !== '' && (
220
+ <FeedBackContainer>No results found</FeedBackContainer>
221
+ )}
222
+ </SelectContainer>
223
+ </FloatingFocusManager>
224
+ );
225
+ };
226
+
227
+ const options = useMemo(() => {
228
+ return [
229
+ ...(Children.map(
230
+ children,
231
+ (child) =>
232
+ isValidElement(child) && (
233
+ <ul key={child.props.label} role="group" aria-labelledby={`select-${child.props.label}`}>
234
+ {child.props.label && (
235
+ <GroupLabel role="presentation" id={`select-${child.props.label}`} aria-hidden="true">
236
+ {child.props.label}
237
+ </GroupLabel>
238
+ )}
239
+ {Children.map(child.props.children, (option) => {
240
+ return cloneElement(option, {
241
+ onChange: onChange,
242
+ });
243
+ })}
244
+ </ul>
245
+ )
246
+ ) ?? []),
247
+ ];
248
+ }, [children]);
249
+
250
+ return (
251
+ <SelectContext.Provider
252
+ value={{
253
+ listRef: listItemsRef,
254
+ setOpen,
255
+ getItemProps,
256
+ setActiveIndex,
257
+ activeIndex,
258
+ dataRef: context.dataRef,
259
+ multiple,
260
+ selectedItems,
261
+ setSelectedItems,
262
+ name,
263
+ }}
264
+ >
265
+ <SelectButton
266
+ id={id}
267
+ ref={refs.setReference}
268
+ disabled={disabled}
269
+ readOnly={readOnly}
270
+ onBlur={onBlur}
271
+ onFocus={onFocus}
272
+ isOpen={open}
273
+ tabIndex={disabled ? -1 : 0}
274
+ hasError={hasError}
275
+ aria-describedby={setAriaDescribedBy(name, hasDescription)}
276
+ {...getReferenceProps()}
277
+ >
278
+ {render ? (
279
+ render(selectedItems)
280
+ ) : (
281
+ <div>{selectedItems.length === 0 ? 'Select' : selectedItems.map((item) => item.label).join(', ')}</div>
282
+ )}
283
+
284
+ {!readOnly && canClear && selectedItems.length > 0 && !open ? (
285
+ <IconButton size="tiny" icon={<ClearIcon />} ariaLabel="clear" onClick={(e) => handleClear(e)} />
286
+ ) : (
287
+ <StyledArrowIcon size={16} />
288
+ )}
289
+ </SelectButton>
290
+ {open &&
291
+ (!inPortal ? (
292
+ <StyledFloatingOverlay lockScroll style={{ zIndex: 1000 }}>
293
+ {renderSelect()}
294
+ </StyledFloatingOverlay>
295
+ ) : (
296
+ <FloatingPortal>{renderSelect()}</FloatingPortal>
297
+ ))}
298
+ </SelectContext.Provider>
299
+ );
300
+ });
@@ -0,0 +1,260 @@
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
+ name="film"
73
+ >
74
+ {/* In this case the label is the same as the value but ofcourse that can differ*/}
75
+ <SelectQueryField.OptionGroup>
76
+ {options?.map(({ name, icon }) => (
77
+ <SelectQueryField.Option key={name} value={name} label={name}>
78
+ <div style={{ display: 'flex', alignItems: 'center' }}>
79
+ <img src={icon} width="20px" height="20px" style={{ borderRadius: '50%', marginRight: '10px' }} />
80
+ <span>{name}</span>
81
+ </div>
82
+ </SelectQueryField.Option>
83
+ ))}
84
+ </SelectQueryField.OptionGroup>
85
+ </SelectQueryField>
86
+ <Button type="submit" text="Submit form" />
87
+ </form>
88
+ This is the submitted value:
89
+ <div>{result}</div>
90
+ </>
91
+ );
92
+ };
93
+
94
+ export const ClientSideSubmit: StoryFn<SelectQueryFieldProps> = (args) => {
95
+ interface FormValues {
96
+ film: string;
97
+ }
98
+
99
+ const { control, handleSubmit } = useForm<FormValues>();
100
+ const [options, setOptions] = useState<Film[]>();
101
+ const [result, setResult] = useState<string>('');
102
+
103
+ // Function to handle the simulated API call
104
+ // This function will be called each time the input changes
105
+ const handleInputChange = (value: string) => {
106
+ // Start loading
107
+ const filteredOptions = films.filter((film) => film.name.toLowerCase().trim().includes(value.toLowerCase()));
108
+ setOptions(filteredOptions);
109
+ };
110
+
111
+ const onSubmit: SubmitHandler<FormValues> = ({ film }) => {
112
+ setResult(film);
113
+ };
114
+
115
+ return (
116
+ <>
117
+ <form onSubmit={handleSubmit(onSubmit)}>
118
+ <SelectQueryField
119
+ control={control}
120
+ placeholder="Search for a film"
121
+ label="Film"
122
+ canClear={args.canClear}
123
+ /* The onChange returns the not debounced value, probably never needed, but is inherited by all inputFields */
124
+ handleInputValueChange={handleInputChange}
125
+ required={false}
126
+ debounce={0}
127
+ name="film"
128
+ >
129
+ {/* In this case the label is the same as the value but ofcourse that can differ*/}
130
+ <SelectQueryField.OptionGroup>
131
+ {options?.map(({ name, icon, decade }) => (
132
+ <SelectQueryField.Option key={name} value={decade} label={name}>
133
+ <div style={{ display: 'flex', alignItems: 'center' }}>
134
+ <img src={icon} width="20px" height="20px" style={{ borderRadius: '50%', marginRight: '10px' }} />
135
+ <span>{name}</span>
136
+ </div>
137
+ </SelectQueryField.Option>
138
+ ))}
139
+ </SelectQueryField.OptionGroup>
140
+ </SelectQueryField>
141
+ <Button type="submit" text="Submit form" />
142
+ </form>
143
+ The result returns the decade of the film:
144
+ <div>{result}</div>
145
+ </>
146
+ );
147
+ };
148
+
149
+ export const ClientSideMultiSelectSubmit: StoryFn<SelectQueryFieldProps> = (args) => {
150
+ interface FormValues {
151
+ films: string[];
152
+ }
153
+
154
+ const validationSchema = z.object({
155
+ films: z.array(z.string()).nonempty(),
156
+ });
157
+
158
+ const { control, handleSubmit } = useForm<FormValues>({
159
+ resolver: zodResolver(validationSchema),
160
+ });
161
+ const [options, setOptions] = useState<Film[]>();
162
+ const [result, setResult] = useState<string[]>([]);
163
+
164
+ // Function to handle the simulated API call
165
+ // This function will be called each time the input changes
166
+ const handleInputChange = (value: string) => {
167
+ // Start loading
168
+ const filteredOptions = films.filter((film) => film.name.toLowerCase().trim().includes(value.toLowerCase()));
169
+ setOptions(filteredOptions);
170
+ };
171
+
172
+ const onSubmit: SubmitHandler<FormValues> = ({ films }) => {
173
+ if (films && films.length === 0) return;
174
+ setResult(films);
175
+ };
176
+
177
+ return (
178
+ <>
179
+ <form onSubmit={handleSubmit(onSubmit)}>
180
+ <SelectQueryField
181
+ control={control}
182
+ placeholder="Search for a film"
183
+ label="Film"
184
+ /* The onChange returns the not debounced value, probably never needed, but is inherited by all inputFields */
185
+ handleInputValueChange={handleInputChange}
186
+ required={false}
187
+ canClear={args.canClear}
188
+ debounce={0}
189
+ multiple
190
+ name="films"
191
+ >
192
+ {/* In this case the label is the same as the value but ofcourse that can differ*/}
193
+ <SelectQueryField.OptionGroup>
194
+ {options?.map(({ name, icon }) => (
195
+ <SelectQueryField.Option key={name} value={name} label={name}>
196
+ <div style={{ display: 'flex', alignItems: 'center' }}>
197
+ <img src={icon} width="20px" height="20px" style={{ borderRadius: '50%', marginRight: '10px' }} />
198
+ <span>{name}</span>
199
+ </div>
200
+ </SelectQueryField.Option>
201
+ ))}
202
+ </SelectQueryField.OptionGroup>
203
+ </SelectQueryField>
204
+ <Button type="submit" text="Submit form" />
205
+ </form>
206
+ Selected films:
207
+ <div>{result && result.join(',')}</div>
208
+ </>
209
+ );
210
+ };
211
+
212
+ export const Generic: StoryFn<SelectQueryFieldProps> = () => {
213
+ const [options, setOptions] = useState<Film[]>();
214
+ const [result, setResult] = useState<string[]>([]);
215
+
216
+ // Function to handle the simulated API call
217
+ // This function will be called each time the input changes
218
+ const handleInputChange = (value: string) => {
219
+ // Start loading
220
+ const filteredOptions = films.filter((film) => film.name.toLowerCase().trim().includes(value.toLowerCase()));
221
+ setOptions(filteredOptions);
222
+ };
223
+
224
+ const onChange = (values: string[]) => {
225
+ setResult(values);
226
+ };
227
+
228
+ return (
229
+ <>
230
+ <GenericSelectQueryField
231
+ id="films"
232
+ onChange={onChange}
233
+ placeholder="Search for a film"
234
+ /* The onChange returns the not debounced value, probably never needed, but is inherited by all inputFields */
235
+ handleInputValueChange={handleInputChange}
236
+ required={false}
237
+ debounce={0}
238
+ multiple
239
+ hasError={false}
240
+ hasDescription={false}
241
+ value={result}
242
+ name="film"
243
+ >
244
+ {/* In this case the label is the same as the value but ofcourse that can differ*/}
245
+ <SelectQueryField.OptionGroup>
246
+ {options?.map(({ name, icon }) => (
247
+ <SelectQueryField.Option key={name} value={name} label={name}>
248
+ <div style={{ display: 'flex', alignItems: 'center' }}>
249
+ <img src={icon} width="20px" height="20px" style={{ borderRadius: '50%', marginRight: '10px' }} />
250
+ <span>{name}</span>
251
+ </div>
252
+ </SelectQueryField.Option>
253
+ ))}
254
+ </SelectQueryField.OptionGroup>
255
+ </GenericSelectQueryField>
256
+ Selected films:
257
+ <div>{result.map((film) => film).join(',')}</div>
258
+ </>
259
+ );
260
+ };
@@ -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,14 @@
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
+ padding-top: ${({ theme }) => theme.spacing['1']};
9
+
10
+ // loading
11
+ span {
12
+ margin-left: ${({ theme }) => theme.spacing['1']};
13
+ }
14
+ `;