@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,40 @@
1
+ import type { ComponentProps } from 'react';
2
+
3
+ import { cn } from '../../utils/components';
4
+ import { Spinner } from '../Spinner/Spinner';
5
+
6
+ export type LoadingBoxProps = ComponentProps<'div'> & {
7
+ loading?: boolean;
8
+ title?: string;
9
+ };
10
+
11
+ export const LoadingBox = ({
12
+ loading = false,
13
+ title = 'Loading',
14
+ className,
15
+ children,
16
+ ...props
17
+ }: LoadingBoxProps) => (
18
+ <div data-slot="loading-box" className={cn('cn-loading-box', className)} {...props}>
19
+ <div
20
+ data-slot="loading-box-overlay"
21
+ data-loading={loading || undefined}
22
+ inert={!loading}
23
+ role="status"
24
+ className="cn-loading-box-overlay"
25
+ >
26
+ <Spinner aria-hidden className="cn-loading-box-spinner" />
27
+
28
+ <span className="sr-only">{title}</span>
29
+ </div>
30
+
31
+ {/* display:contents so this purely exists to carry `inert`, it doesn't
32
+ add a box that could change how children participate in whatever
33
+ layout the consumer's own content establishes. Blocks focus/clicks
34
+ on content that's about to be replaced once loading starts, rather
35
+ than just visually covering it while leaving it reachable. */}
36
+ <div data-slot="loading-box-content" inert={loading} className="contents">
37
+ {children}
38
+ </div>
39
+ </div>
40
+ );
@@ -0,0 +1,111 @@
1
+ @layer components {
2
+ /*
3
+ MARK: Modal overlay
4
+ Semi-transparent backdrop. Radix sets data-state to open or closed
5
+ which drives enter and exit fade transitions.
6
+ */
7
+ .cn-modal-overlay {
8
+ @apply bg-black/50 cn-z-overlay;
9
+
10
+ &[data-state='open'] {
11
+ animation: cn-modal-overlay-in 150ms ease-out;
12
+ }
13
+ &[data-state='closed'] {
14
+ animation: cn-modal-overlay-out 150ms ease-in;
15
+ }
16
+ }
17
+
18
+ @keyframes cn-modal-overlay-in {
19
+ from {
20
+ opacity: 0;
21
+ }
22
+ to {
23
+ opacity: 1;
24
+ }
25
+ }
26
+
27
+ @keyframes cn-modal-overlay-out {
28
+ from {
29
+ opacity: 1;
30
+ }
31
+ to {
32
+ opacity: 0;
33
+ }
34
+ }
35
+
36
+ /*
37
+ MARK: Modal content
38
+ The panel box with white background and GDS form-width border.
39
+ No rounded corners. The fixed position and centring transform are
40
+ applied via Tailwind in the TSX. Only visual appearance is set here.
41
+
42
+ Add a max-w-* class to ModalContent to widen for specific modals.
43
+ */
44
+ .cn-modal-content {
45
+ @apply panel cn-z-overlay p-gds-4 w-full max-w-sm;
46
+
47
+ &[data-state='open'] {
48
+ animation: cn-modal-content-in 150ms ease-out;
49
+ }
50
+ &[data-state='closed'] {
51
+ animation: cn-modal-content-out 150ms ease-in;
52
+ }
53
+ }
54
+
55
+ @keyframes cn-modal-content-in {
56
+ from {
57
+ opacity: 0;
58
+ }
59
+ to {
60
+ opacity: 1;
61
+ }
62
+ }
63
+
64
+ @keyframes cn-modal-content-out {
65
+ from {
66
+ opacity: 1;
67
+ }
68
+ to {
69
+ opacity: 0;
70
+ }
71
+ }
72
+
73
+ /*
74
+ MARK: Modal close button
75
+ Positioned absolutely in the top-right corner of the panel.
76
+ The parent cn-modal-content has position fixed which acts
77
+ as the containing block for absolute children.
78
+ */
79
+ .cn-modal-close {
80
+ @apply absolute top-gds-2 right-gds-2;
81
+ }
82
+
83
+ /* MARK: Modal header and footer */
84
+
85
+ .cn-modal-header {
86
+ @apply flex flex-col gap-gds-1;
87
+ }
88
+
89
+ .cn-modal-footer {
90
+ @apply flex flex-col gap-gds-2 sm:flex-row;
91
+ }
92
+
93
+ /* MARK: Vertical rhythm between sections
94
+ No layout opinion of its own on cn-modal-content, it needs to stay a
95
+ plain block so consumers can turn it into a flex row instead (e.g.
96
+ ErrorModal, an icon beside the content) without fighting a hardcoded
97
+ flex-direction. Wrap whatever sits inside (ModalHeader, ModalDescription,
98
+ ModalFooter, and anything else a specific modal needs, a form, a
99
+ Details section, ...) in a Stack instead, same as any other arbitrary
100
+ vertical content elsewhere in the library. */
101
+
102
+ /* MARK: Modal title and description */
103
+
104
+ .cn-modal-title {
105
+ @apply text-xl font-bold text-body;
106
+ }
107
+
108
+ .cn-modal-description {
109
+ @apply font-normal text-body;
110
+ }
111
+ }
@@ -1,188 +1,127 @@
1
1
  import { useState } from 'react';
2
2
 
3
- import { useArgs } from 'storybook/preview-api';
4
-
5
3
  import type { Meta, StoryObj } from '@storybook/react-vite';
6
4
 
7
- import { Modal } from './Modal';
5
+ import {
6
+ Modal,
7
+ ModalClose,
8
+ ModalContent,
9
+ ModalDescription,
10
+ ModalFooter,
11
+ ModalHeader,
12
+ ModalTitle,
13
+ ModalTrigger,
14
+ } from './Modal';
15
+ import { Button } from '../Button/Button';
16
+ import { FormGroup } from '../Form/FormGroup';
17
+ import { HintText } from '../HintText/HintText';
18
+ import { Input } from '../Input/Input';
19
+ import { Label } from '../Label/Label';
20
+ import { Stack } from '../Layout/Stack/Stack';
8
21
 
9
22
  const meta: Meta<typeof Modal> = {
10
23
  title: 'Components/Modal',
11
24
  component: Modal,
25
+ tags: ['autodocs'],
12
26
  parameters: {
13
- layout: 'fullscreen',
14
27
  docs: {
15
28
  description: {
16
- component: 'A modal dialog component that renders content in a portal overlay.',
29
+ component:
30
+ "Use the Modal primitives to display dialog content in an overlay. ModalContent has no layout opinion of its own (so consumers can turn it into something other than a column, e.g. ErrorModal's icon-beside-content row), wrap ModalHeader/ModalDescription/ModalFooter and anything else in a Stack for spacing between them, as below.",
17
31
  },
18
32
  },
19
33
  },
20
- // removed the auto-docs for now as that will cause all modals to open immediately
21
- // tags: ['autodocs'],
22
34
  argTypes: {
23
- isOpen: {
24
- control: 'boolean',
25
- description: 'Whether the modal is open',
26
- },
27
- onClose: {
28
- action: 'onClose',
29
- description: 'Callback function called when the modal should close',
30
- },
31
- children: {
32
- control: false,
33
- description: 'Content to display inside the modal',
34
- },
35
+ children: { control: false },
35
36
  },
36
- decorators: [
37
- (Story, context) => {
38
- const [{ isOpen }, updateArgs] = useArgs();
39
-
40
- const handleClose = () => {
41
- updateArgs({ isOpen: false });
42
- };
43
-
44
- // Override onClose prop to use local handler
45
- return <Story args={{ ...context.args, isOpen, onClose: handleClose }} />;
46
- },
47
- ],
48
37
  };
49
38
 
50
39
  export default meta;
40
+
51
41
  type Story = StoryObj<typeof Modal>;
52
42
 
53
43
  export const Default: Story = {
54
- args: {
55
- isOpen: true,
56
- children: (
57
- <div>
58
- <h2 className="mb-4 text-xl font-bold">Modal Title</h2>
59
-
60
- <p className="mb-4 text-gray-600">
61
- This is a basic modal with some content. You can close it by clicking the X button,
62
- pressing Escape, or clicking outside the modal.
63
- </p>
64
-
65
- <div className="flex gap-2">
66
- <button className="px-4 py-2 text-white bg-blue-500 rounded hover:bg-blue-600">
67
- Confirm
68
- </button>
69
-
70
- <button className="px-4 py-2 text-gray-700 bg-gray-300 rounded hover:bg-gray-400">
71
- Cancel
72
- </button>
73
- </div>
74
- </div>
75
- ),
76
- },
77
- };
78
-
79
- export const Closed: Story = {
80
- args: {
81
- isOpen: false,
82
- children: (
83
- <div>
84
- <h2 className="mb-4 text-xl font-bold">You won&apos;t see this</h2>
44
+ render: () => {
45
+ const [open, setOpen] = useState(false);
85
46
 
86
- <p>This modal is closed, so the content is not visible.</p>
87
- </div>
88
- ),
47
+ return (
48
+ <Modal open={open} onOpenChange={setOpen}>
49
+ <ModalTrigger asChild>
50
+ <Button>Open modal</Button>
51
+ </ModalTrigger>
52
+
53
+ <ModalContent>
54
+ <Stack gap="sm">
55
+ <ModalHeader>
56
+ <ModalTitle>Confirm action</ModalTitle>
57
+ </ModalHeader>
58
+
59
+ <ModalDescription>
60
+ Are you sure you want to continue? This action cannot be undone.
61
+ </ModalDescription>
62
+
63
+ <ModalFooter>
64
+ <Button appearance="secondary" onClick={() => setOpen(false)}>
65
+ Cancel
66
+ </Button>
67
+
68
+ <ModalClose asChild>
69
+ <Button>Confirm</Button>
70
+ </ModalClose>
71
+ </ModalFooter>
72
+ </Stack>
73
+ </ModalContent>
74
+ </Modal>
75
+ );
89
76
  },
90
77
  };
91
78
 
92
- export const SimpleMessage: Story = {
93
- args: {
94
- isOpen: true,
95
- children: (
96
- <div className="text-center">
97
- <h3 className="mb-2 text-lg font-semibold">Success!</h3>
98
-
99
- <p className="text-gray-600">Your action was completed successfully.</p>
100
- </div>
101
- ),
79
+ export const WithFormContent: Story = {
80
+ parameters: {
81
+ docs: {
82
+ description: {
83
+ story:
84
+ "Arbitrary content (a FormGroup here, could be anything) sits in the same Stack as ModalHeader/ModalDescription/ModalFooter, getting the same gap on both sides automatically, no extra spacing rules needed regardless of what's between them.",
85
+ },
86
+ },
102
87
  },
103
- };
104
-
105
- export const Interactive: Story = {
106
88
  render: () => {
107
- const [isOpen, setIsOpen] = useState(false);
108
- const [selectedModal, setSelectedModal] = useState<string | null>(null);
109
-
110
- const openModal = (type: string) => {
111
- setSelectedModal(type);
112
- setIsOpen(true);
113
- };
114
-
115
- const closeModal = () => {
116
- setIsOpen(false);
117
- setSelectedModal(null);
118
- };
119
-
120
- const renderModalContent = () => {
121
- switch (selectedModal) {
122
- case 'info':
123
- return (
124
- <div>
125
- <h3 className="mb-2 text-lg font-semibold">Information</h3>
126
-
127
- <p className="text-gray-600">This is an informational modal.</p>
128
- </div>
129
- );
130
- case 'warning':
131
- return (
132
- <div>
133
- <h3 className="mb-2 text-lg font-semibold text-yellow-600">Warning</h3>
134
-
135
- <p className="text-gray-600">This action requires confirmation.</p>
136
- </div>
137
- );
138
- case 'error':
139
- return (
140
- <div>
141
- <h3 className="mb-2 text-lg font-semibold text-red-600">Error</h3>
142
-
143
- <p className="text-gray-600">Something went wrong. Please try again.</p>
144
- </div>
145
- );
146
- default:
147
- return <p>Default modal content</p>;
148
- }
149
- };
89
+ const [open, setOpen] = useState(false);
150
90
 
151
91
  return (
152
- <div className="p-8">
153
- <h2 className="mb-4 text-xl font-bold">Interactive Modal Demo</h2>
154
-
155
- <p className="mb-6 text-gray-600">
156
- Click any button below to open different types of modals.
157
- </p>
158
-
159
- <div className="space-x-4">
160
- <button
161
- onClick={() => openModal('info')}
162
- className="px-4 py-2 text-white bg-blue-500 rounded hover:bg-blue-600"
163
- >
164
- Info Modal
165
- </button>
166
-
167
- <button
168
- onClick={() => openModal('warning')}
169
- className="px-4 py-2 text-white bg-yellow-500 rounded hover:bg-yellow-600"
170
- >
171
- Warning Modal
172
- </button>
173
-
174
- <button
175
- onClick={() => openModal('error')}
176
- className="px-4 py-2 text-white bg-red-500 rounded hover:bg-red-600"
177
- >
178
- Error Modal
179
- </button>
180
- </div>
181
-
182
- <Modal isOpen={isOpen} onClose={closeModal}>
183
- {renderModalContent()}
184
- </Modal>
185
- </div>
92
+ <Modal open={open} onOpenChange={setOpen}>
93
+ <ModalTrigger asChild>
94
+ <Button>Open modal</Button>
95
+ </ModalTrigger>
96
+
97
+ <ModalContent>
98
+ <Stack gap="sm">
99
+ <ModalHeader>
100
+ <ModalTitle>Rename item</ModalTitle>
101
+ </ModalHeader>
102
+
103
+ <ModalDescription>Choose a new name for this item.</ModalDescription>
104
+
105
+ <FormGroup>
106
+ <Label htmlFor="rename-item">Name</Label>
107
+
108
+ <HintText>As it should appear in the list</HintText>
109
+
110
+ <Input id="rename-item" aria-describedby="rename-item-hint" defaultValue="Untitled" />
111
+ </FormGroup>
112
+
113
+ <ModalFooter>
114
+ <Button appearance="secondary" onClick={() => setOpen(false)}>
115
+ Cancel
116
+ </Button>
117
+
118
+ <ModalClose asChild>
119
+ <Button>Save</Button>
120
+ </ModalClose>
121
+ </ModalFooter>
122
+ </Stack>
123
+ </ModalContent>
124
+ </Modal>
186
125
  );
187
126
  },
188
127
  };
@@ -1,83 +1,149 @@
1
1
  'use client';
2
2
 
3
- import { useCallback, useEffect, useRef } from 'react';
3
+ import type { ComponentProps } from 'react';
4
4
 
5
- import { createPortal } from 'react-dom';
6
- import { IoMdCloseCircle } from 'react-icons/io';
5
+ import { Dialog as DialogPrimitive } from 'radix-ui';
6
+ import { LuX } from 'react-icons/lu';
7
7
 
8
- import type { ExtendProps } from '../../types';
9
- import { cn } from '../../utils';
8
+ import { cn } from '../../utils/components';
9
+ import { Button } from '../Button/Button';
10
10
 
11
- type Props = {
12
- isOpen: boolean;
13
- onClose: () => void;
14
- children: React.ReactNode;
11
+ export type ModalProps = ComponentProps<typeof DialogPrimitive.Root>;
12
+
13
+ export const Modal = ({ ...props }: ModalProps) => (
14
+ <DialogPrimitive.Root data-slot="modal" {...props} />
15
+ );
16
+
17
+ export type ModalTriggerProps = ComponentProps<typeof DialogPrimitive.Trigger>;
18
+
19
+ export const ModalTrigger = ({ ...props }: ModalTriggerProps) => (
20
+ <DialogPrimitive.Trigger data-slot="modal-trigger" {...props} />
21
+ );
22
+
23
+ export type ModalPortalProps = ComponentProps<typeof DialogPrimitive.Portal>;
24
+
25
+ export const ModalPortal = ({ ...props }: ModalPortalProps) => (
26
+ <DialogPrimitive.Portal data-slot="modal-portal" {...props} />
27
+ );
28
+
29
+ export type ModalCloseProps = ComponentProps<typeof DialogPrimitive.Close>;
30
+
31
+ export const ModalClose = ({ ...props }: ModalCloseProps) => (
32
+ <DialogPrimitive.Close data-slot="modal-close" {...props} />
33
+ );
34
+
35
+ export type ModalOverlayProps = ComponentProps<typeof DialogPrimitive.Overlay>;
36
+
37
+ export const ModalOverlay = ({ className, ...props }: ModalOverlayProps) => (
38
+ <DialogPrimitive.Overlay
39
+ data-slot="modal-overlay"
40
+ className={cn('cn-modal-overlay fixed inset-0 isolate', className)}
41
+ {...props}
42
+ />
43
+ );
44
+
45
+ export type ModalContentProps = ComponentProps<typeof DialogPrimitive.Content> & {
46
+ showCloseButton?: boolean;
15
47
  };
16
48
 
17
- export type ModalProps = ExtendProps<'dialog', Props>;
18
-
19
- export const Modal = ({ isOpen, onClose, children, className, ...props }: ModalProps) => {
20
- const modalRef = useRef<HTMLDialogElement>(null);
21
-
22
- const handleClose = useCallback(() => {
23
- modalRef.current?.close();
24
- onClose();
25
- }, [onClose]);
26
-
27
- useEffect(() => {
28
- if (!isOpen) {
29
- return;
30
- }
31
-
32
- modalRef.current?.showModal();
33
- }, [isOpen]);
34
-
35
- // typically dialogs don't need to be rendered conditionally, as the browser sets `display: none` when it's closed, but
36
- // as we override the display style and make it `flex`, we need the condition to hide it
37
- return isOpen
38
- ? // although dialogs are in their own special top-layer, this is only for styling, and DOM-wise they receive events like any other element,
39
- // so we want to portal it to be the highest element in the DOM
40
- createPortal(
41
- // dialog elements do have a key handler as you can close them with `Escape`, so this can be ignored
42
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
43
- <dialog
44
- className={cn(
45
- `fixed inset-0 flex items-center justify-center w-full h-full m-0 bg-transparent
46
- backdrop:bg-black/50`,
47
- className,
48
- )}
49
- ref={modalRef}
50
- onCancel={(event) => {
51
- event.preventDefault();
52
- event.stopPropagation();
53
-
54
- handleClose();
55
- }}
56
- onClick={() => {
57
- // close the modal if the user clicks outside the main content (i.e. on the backdrop)
58
- handleClose();
59
- }}
60
- {...props}
61
- >
62
- {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
63
- <div
64
- className="relative z-10 w-full max-w-md p-6 bg-white rounded-lg shadow-lg"
65
- onClick={(event) => {
66
- // stop event from bubbling to the `dialog` element, as we don't want the modal to close if you click the content
67
- event.stopPropagation();
68
- }}
69
- >
70
- <button
71
- onClick={handleClose}
72
- className="absolute text-gray-600 text-static-xl top-2 right-2 hover:text-black"
73
- aria-label="Close modal"
74
- >
75
- <IoMdCloseCircle size={20} />
76
- </button>
77
- {children}
78
- </div>
79
- </dialog>,
80
- document.body,
81
- )
82
- : null;
49
+ export const ModalContent = ({
50
+ className,
51
+ children,
52
+ showCloseButton = true,
53
+ ...props
54
+ }: ModalContentProps) => (
55
+ <ModalPortal>
56
+ <ModalOverlay />
57
+
58
+ <DialogPrimitive.Content
59
+ data-slot="modal-content"
60
+ className={cn(
61
+ `cn-modal-content fixed top-1/2 left-1/2 w-full -translate-x-1/2 -translate-y-1/2
62
+ outline-none`,
63
+ className,
64
+ )}
65
+ {...props}
66
+ >
67
+ {children}
68
+
69
+ {showCloseButton && (
70
+ <div className="cn-modal-close">
71
+ <DialogPrimitive.Close data-slot="modal-close" asChild>
72
+ <Button variant="icon" appearance="ghost">
73
+ <LuX />
74
+
75
+ <span className="sr-only">Close</span>
76
+ </Button>
77
+ </DialogPrimitive.Close>
78
+ </div>
79
+ )}
80
+ </DialogPrimitive.Content>
81
+ </ModalPortal>
82
+ );
83
+
84
+ export type ModalHeaderProps = ComponentProps<'div'>;
85
+
86
+ export const ModalHeader = ({ className, ...props }: ModalHeaderProps) => (
87
+ <div
88
+ data-slot="modal-header"
89
+ className={cn('cn-modal-header flex flex-col', className)}
90
+ {...props}
91
+ />
92
+ );
93
+
94
+ export type ModalFooterProps = ComponentProps<'div'> & {
95
+ showCloseButton?: boolean;
83
96
  };
97
+
98
+ export const ModalFooter = ({
99
+ className,
100
+ showCloseButton = false,
101
+ children,
102
+ ...props
103
+ }: ModalFooterProps) => (
104
+ <div
105
+ data-slot="modal-footer"
106
+ className={cn(
107
+ 'cn-modal-footer flex flex-col-reverse gap-2 sm:flex-row sm:justify-end',
108
+ className,
109
+ )}
110
+ {...props}
111
+ >
112
+ {children}
113
+
114
+ {showCloseButton && (
115
+ <DialogPrimitive.Close asChild>
116
+ <Button appearance="secondary">Close</Button>
117
+ </DialogPrimitive.Close>
118
+ )}
119
+ </div>
120
+ );
121
+
122
+ export type ModalTitleProps = ComponentProps<typeof DialogPrimitive.Title>;
123
+
124
+ export const ModalTitle = ({ className, ...props }: ModalTitleProps) => (
125
+ <DialogPrimitive.Title
126
+ data-slot="modal-title"
127
+ className={cn('cn-modal-title cn-font-heading', className)}
128
+ {...props}
129
+ />
130
+ );
131
+
132
+ export type ModalDescriptionProps = ComponentProps<typeof DialogPrimitive.Description>;
133
+
134
+ // Renders a <p> (Description's own default), which can only contain
135
+ // phrasing content, children here is assumed to be plain descriptive text
136
+ // for that reason. Anything else (a Details/SummaryList section, a copy
137
+ // button, ...) belongs as a sibling of ModalDescription instead, not
138
+ // nested inside it, both because a <p> can't legally contain block
139
+ // content (a browser silently closes it early on hitting one, which
140
+ // desyncs SSR/client markup into a hydration error) and because
141
+ // aria-describedby content should read as plain description text, not
142
+ // fold in interactive elements. See ErrorModal for the sibling pattern.
143
+ export const ModalDescription = ({ className, ...props }: ModalDescriptionProps) => (
144
+ <DialogPrimitive.Description
145
+ data-slot="modal-description"
146
+ className={cn('cn-modal-description', className)}
147
+ {...props}
148
+ />
149
+ );
@@ -0,0 +1,17 @@
1
+ @layer components {
2
+ /* MARK: NoScript banner
3
+ Full-width accent-coloured bar. Intended as the very first element in
4
+ the DOM, above the header, same position as the cookie banner, so it's
5
+ unmissable and consistent across every app. role="region" + aria-label
6
+ keeps it discoverable via landmark navigation even though it sits
7
+ outside both the header and main landmarks. */
8
+ .cn-noscript-banner {
9
+ @apply bg-accent text-on-accent py-gds-4;
10
+ }
11
+
12
+ /* MARK: Inner wrapper
13
+ Centres and constrains content, matching cn-cookie-banner-inner. */
14
+ .cn-noscript-banner-inner {
15
+ @apply mx-auto max-w-page px-gds-4;
16
+ }
17
+ }