@tpzdsp/next-toolkit 2.5.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (357) hide show
  1. package/package.json +21 -12
  2. package/src/assets/styles/globals.css +75 -95
  3. package/src/assets/styles/ol.css +57 -16
  4. package/src/assets/styles/utils.css +80 -0
  5. package/src/components/Accordion/Accordion.css +85 -0
  6. package/src/components/Accordion/Accordion.stories.tsx +264 -0
  7. package/src/components/Accordion/Accordion.tsx +98 -0
  8. package/src/components/Alert/Alert.css +129 -0
  9. package/src/components/Alert/Alert.stories.tsx +291 -0
  10. package/src/components/Alert/Alert.tsx +76 -0
  11. package/src/components/BackLink/BackLink.css +12 -0
  12. package/src/components/BackLink/BackLink.stories.tsx +52 -0
  13. package/src/components/BackLink/BackLink.tsx +44 -0
  14. package/src/components/BackToTop/BackToTop.css +23 -0
  15. package/src/components/BackToTop/BackToTop.stories.tsx +41 -0
  16. package/src/components/BackToTop/BackToTop.tsx +48 -0
  17. package/src/components/Breadcrumb/Breadcrumb.css +42 -0
  18. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +94 -0
  19. package/src/components/Breadcrumb/Breadcrumb.tsx +135 -0
  20. package/src/components/Button/Button.css +229 -0
  21. package/src/components/Button/Button.stories.tsx +140 -20
  22. package/src/components/Button/Button.tsx +53 -28
  23. package/src/components/Button/ButtonSkeleton.stories.tsx +50 -0
  24. package/src/components/Button/ButtonSkeleton.tsx +14 -0
  25. package/src/components/ButtonGroup/ButtonGroup.css +52 -0
  26. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +156 -0
  27. package/src/components/ButtonGroup/ButtonGroup.tsx +50 -0
  28. package/src/components/ButtonLink/ButtonLink.css +114 -0
  29. package/src/components/ButtonLink/ButtonLink.stories.tsx +38 -51
  30. package/src/components/ButtonLink/ButtonLink.tsx +54 -23
  31. package/src/components/Card/Card.css +13 -0
  32. package/src/components/Card/Card.stories.tsx +98 -57
  33. package/src/components/Card/Card.tsx +4 -13
  34. package/src/components/CardGroup/CardGroup.css +10 -0
  35. package/src/components/CardGroup/CardGroup.stories.tsx +81 -0
  36. package/src/components/CardGroup/CardGroup.tsx +9 -0
  37. package/src/components/Checkbox/Checkbox.css +49 -0
  38. package/src/components/Checkbox/Checkbox.stories.tsx +86 -0
  39. package/src/components/Checkbox/Checkbox.tsx +32 -0
  40. package/src/components/Chip/Chip.css +54 -0
  41. package/src/components/Chip/Chip.stories.tsx +94 -0
  42. package/src/components/Chip/Chip.tsx +34 -0
  43. package/src/components/CookieBanner/CookieBanner.css +19 -0
  44. package/src/components/CookieBanner/CookieBanner.stories.tsx +52 -0
  45. package/src/components/CookieBanner/CookieBanner.tsx +55 -0
  46. package/src/components/CopyButton/CopyButton.stories.tsx +28 -0
  47. package/src/components/CopyButton/CopyButton.tsx +65 -0
  48. package/src/components/DateInput/DateInput.css +13 -0
  49. package/src/components/DateInput/DateInput.stories.tsx +131 -0
  50. package/src/components/DateInput/DateInput.test.tsx +21 -0
  51. package/src/components/DateInput/DateInput.tsx +98 -0
  52. package/src/components/Details/Details.css +28 -0
  53. package/src/components/Details/Details.stories.tsx +48 -0
  54. package/src/components/Details/Details.tsx +41 -0
  55. package/src/components/Dropdown/Dropdown.css +81 -0
  56. package/src/components/Dropdown/Dropdown.stories.tsx +131 -0
  57. package/src/components/Dropdown/Dropdown.tsx +69 -0
  58. package/src/components/ErrorBoundary/ErrorBoundary.stories.tsx +4 -39
  59. package/src/components/ErrorBoundary/ErrorBoundary.tsx +7 -4
  60. package/src/components/ErrorBoundary/ErrorFallback.tsx +32 -66
  61. package/src/components/ErrorModal/ErrorModal.css +34 -0
  62. package/src/components/ErrorModal/ErrorModal.stories.tsx +100 -0
  63. package/src/components/ErrorModal/ErrorModal.tsx +123 -0
  64. package/src/components/ErrorText/ErrorText.css +22 -0
  65. package/src/components/ErrorText/ErrorText.stories.tsx +42 -27
  66. package/src/components/ErrorText/ErrorText.tsx +10 -8
  67. package/src/components/ExternalLink/ExternalLink.css +12 -0
  68. package/src/components/ExternalLink/ExternalLink.stories.tsx +43 -0
  69. package/src/components/ExternalLink/ExternalLink.tsx +43 -0
  70. package/src/components/Fieldset/Fieldset.css +103 -0
  71. package/src/components/Fieldset/Fieldset.stories.tsx +304 -0
  72. package/src/components/Fieldset/Fieldset.tsx +38 -0
  73. package/src/components/FileUpload/FileUpload.css +85 -0
  74. package/src/components/FileUpload/FileUpload.stories.tsx +106 -0
  75. package/src/components/FileUpload/FileUpload.tsx +99 -0
  76. package/src/components/{layout/footer → Footer}/Copyright.tsx +3 -2
  77. package/src/components/Footer/Footer.stories.tsx +27 -0
  78. package/src/components/Footer/Footer.tsx +46 -0
  79. package/src/components/Footer/Licence.tsx +18 -0
  80. package/src/components/Footer/MetaLinks.tsx +47 -0
  81. package/src/components/Footer/Small/SmallFooter.stories.tsx +3 -0
  82. package/src/components/Footer/Small/SmallFooter.tsx +53 -41
  83. package/src/components/Form/FormGroup.css +18 -0
  84. package/src/components/Form/FormGroup.stories.tsx +87 -0
  85. package/src/components/Form/FormGroup.tsx +16 -0
  86. package/src/components/{layout/header → Header}/Header.stories.tsx +26 -12
  87. package/src/components/Header/Header.test.tsx +87 -0
  88. package/src/components/Header/Header.tsx +304 -0
  89. package/src/components/Header/HeaderAppContent.tsx +120 -0
  90. package/src/components/Heading/Heading.css +40 -0
  91. package/src/components/Heading/Heading.stories.tsx +15 -5
  92. package/src/components/Heading/Heading.tsx +21 -44
  93. package/src/components/Heading/HeadingSkeleton.stories.tsx +30 -0
  94. package/src/components/Heading/HeadingSkeleton.tsx +14 -0
  95. package/src/components/Hero/Hero.css +19 -0
  96. package/src/components/Hero/Hero.stories.tsx +41 -0
  97. package/src/components/Hero/Hero.tsx +14 -0
  98. package/src/components/HintText/HintText.css +5 -0
  99. package/src/components/HintText/HintText.stories.tsx +29 -0
  100. package/src/components/HintText/HintText.tsx +13 -0
  101. package/src/components/InfoBox/InfoBox.css +38 -0
  102. package/src/components/InfoBox/InfoBox.stories.tsx +51 -403
  103. package/src/components/InfoBox/InfoBox.tsx +31 -158
  104. package/src/components/Input/Input.css +77 -0
  105. package/src/components/Input/Input.stories.tsx +123 -0
  106. package/src/components/Input/Input.tsx +74 -0
  107. package/src/components/InputGroup/InputGroup.css +140 -0
  108. package/src/components/InputGroup/InputGroup.stories.tsx +125 -0
  109. package/src/components/InputGroup/InputGroup.tsx +47 -0
  110. package/src/components/InsetText/InsetText.css +5 -0
  111. package/src/components/InsetText/InsetText.stories.tsx +30 -0
  112. package/src/components/InsetText/InsetText.tsx +9 -0
  113. package/src/components/Keyboard/Keyboard.css +9 -0
  114. package/src/components/Keyboard/Keyboard.stories.tsx +63 -0
  115. package/src/components/Keyboard/Keyboard.tsx +30 -0
  116. package/src/components/Label/Label.css +27 -0
  117. package/src/components/Label/Label.stories.tsx +40 -0
  118. package/src/components/Label/Label.tsx +17 -0
  119. package/src/components/LayerSwitcher/LayerSwitcher.css +59 -0
  120. package/src/components/LayerSwitcher/LayerSwitcher.stories.tsx +112 -0
  121. package/src/components/LayerSwitcher/LayerSwitcher.tsx +61 -0
  122. package/src/components/Layout/401/401.stories.tsx +23 -0
  123. package/src/components/Layout/401/401.tsx +1 -0
  124. package/src/components/Layout/403/403.stories.tsx +23 -0
  125. package/src/components/Layout/403/403.tsx +21 -0
  126. package/src/components/Layout/404/404.stories.tsx +23 -0
  127. package/src/components/Layout/404/404.tsx +28 -0
  128. package/src/components/Layout/500/500.stories.tsx +56 -0
  129. package/src/components/Layout/500/500.tsx +63 -0
  130. package/src/components/Layout/ButtonGroup/ButtonGroup.css +52 -0
  131. package/src/components/Layout/ButtonGroup/ButtonGroup.stories.tsx +156 -0
  132. package/src/components/Layout/ButtonGroup/ButtonGroup.tsx +50 -0
  133. package/src/components/Layout/HeadingGroup/HeadingGroup.css +21 -0
  134. package/src/components/Layout/HeadingGroup/HeadingGroup.stories.tsx +84 -0
  135. package/src/components/Layout/HeadingGroup/HeadingGroup.tsx +9 -0
  136. package/src/components/Layout/MainWrapper/MainWrapper.css +12 -0
  137. package/src/components/Layout/MainWrapper/MainWrapper.stories.tsx +36 -0
  138. package/src/components/Layout/MainWrapper/MainWrapper.tsx +14 -0
  139. package/src/components/Layout/PageShell/PageShell.css +42 -0
  140. package/src/components/Layout/PageShell/PageShell.stories.tsx +108 -0
  141. package/src/components/Layout/PageShell/PageShell.tsx +31 -0
  142. package/src/components/Layout/ParagraphGroup/ParagraphGroup.css +5 -0
  143. package/src/components/Layout/ParagraphGroup/ParagraphGroup.stories.tsx +34 -0
  144. package/src/components/Layout/ParagraphGroup/ParagraphGroup.tsx +9 -0
  145. package/src/components/Layout/Stack/Stack.css +29 -0
  146. package/src/components/Layout/Stack/Stack.stories.tsx +83 -0
  147. package/src/components/Layout/Stack/Stack.tsx +19 -0
  148. package/src/components/Layout/WidthContainer/WidthContainer.css +17 -0
  149. package/src/components/Layout/WidthContainer/WidthContainer.stories.tsx +59 -0
  150. package/src/components/Layout/WidthContainer/WidthContainer.tsx +13 -0
  151. package/src/components/Legend/Legend.css +95 -0
  152. package/src/components/Legend/Legend.stories.tsx +81 -0
  153. package/src/components/Legend/Legend.tsx +32 -0
  154. package/src/components/Legend/LegendDot.tsx +15 -0
  155. package/src/components/Legend/LegendPanel.stories.tsx +101 -0
  156. package/src/components/Legend/LegendPanel.tsx +68 -0
  157. package/src/components/Legend/LegendSkeleton.stories.tsx +87 -0
  158. package/src/components/Legend/LegendSkeleton.tsx +73 -0
  159. package/src/components/LegendSelect/LegendSelect.css +8 -0
  160. package/src/components/LegendSelect/LegendSelect.stories.tsx +80 -0
  161. package/src/components/LegendSelect/LegendSelect.tsx +26 -0
  162. package/src/components/Link/Link.css +98 -0
  163. package/src/components/Link/Link.stories.tsx +70 -0
  164. package/src/components/Link/Link.tsx +52 -0
  165. package/src/components/LinkButton/LinkButton.css +67 -0
  166. package/src/components/LinkButton/LinkButton.stories.tsx +90 -42
  167. package/src/components/LinkButton/LinkButton.tsx +50 -63
  168. package/src/components/LinkList/LinkList.css +28 -0
  169. package/src/components/LinkList/LinkList.stories.tsx +46 -0
  170. package/src/components/LinkList/LinkList.tsx +23 -0
  171. package/src/components/List/Li.tsx +9 -0
  172. package/src/components/List/List.css +9 -0
  173. package/src/components/List/OrderedList.stories.tsx +36 -0
  174. package/src/components/List/OrderedList.tsx +9 -0
  175. package/src/components/List/UnorderedList.stories.tsx +36 -0
  176. package/src/components/List/UnorderedList.tsx +9 -0
  177. package/src/components/LoadingBox/LoadingBox.css +27 -0
  178. package/src/components/LoadingBox/LoadingBox.stories.tsx +66 -0
  179. package/src/components/LoadingBox/LoadingBox.tsx +40 -0
  180. package/src/components/Modal/Modal.css +111 -0
  181. package/src/components/Modal/Modal.stories.tsx +94 -155
  182. package/src/components/Modal/Modal.tsx +141 -75
  183. package/src/components/NoScriptBanner/NoScriptBanner.css +17 -0
  184. package/src/components/NoScriptBanner/NoScriptBanner.stories.tsx +46 -0
  185. package/src/components/NoScriptBanner/NoScriptBanner.tsx +26 -0
  186. package/src/components/Paragraph/Paragraph.css +22 -0
  187. package/src/components/Paragraph/Paragraph.stories.tsx +1 -42
  188. package/src/components/Paragraph/Paragraph.tsx +4 -3
  189. package/src/components/Paragraph/ParagraphSkeleton.stories.tsx +44 -0
  190. package/src/components/Paragraph/ParagraphSkeleton.tsx +33 -0
  191. package/src/components/PasswordInput/PasswordInput.css +3 -0
  192. package/src/components/PasswordInput/PasswordInput.stories.tsx +47 -0
  193. package/src/components/PasswordInput/PasswordInput.tsx +45 -0
  194. package/src/components/PhaseBanner/PhaseBanner.css +12 -0
  195. package/src/components/PhaseBanner/PhaseBanner.stories.tsx +61 -0
  196. package/src/components/PhaseBanner/PhaseBanner.tsx +17 -0
  197. package/src/components/Popover/Popover.css +43 -0
  198. package/src/components/Popover/Popover.stories.tsx +102 -0
  199. package/src/components/Popover/Popover.tsx +40 -0
  200. package/src/components/Radio/Radio.css +69 -0
  201. package/src/components/Radio/Radio.stories.tsx +169 -0
  202. package/src/components/Radio/Radio.tsx +56 -0
  203. package/src/components/Resizable/Resizable.css +86 -0
  204. package/src/components/Resizable/Resizable.stories.tsx +123 -0
  205. package/src/components/Resizable/Resizable.tsx +86 -0
  206. package/src/components/ScrollArea/ScrollArea.css +9 -0
  207. package/src/components/ScrollArea/ScrollArea.stories.tsx +42 -0
  208. package/src/components/ScrollArea/ScrollArea.tsx +11 -0
  209. package/src/components/SearchBox/SearchBox.stories.tsx +88 -0
  210. package/src/components/SearchBox/SearchBox.tsx +36 -0
  211. package/src/components/Select/AsyncSelect.stories.tsx +84 -0
  212. package/src/components/Select/AsyncSelect.tsx +41 -0
  213. package/src/components/Select/Select.css +202 -0
  214. package/src/components/Select/Select.stories.tsx +162 -0
  215. package/src/components/Select/Select.test.tsx +36 -0
  216. package/src/components/Select/Select.tsx +296 -0
  217. package/src/components/Select/SelectSkeleton.stories.tsx +51 -0
  218. package/src/components/Select/SelectSkeleton.tsx +23 -0
  219. package/src/components/Separator/Separator.css +41 -0
  220. package/src/components/Separator/Separator.stories.tsx +63 -0
  221. package/src/components/Separator/Separator.tsx +42 -0
  222. package/src/components/Sidebar/ResizableSidebar.tsx +118 -0
  223. package/src/components/Sidebar/Sidebar.css +203 -0
  224. package/src/components/Sidebar/Sidebar.stories.tsx +438 -0
  225. package/src/components/Sidebar/Sidebar.tsx +225 -0
  226. package/src/components/Skeleton/Skeleton.css +16 -0
  227. package/src/components/Skeleton/Skeleton.stories.tsx +39 -0
  228. package/src/components/Skeleton/Skeleton.tsx +12 -0
  229. package/src/components/SkipLink/SkipLink.css +16 -0
  230. package/src/components/SkipLink/SkipLink.stories.tsx +40 -0
  231. package/src/components/SkipLink/SkipLink.tsx +15 -0
  232. package/src/components/Spinner/Spinner.css +30 -0
  233. package/src/components/Spinner/Spinner.stories.tsx +36 -0
  234. package/src/components/Spinner/Spinner.tsx +45 -0
  235. package/src/components/StartButton/StartButton.css +13 -0
  236. package/src/components/StartButton/StartButton.stories.tsx +68 -0
  237. package/src/components/StartButton/StartButton.tsx +50 -0
  238. package/src/components/SubmitButton/SubmitButton.stories.tsx +31 -0
  239. package/src/components/SubmitButton/SubmitButton.tsx +14 -0
  240. package/src/components/SummaryList/SummaryList.css +71 -0
  241. package/src/components/SummaryList/SummaryList.stories.tsx +211 -0
  242. package/src/components/SummaryList/SummaryList.tsx +41 -0
  243. package/src/components/SummaryList/SummaryListSkeleton.stories.tsx +67 -0
  244. package/src/components/SummaryList/SummaryListSkeleton.tsx +40 -0
  245. package/src/components/Tabs/Tabs.css +84 -0
  246. package/src/components/Tabs/Tabs.stories.tsx +133 -0
  247. package/src/components/Tabs/Tabs.tsx +66 -0
  248. package/src/components/Tag/Tag.css +8 -0
  249. package/src/components/Tag/Tag.stories.tsx +96 -0
  250. package/src/components/Tag/Tag.tsx +34 -0
  251. package/src/components/Textarea/Textarea.css +38 -0
  252. package/src/components/Textarea/Textarea.stories.tsx +131 -0
  253. package/src/components/Textarea/Textarea.tsx +50 -0
  254. package/src/components/TextareaCount/TextareaCount.css +17 -0
  255. package/src/components/TextareaCount/TextareaCount.stories.tsx +131 -0
  256. package/src/components/TextareaCount/TextareaCount.tsx +108 -0
  257. package/src/components/Tooltip/Tooltip.css +43 -0
  258. package/src/components/Tooltip/Tooltip.stories.tsx +110 -0
  259. package/src/components/Tooltip/Tooltip.tsx +53 -0
  260. package/src/components/WarningText/WarningText.css +20 -0
  261. package/src/components/WarningText/WarningText.stories.tsx +29 -0
  262. package/src/components/WarningText/WarningText.tsx +17 -0
  263. package/src/components/index.ts +343 -61
  264. package/src/errors/errorDisplay.ts +70 -0
  265. package/src/errors/index.ts +1 -0
  266. package/src/http/constants.ts +2 -0
  267. package/src/http/fetch.ts +7 -3
  268. package/src/map/LayerSwitcherPanel.tsx +2 -173
  269. package/src/map/LegendShim.tsx +2 -0
  270. package/src/map/MapComponent.tsx +7 -17
  271. package/src/map/MapControlsOverlay.tsx +68 -175
  272. package/src/map/Popup.tsx +71 -24
  273. package/src/map/geocoder/Geocoder.test.tsx +46 -3
  274. package/src/map/geocoder/Geocoder.tsx +155 -278
  275. package/src/map/index.ts +1 -1
  276. package/src/types/utils.ts +0 -10
  277. package/src/utils/components.ts +96 -0
  278. package/src/utils/index.ts +1 -0
  279. package/src/utils/utils.ts +0 -12
  280. package/src/assets/images/defra-logo.svg +0 -51
  281. package/src/assets/images/ea-logo.svg +0 -58
  282. package/src/assets/images/ogl.svg +0 -1
  283. package/src/components/Button/Button.test.tsx +0 -53
  284. package/src/components/ButtonLink/ButtonLink.test.tsx +0 -154
  285. package/src/components/Card/Card.test.tsx +0 -51
  286. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +0 -75
  287. package/src/components/ErrorBoundary/ErrorFallback.test.tsx +0 -107
  288. package/src/components/ErrorText/ErrorText.test.tsx +0 -33
  289. package/src/components/Heading/Heading.test.tsx +0 -22
  290. package/src/components/Hint/Hint.stories.tsx +0 -58
  291. package/src/components/Hint/Hint.test.tsx +0 -33
  292. package/src/components/Hint/Hint.tsx +0 -12
  293. package/src/components/InfoBox/InfoBox.test.tsx +0 -330
  294. package/src/components/InfoBox/types.ts +0 -6
  295. package/src/components/LinkButton/LinkButton.test.tsx +0 -177
  296. package/src/components/Modal/Modal.test.tsx +0 -246
  297. package/src/components/NotificationBanner/NotificationBanner.stories.tsx +0 -45
  298. package/src/components/NotificationBanner/NotificationBanner.test.tsx +0 -58
  299. package/src/components/NotificationBanner/NotificationBanner.tsx +0 -45
  300. package/src/components/Paragraph/Paragraph.test.tsx +0 -10
  301. package/src/components/SlidingPanel/SlidingPanel.stories.tsx +0 -129
  302. package/src/components/SlidingPanel/SlidingPanel.test.tsx +0 -83
  303. package/src/components/SlidingPanel/SlidingPanel.tsx +0 -258
  304. package/src/components/accordion/Accordion.stories.tsx +0 -234
  305. package/src/components/accordion/Accordion.test.tsx +0 -192
  306. package/src/components/accordion/Accordion.tsx +0 -73
  307. package/src/components/backToTop/BackToTop.stories.tsx +0 -407
  308. package/src/components/backToTop/BackToTop.test.tsx +0 -57
  309. package/src/components/backToTop/BackToTop.tsx +0 -134
  310. package/src/components/chip/Chip.stories.tsx +0 -61
  311. package/src/components/chip/Chip.test.tsx +0 -31
  312. package/src/components/chip/Chip.tsx +0 -23
  313. package/src/components/container/Container.tsx +0 -42
  314. package/src/components/cookieBanner/CookieBanner.stories.tsx +0 -257
  315. package/src/components/cookieBanner/CookieBanner.test.tsx +0 -68
  316. package/src/components/cookieBanner/CookieBanner.tsx +0 -73
  317. package/src/components/divider/RuleDivider.stories.tsx +0 -254
  318. package/src/components/divider/RuleDivider.test.tsx +0 -164
  319. package/src/components/divider/RuleDivider.tsx +0 -23
  320. package/src/components/dropdown/DropdownMenu.test.tsx +0 -211
  321. package/src/components/dropdown/DropdownMenu.tsx +0 -108
  322. package/src/components/dropdown/useDropdownMenu.ts +0 -249
  323. package/src/components/form/Input.stories.tsx +0 -435
  324. package/src/components/form/Input.test.tsx +0 -206
  325. package/src/components/form/Input.tsx +0 -23
  326. package/src/components/form/TextArea.stories.tsx +0 -464
  327. package/src/components/form/TextArea.test.tsx +0 -232
  328. package/src/components/form/TextArea.tsx +0 -23
  329. package/src/components/layout/footer/Footer.tsx +0 -26
  330. package/src/components/layout/footer/Licence.tsx +0 -19
  331. package/src/components/layout/footer/MetaLinks.tsx +0 -36
  332. package/src/components/layout/header/Header.test.tsx +0 -36
  333. package/src/components/layout/header/Header.tsx +0 -90
  334. package/src/components/layout/header/HeaderAuthClient.test.tsx +0 -45
  335. package/src/components/layout/header/HeaderAuthClient.tsx +0 -40
  336. package/src/components/layout/header/HeaderNavClient.test.tsx +0 -44
  337. package/src/components/layout/header/HeaderNavClient.tsx +0 -67
  338. package/src/components/link/ExternalLink.test.tsx +0 -102
  339. package/src/components/link/ExternalLink.tsx +0 -29
  340. package/src/components/link/Link.tsx +0 -26
  341. package/src/components/select/Select.stories.tsx +0 -336
  342. package/src/components/select/Select.test.tsx +0 -474
  343. package/src/components/select/Select.tsx +0 -125
  344. package/src/components/select/SelectSkeleton.stories.tsx +0 -194
  345. package/src/components/select/SelectSkeleton.test.tsx +0 -104
  346. package/src/components/select/SelectSkeleton.tsx +0 -23
  347. package/src/components/select/common.ts +0 -3
  348. package/src/components/select/index.ts +0 -18
  349. package/src/components/skipLink/SkipLink.stories.tsx +0 -346
  350. package/src/components/skipLink/SkipLink.test.tsx +0 -22
  351. package/src/components/skipLink/SkipLink.tsx +0 -49
  352. package/src/map/LegendPanel.tsx +0 -85
  353. /package/src/{components → assets}/images/DefraLogo.tsx +0 -0
  354. /package/src/{components → assets}/images/EaLogo.tsx +0 -0
  355. /package/src/{components → assets}/images/OglLogo.tsx +0 -0
  356. /package/src/components/{googleAnalytics → GoogleAnalytics}/GlobalVars.tsx +0 -0
  357. /package/src/components/{googleAnalytics → GoogleAnalytics}/GoogleAnalytics.tsx +0 -0
@@ -0,0 +1,66 @@
1
+ 'use client';
2
+
3
+ import type { ComponentProps } from 'react';
4
+
5
+ import { Tabs as TabsPrimitive } from 'radix-ui';
6
+
7
+ import { cn } from '../../utils/components';
8
+
9
+ export type TabsProps<T extends string> = Omit<
10
+ ComponentProps<typeof TabsPrimitive.Root>,
11
+ 'defaultValue' | 'value' | 'onValueChange'
12
+ > & {
13
+ defaultValue?: T;
14
+ value?: T;
15
+ onValueChange?: (value: T) => void;
16
+ };
17
+
18
+ export const Tabs = <T extends string = string>({
19
+ className,
20
+ defaultValue,
21
+ value,
22
+ onValueChange,
23
+ ...props
24
+ }: TabsProps<T>) => (
25
+ <TabsPrimitive.Root
26
+ data-slot="tabs"
27
+ className={cn('cn-tabs', className)}
28
+ defaultValue={defaultValue as string}
29
+ value={value as string}
30
+ onValueChange={(value) => onValueChange?.(value as T)}
31
+ {...props}
32
+ />
33
+ );
34
+
35
+ export type TabsListProps = ComponentProps<typeof TabsPrimitive.List>;
36
+
37
+ export const TabsList = ({ className, ...props }: TabsListProps) => (
38
+ <TabsPrimitive.List data-slot="tabs-list" className={cn('cn-tabs-list', className)} {...props} />
39
+ );
40
+
41
+ export type TabsTriggerProps = ComponentProps<typeof TabsPrimitive.Trigger>;
42
+
43
+ export const TabsTrigger = ({ className, children, ...props }: TabsTriggerProps) => (
44
+ <TabsPrimitive.Trigger
45
+ data-slot="tabs-trigger"
46
+ className={cn('cn-tabs-trigger', className)}
47
+ {...props}
48
+ >
49
+ {/* Bold copy reserves the active-state width so siblings never shift. */}
50
+ <span aria-hidden className="cn-tabs-trigger-sizer">
51
+ {children}
52
+ </span>
53
+
54
+ <span className="cn-tabs-trigger-text">{children}</span>
55
+ </TabsPrimitive.Trigger>
56
+ );
57
+
58
+ export type TabsContentProps = ComponentProps<typeof TabsPrimitive.Content>;
59
+
60
+ export const TabsContent = ({ className, ...props }: TabsContentProps) => (
61
+ <TabsPrimitive.Content
62
+ data-slot="tabs-content"
63
+ className={cn('cn-tabs-content', className)}
64
+ {...props}
65
+ />
66
+ );
@@ -0,0 +1,8 @@
1
+ @layer components {
2
+ /* MARK: Tag
3
+ GDS-style status label rendered as <strong> for semantic importance.
4
+ Composes Chip utilities for sizing and colour, adds font-bold on top. */
5
+ .cn-tag {
6
+ @apply cn-chip font-bold;
7
+ }
8
+ }
@@ -0,0 +1,96 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+
3
+ import { Tag } from './Tag';
4
+
5
+ const meta: Meta<typeof Tag> = {
6
+ title: 'Components/Tag',
7
+ component: Tag,
8
+ tags: ['autodocs'],
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component:
13
+ 'GDS-style status label for communicating phase, status, or category. Rendered as `<strong>` for semantic importance. Uses the same colour palette as Chip but always bold.',
14
+ },
15
+ },
16
+ },
17
+ argTypes: {
18
+ appearance: {
19
+ control: { type: 'radio' },
20
+ options: ['neutral', 'success', 'warning', 'error', 'info'],
21
+ },
22
+ size: {
23
+ control: { type: 'radio' },
24
+ options: ['sm', 'base', 'lg'],
25
+ },
26
+ children: { control: 'text' },
27
+ },
28
+ args: {
29
+ appearance: 'info',
30
+ children: 'Alpha',
31
+ size: 'base',
32
+ },
33
+ };
34
+
35
+ export default meta;
36
+
37
+ type Story = StoryObj<typeof Tag>;
38
+
39
+ export const Default: Story = {};
40
+
41
+ export const Appearances: Story = {
42
+ parameters: {
43
+ docs: {
44
+ description: {
45
+ story: 'All appearances share the same subtle tinted palette as Chip.',
46
+ },
47
+ },
48
+ },
49
+ render: (args) => (
50
+ <div className="flex flex-wrap gap-gds-2">
51
+ <Tag {...args} appearance="neutral">
52
+ Inactive
53
+ </Tag>
54
+
55
+ <Tag {...args} appearance="success">
56
+ Active
57
+ </Tag>
58
+
59
+ <Tag {...args} appearance="warning">
60
+ Pending
61
+ </Tag>
62
+
63
+ <Tag {...args} appearance="error">
64
+ Rejected
65
+ </Tag>
66
+
67
+ <Tag {...args} appearance="info">
68
+ Alpha
69
+ </Tag>
70
+ </div>
71
+ ),
72
+ };
73
+
74
+ export const Small: Story = {
75
+ args: { size: 'sm', children: 'Beta' },
76
+ };
77
+
78
+ export const Large: Story = {
79
+ args: { size: 'lg', children: 'New' },
80
+ };
81
+
82
+ export const Inline: Story = {
83
+ parameters: {
84
+ docs: {
85
+ description: {
86
+ story:
87
+ 'Tags use negative margins so they sit inline within body text without inflating line height.',
88
+ },
89
+ },
90
+ },
91
+ render: (args) => (
92
+ <p>
93
+ This service is <Tag {...args} /> and actively being developed.
94
+ </p>
95
+ ),
96
+ };
@@ -0,0 +1,34 @@
1
+ import type { ComponentProps } from 'react';
2
+
3
+ import { cn } from '../../utils/components';
4
+
5
+ const TAG_APPEARANCES = {
6
+ neutral: 'cn-chip-appearance-neutral',
7
+ success: 'cn-chip-appearance-success',
8
+ warning: 'cn-chip-appearance-warning',
9
+ error: 'cn-chip-appearance-error',
10
+ info: 'cn-chip-appearance-info',
11
+ } as const;
12
+
13
+ const TAG_SIZES = {
14
+ sm: 'cn-chip-size-sm',
15
+ base: 'cn-chip-size-base',
16
+ lg: 'cn-chip-size-lg',
17
+ } as const;
18
+
19
+ export type TagAppearance = keyof typeof TAG_APPEARANCES;
20
+ export type TagSize = keyof typeof TAG_SIZES;
21
+
22
+ export type TagProps = ComponentProps<'strong'> & {
23
+ appearance: TagAppearance;
24
+ size?: TagSize;
25
+ };
26
+
27
+ export const Tag = ({ className, appearance, size = 'base', ...props }: TagProps) => (
28
+ <strong
29
+ data-slot="tag"
30
+ data-size={size}
31
+ className={cn('cn-tag', TAG_APPEARANCES[appearance], TAG_SIZES[size], className)}
32
+ {...props}
33
+ />
34
+ );
@@ -0,0 +1,38 @@
1
+ @layer components {
2
+ /* MARK: Textarea
3
+ GDS textarea: same border and focus as Input, vertical resize only.
4
+ Height is content-driven via rows, min-height matches the input baseline. */
5
+ .cn-textarea {
6
+ @apply cn-form-border w-full p-gds-1 text-base box-border appearance-none resize-y min-h-32;
7
+
8
+ &:focus {
9
+ @apply outline-focus;
10
+ box-shadow: inset 0 0 0 var(--border-width-form) var(--color-divider-input);
11
+ }
12
+
13
+ &[aria-invalid='true'],
14
+ &:user-invalid {
15
+ @apply border-error;
16
+
17
+ &:focus {
18
+ box-shadow: inset 0 0 0 var(--border-width-form) var(--color-error);
19
+ }
20
+ }
21
+
22
+ &[readonly] {
23
+ @apply bg-wash resize-none;
24
+ }
25
+
26
+ &:disabled,
27
+ &[aria-disabled='true'] {
28
+ @apply opacity-50 cursor-not-allowed select-none;
29
+ color: inherit;
30
+ }
31
+ }
32
+
33
+ /* MARK: Appearances */
34
+ .cn-textarea-appearance-code {
35
+ font-variant-numeric: tabular-nums;
36
+ letter-spacing: 0.05em;
37
+ }
38
+ }
@@ -0,0 +1,131 @@
1
+ 'use client';
2
+
3
+ import type { Meta, StoryObj } from '@storybook/react-vite';
4
+
5
+ import { Textarea } from './Textarea';
6
+ import { CopyButton } from '../CopyButton/CopyButton';
7
+ import { ErrorText } from '../ErrorText/ErrorText';
8
+ import { FormGroup } from '../Form/FormGroup';
9
+ import { HintText } from '../HintText/HintText';
10
+ import { InputGroup, InputToolbar } from '../InputGroup/InputGroup';
11
+ import { Label } from '../Label/Label';
12
+ import { TextareaCount, TextareaCountMessage } from '../TextareaCount/TextareaCount';
13
+
14
+ const meta: Meta<typeof Textarea> = {
15
+ title: 'Components/Textarea',
16
+ component: Textarea,
17
+ tags: ['autodocs'],
18
+ parameters: {
19
+ docs: {
20
+ description: {
21
+ component:
22
+ 'GDS-style multi-line text input. Resizes vertically. Compose with `TextareaCount` and `TextareaCountMessage` to add character or word count feedback. Use a vertical `InputGroup` with `InputToolbar` to add action buttons above the field.',
23
+ },
24
+ },
25
+ },
26
+ argTypes: {
27
+ appearance: {
28
+ control: { type: 'radio' },
29
+ options: ['default', 'code'],
30
+ },
31
+ rows: { control: { type: 'number', min: 1, max: 20 } },
32
+ disabled: { control: 'boolean' },
33
+ },
34
+ args: {
35
+ rows: 5,
36
+ appearance: 'default',
37
+ },
38
+ };
39
+
40
+ export default meta;
41
+
42
+ type Story = StoryObj<typeof Textarea>;
43
+
44
+ const SHARE_URL = 'https://environment.data.gov.uk/share/flood-risk-assessment/abc123xyz';
45
+
46
+ export const Default: Story = {};
47
+
48
+ export const Invalid: Story = {
49
+ render: (args) => (
50
+ <FormGroup invalid>
51
+ <Label htmlFor="textarea-invalid">Description</Label>
52
+
53
+ <ErrorText id="textarea-invalid-error">Enter a description</ErrorText>
54
+
55
+ <Textarea
56
+ id="textarea-invalid"
57
+ aria-invalid
58
+ aria-describedby="textarea-invalid-error"
59
+ {...args}
60
+ />
61
+ </FormGroup>
62
+ ),
63
+ };
64
+
65
+ export const ReadOnly: Story = {
66
+ args: {
67
+ readOnly: true,
68
+ defaultValue: 'This text can be selected and copied but not edited.',
69
+ rows: 3,
70
+ },
71
+ };
72
+
73
+ export const Disabled: Story = {
74
+ args: { disabled: true, value: 'This content cannot be edited' },
75
+ };
76
+
77
+ export const Code: Story = {
78
+ args: {
79
+ appearance: 'code',
80
+ rows: 8,
81
+ defaultValue: 'SELECT *\nFROM users\nWHERE active = true;',
82
+ },
83
+ };
84
+
85
+ export const WithToolbar: Story = {
86
+ render: () => {
87
+ return (
88
+ <div className="flex flex-col gap-gds-1">
89
+ <Label htmlFor="share-url">Share link</Label>
90
+
91
+ <HintText id="share-url-hint">Copy this link to share your flood risk assessment.</HintText>
92
+
93
+ <InputGroup direction="vertical">
94
+ <InputToolbar>
95
+ <CopyButton appearance="ghost" size="sm" content={SHARE_URL} />
96
+ </InputToolbar>
97
+
98
+ <Textarea
99
+ id="share-url"
100
+ readOnly
101
+ rows={3}
102
+ value={SHARE_URL}
103
+ aria-describedby="share-url-hint"
104
+ />
105
+ </InputGroup>
106
+ </div>
107
+ );
108
+ },
109
+ };
110
+
111
+ export const WithToolbarAndCount: Story = {
112
+ render: () => (
113
+ <div className="flex flex-col gap-gds-1">
114
+ <Label htmlFor="notes-count">Notes</Label>
115
+
116
+ <HintText id="notes-count-hint">Do not enter more than 200 characters.</HintText>
117
+
118
+ <TextareaCount maxLength={200}>
119
+ <InputGroup direction="vertical">
120
+ <InputToolbar>
121
+ <CopyButton appearance="ghost" size="sm" content="Some content" />
122
+ </InputToolbar>
123
+
124
+ <Textarea id="notes-count" rows={5} aria-describedby="notes-count-hint" />
125
+ </InputGroup>
126
+
127
+ <TextareaCountMessage />
128
+ </TextareaCount>
129
+ </div>
130
+ ),
131
+ };
@@ -0,0 +1,50 @@
1
+ 'use client';
2
+
3
+ import { useContext, type ChangeEvent, type ComponentProps } from 'react';
4
+
5
+ import { cn } from '../../utils/components';
6
+ import { TextareaCountContext } from '../TextareaCount/TextareaCount';
7
+
8
+ const TEXTAREA_APPEARANCES = {
9
+ default: '',
10
+ code: 'cn-textarea-appearance-code',
11
+ } as const;
12
+
13
+ export type TextareaAppearance = keyof typeof TEXTAREA_APPEARANCES;
14
+
15
+ export type TextareaProps = ComponentProps<'textarea'> & {
16
+ appearance?: TextareaAppearance;
17
+ };
18
+
19
+ export const Textarea = ({
20
+ className,
21
+ appearance = 'default',
22
+ rows = 5,
23
+ onChange,
24
+ 'aria-describedby': ariaDescribedby,
25
+ 'aria-invalid': ariaInvalid,
26
+ ...props
27
+ }: TextareaProps) => {
28
+ const countContext = useContext(TextareaCountContext);
29
+ const isCountOver = countContext !== null && countContext.currentCount > countContext.maxCount;
30
+
31
+ const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
32
+ countContext?.reportValue(event.target.value);
33
+ onChange?.(event);
34
+ };
35
+
36
+ const describedBy =
37
+ [ariaDescribedby, countContext?.messageId].filter(Boolean).join(' ') || undefined;
38
+
39
+ return (
40
+ <textarea
41
+ rows={rows}
42
+ data-slot="textarea"
43
+ aria-describedby={describedBy}
44
+ aria-invalid={ariaInvalid ?? (isCountOver ? 'true' : undefined)}
45
+ className={cn('cn-textarea', TEXTAREA_APPEARANCES[appearance], className)}
46
+ onChange={handleChange}
47
+ {...props}
48
+ />
49
+ );
50
+ };
@@ -0,0 +1,17 @@
1
+ @layer components {
2
+ /* MARK: Count message
3
+ Mirrors hint text styling in the normal state.
4
+ Hidden (but still in DOM for live region) when below threshold.
5
+ Over-limit state uses error styling. */
6
+ .cn-textarea-count-message {
7
+ @apply text-sm text-body-secondary mt-gds-1;
8
+ }
9
+
10
+ .cn-textarea-count-message[data-hidden] {
11
+ visibility: hidden;
12
+ }
13
+
14
+ .cn-textarea-count-message[data-over] {
15
+ @apply text-error font-bold;
16
+ }
17
+ }
@@ -0,0 +1,131 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+
5
+ import type { Meta, StoryObj } from '@storybook/react-vite';
6
+
7
+ import { TextareaCount, TextareaCountMessage } from './TextareaCount';
8
+ import { FormGroup } from '../Form/FormGroup';
9
+ import { Label } from '../Label/Label';
10
+ import { Textarea } from '../Textarea/Textarea';
11
+
12
+ const meta: Meta<typeof TextareaCount> = {
13
+ title: 'Components/TextareaCount',
14
+ component: TextareaCount,
15
+ tags: ['autodocs'],
16
+ parameters: {
17
+ docs: {
18
+ description: {
19
+ component:
20
+ 'Wrapper that adds live character or word count feedback to a `Textarea`. Renders into context. Place `TextareaCountMessage` anywhere below the textarea to show the count hint.',
21
+ },
22
+ },
23
+ },
24
+ };
25
+
26
+ export default meta;
27
+
28
+ type Story = StoryObj<typeof TextareaCount>;
29
+
30
+ export const CharacterCount: Story = {
31
+ render: () => (
32
+ <div>
33
+ <Label htmlFor="char-count-textarea">Description</Label>
34
+
35
+ <TextareaCount maxLength={200}>
36
+ <Textarea id="char-count-textarea" />
37
+
38
+ <TextareaCountMessage />
39
+ </TextareaCount>
40
+ </div>
41
+ ),
42
+ };
43
+
44
+ export const WordCount: Story = {
45
+ render: () => (
46
+ <div>
47
+ <Label htmlFor="word-count-textarea">Summary</Label>
48
+
49
+ <TextareaCount maxWords={50}>
50
+ <Textarea id="word-count-textarea" />
51
+
52
+ <TextareaCountMessage />
53
+ </TextareaCount>
54
+ </div>
55
+ ),
56
+ };
57
+
58
+ export const WithThreshold: Story = {
59
+ parameters: {
60
+ docs: {
61
+ description: {
62
+ story:
63
+ 'The count message is hidden until the user reaches 75% of the limit, then appears. Type more than 150 characters to see it.',
64
+ },
65
+ },
66
+ },
67
+ render: () => (
68
+ <div>
69
+ <Label htmlFor="threshold-textarea">Description</Label>
70
+
71
+ <TextareaCount maxLength={200} threshold={0.75}>
72
+ <Textarea id="threshold-textarea" />
73
+
74
+ <TextareaCountMessage />
75
+ </TextareaCount>
76
+ </div>
77
+ ),
78
+ };
79
+
80
+ export const PreFilled: Story = {
81
+ parameters: {
82
+ docs: {
83
+ description: {
84
+ story:
85
+ 'Pass `initialValue` to `TextareaCount` to seed the count when the textarea has a pre-filled value.',
86
+ },
87
+ },
88
+ },
89
+ render: () => {
90
+ const value = 'This textarea already has some content in it.';
91
+
92
+ return (
93
+ <div>
94
+ <Label htmlFor="prefilled-textarea">Description</Label>
95
+
96
+ <TextareaCount maxLength={200} initialValue={value}>
97
+ <Textarea id="prefilled-textarea" defaultValue={value} />
98
+
99
+ <TextareaCountMessage />
100
+ </TextareaCount>
101
+ </div>
102
+ );
103
+ },
104
+ };
105
+
106
+ export const OverLimit: Story = {
107
+ parameters: {
108
+ docs: {
109
+ description: {
110
+ story:
111
+ 'The count message switches to error styling when the user exceeds the limit. `onValidityChange` fires whenever the over-limit boundary is crossed, letting a parent `FormGroup` react to the state.',
112
+ },
113
+ },
114
+ },
115
+ render: () => {
116
+ const value = 'a'.repeat(220);
117
+ const [isOver, setIsOver] = useState(false);
118
+
119
+ return (
120
+ <FormGroup invalid={isOver}>
121
+ <Label htmlFor="over-limit-textarea">Description</Label>
122
+
123
+ <TextareaCount maxLength={200} initialValue={value} onValidityChange={setIsOver}>
124
+ <Textarea id="over-limit-textarea" defaultValue={value} />
125
+
126
+ <TextareaCountMessage />
127
+ </TextareaCount>
128
+ </FormGroup>
129
+ );
130
+ },
131
+ };
@@ -0,0 +1,108 @@
1
+ 'use client';
2
+
3
+ import {
4
+ createContext,
5
+ useCallback,
6
+ useContext,
7
+ useEffect,
8
+ useId,
9
+ useMemo,
10
+ useState,
11
+ type ComponentProps,
12
+ type ReactNode,
13
+ } from 'react';
14
+
15
+ import { cn } from '../../utils/components';
16
+
17
+ type TextareaCountMode = 'characters' | 'words';
18
+
19
+ export type TextareaCountContextValue = {
20
+ mode: TextareaCountMode;
21
+ maxCount: number;
22
+ threshold: number;
23
+ currentCount: number;
24
+ messageId: string;
25
+ reportValue: (value: string) => void;
26
+ };
27
+
28
+ export const TextareaCountContext = createContext<TextareaCountContextValue | null>(null);
29
+
30
+ export type TextareaCountProps = {
31
+ children: ReactNode;
32
+ threshold?: number;
33
+ initialValue?: string;
34
+ onValidityChange?: (isOver: boolean) => void;
35
+ } & ({ maxLength: number; maxWords?: never } | { maxWords: number; maxLength?: never });
36
+
37
+ const countWords = (value: string) => (value.trim() === '' ? 0 : value.trim().split(/\s+/).length);
38
+
39
+ export const TextareaCount = ({
40
+ children,
41
+ maxLength,
42
+ maxWords,
43
+ threshold = 0,
44
+ initialValue = '',
45
+ onValidityChange,
46
+ }: TextareaCountProps) => {
47
+ const mode: TextareaCountMode = maxWords !== undefined ? 'words' : 'characters';
48
+ const maxCount = (mode === 'words' ? maxWords : maxLength) ?? 0;
49
+ const messageId = useId();
50
+
51
+ const [currentCount, setCurrentCount] = useState(() =>
52
+ mode === 'words' ? countWords(initialValue) : initialValue.length,
53
+ );
54
+
55
+ const isCountOver = currentCount > maxCount;
56
+
57
+ useEffect(() => {
58
+ onValidityChange?.(isCountOver);
59
+ }, [isCountOver, onValidityChange]);
60
+
61
+ const reportValue = useCallback(
62
+ (value: string) => {
63
+ setCurrentCount(mode === 'words' ? countWords(value) : value.length);
64
+ },
65
+ [mode],
66
+ );
67
+
68
+ const contextValue = useMemo(
69
+ () => ({ mode, maxCount, threshold, currentCount, messageId, reportValue }),
70
+ [mode, maxCount, threshold, currentCount, messageId, reportValue],
71
+ );
72
+
73
+ return (
74
+ <TextareaCountContext.Provider value={contextValue}>{children}</TextareaCountContext.Provider>
75
+ );
76
+ };
77
+
78
+ export type TextareaCountMessageProps = ComponentProps<'p'>;
79
+
80
+ export const TextareaCountMessage = ({ className, ...props }: TextareaCountMessageProps) => {
81
+ const context = useContext(TextareaCountContext);
82
+
83
+ if (!context) {
84
+ return null;
85
+ }
86
+
87
+ const { mode, maxCount, threshold, currentCount, messageId } = context;
88
+ const remaining = maxCount - currentCount;
89
+ const isOver = remaining < 0;
90
+ const isHidden = threshold > 0 && currentCount < maxCount * threshold;
91
+ const count = Math.abs(remaining);
92
+ const unit = mode === 'words' ? 'word' : 'character';
93
+ const label = count === 1 ? unit : `${unit}s`;
94
+
95
+ return (
96
+ <p
97
+ id={messageId}
98
+ aria-live="polite"
99
+ data-slot="textarea-count-message"
100
+ data-over={isOver ? true : undefined}
101
+ data-hidden={isHidden ? true : undefined}
102
+ className={cn('cn-textarea-count-message', className)}
103
+ {...props}
104
+ >
105
+ {isOver ? `You have ${count} ${label} too many` : `You have ${count} ${label} remaining`}
106
+ </p>
107
+ );
108
+ };