@tpzdsp/next-toolkit 2.5.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) 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 +32 -0
  62. package/src/components/ErrorModal/ErrorModal.stories.tsx +101 -0
  63. package/src/components/ErrorModal/ErrorModal.tsx +120 -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 +4 -2
  77. package/src/components/Footer/Footer.stories.tsx +24 -0
  78. package/src/components/Footer/Footer.tsx +41 -0
  79. package/src/components/Footer/Licence.tsx +18 -0
  80. package/src/components/{layout/footer → Footer}/MetaLinks.tsx +8 -3
  81. package/src/components/Footer/Small/SmallFooter.tsx +43 -42
  82. package/src/components/Form/FormGroup.css +18 -0
  83. package/src/components/Form/FormGroup.stories.tsx +87 -0
  84. package/src/components/Form/FormGroup.tsx +16 -0
  85. package/src/components/{layout/header → Header}/Header.stories.tsx +26 -12
  86. package/src/components/Header/Header.test.tsx +87 -0
  87. package/src/components/Header/Header.tsx +303 -0
  88. package/src/components/Header/HeaderAppContent.tsx +120 -0
  89. package/src/components/Heading/Heading.css +40 -0
  90. package/src/components/Heading/Heading.stories.tsx +15 -5
  91. package/src/components/Heading/Heading.tsx +21 -44
  92. package/src/components/Heading/HeadingSkeleton.stories.tsx +30 -0
  93. package/src/components/Heading/HeadingSkeleton.tsx +14 -0
  94. package/src/components/Hero/Hero.css +19 -0
  95. package/src/components/Hero/Hero.stories.tsx +41 -0
  96. package/src/components/Hero/Hero.tsx +14 -0
  97. package/src/components/HintText/HintText.css +5 -0
  98. package/src/components/HintText/HintText.stories.tsx +29 -0
  99. package/src/components/HintText/HintText.tsx +13 -0
  100. package/src/components/InfoBox/InfoBox.css +38 -0
  101. package/src/components/InfoBox/InfoBox.stories.tsx +51 -403
  102. package/src/components/InfoBox/InfoBox.tsx +31 -158
  103. package/src/components/Input/Input.css +77 -0
  104. package/src/components/Input/Input.stories.tsx +123 -0
  105. package/src/components/Input/Input.tsx +74 -0
  106. package/src/components/InputGroup/InputGroup.css +140 -0
  107. package/src/components/InputGroup/InputGroup.stories.tsx +125 -0
  108. package/src/components/InputGroup/InputGroup.tsx +47 -0
  109. package/src/components/InsetText/InsetText.css +5 -0
  110. package/src/components/InsetText/InsetText.stories.tsx +30 -0
  111. package/src/components/InsetText/InsetText.tsx +9 -0
  112. package/src/components/Keyboard/Keyboard.css +9 -0
  113. package/src/components/Keyboard/Keyboard.stories.tsx +63 -0
  114. package/src/components/Keyboard/Keyboard.tsx +30 -0
  115. package/src/components/Label/Label.css +27 -0
  116. package/src/components/Label/Label.stories.tsx +40 -0
  117. package/src/components/Label/Label.tsx +17 -0
  118. package/src/components/LayerSwitcher/LayerSwitcher.css +59 -0
  119. package/src/components/LayerSwitcher/LayerSwitcher.stories.tsx +112 -0
  120. package/src/components/LayerSwitcher/LayerSwitcher.tsx +61 -0
  121. package/src/components/Layout/401/401.stories.tsx +23 -0
  122. package/src/components/Layout/401/401.tsx +1 -0
  123. package/src/components/Layout/403/403.stories.tsx +23 -0
  124. package/src/components/Layout/403/403.tsx +21 -0
  125. package/src/components/Layout/404/404.stories.tsx +23 -0
  126. package/src/components/Layout/404/404.tsx +28 -0
  127. package/src/components/Layout/500/500.stories.tsx +56 -0
  128. package/src/components/Layout/500/500.tsx +63 -0
  129. package/src/components/Layout/ButtonGroup/ButtonGroup.css +52 -0
  130. package/src/components/Layout/ButtonGroup/ButtonGroup.stories.tsx +156 -0
  131. package/src/components/Layout/ButtonGroup/ButtonGroup.tsx +50 -0
  132. package/src/components/Layout/HeadingGroup/HeadingGroup.css +21 -0
  133. package/src/components/Layout/HeadingGroup/HeadingGroup.stories.tsx +84 -0
  134. package/src/components/Layout/HeadingGroup/HeadingGroup.tsx +9 -0
  135. package/src/components/Layout/MainWrapper/MainWrapper.css +12 -0
  136. package/src/components/Layout/MainWrapper/MainWrapper.stories.tsx +36 -0
  137. package/src/components/Layout/MainWrapper/MainWrapper.tsx +14 -0
  138. package/src/components/Layout/PageShell/PageShell.css +42 -0
  139. package/src/components/Layout/PageShell/PageShell.stories.tsx +108 -0
  140. package/src/components/Layout/PageShell/PageShell.tsx +31 -0
  141. package/src/components/Layout/ParagraphGroup/ParagraphGroup.css +5 -0
  142. package/src/components/Layout/ParagraphGroup/ParagraphGroup.stories.tsx +34 -0
  143. package/src/components/Layout/ParagraphGroup/ParagraphGroup.tsx +9 -0
  144. package/src/components/Layout/Stack/Stack.css +29 -0
  145. package/src/components/Layout/Stack/Stack.stories.tsx +83 -0
  146. package/src/components/Layout/Stack/Stack.tsx +19 -0
  147. package/src/components/Layout/WidthContainer/WidthContainer.css +17 -0
  148. package/src/components/Layout/WidthContainer/WidthContainer.stories.tsx +59 -0
  149. package/src/components/Layout/WidthContainer/WidthContainer.tsx +13 -0
  150. package/src/components/Legend/Legend.css +95 -0
  151. package/src/components/Legend/Legend.stories.tsx +81 -0
  152. package/src/components/Legend/Legend.tsx +32 -0
  153. package/src/components/Legend/LegendDot.tsx +15 -0
  154. package/src/components/Legend/LegendPanel.stories.tsx +101 -0
  155. package/src/components/Legend/LegendPanel.tsx +68 -0
  156. package/src/components/Legend/LegendSkeleton.stories.tsx +87 -0
  157. package/src/components/Legend/LegendSkeleton.tsx +73 -0
  158. package/src/components/LegendSelect/LegendSelect.css +8 -0
  159. package/src/components/LegendSelect/LegendSelect.stories.tsx +80 -0
  160. package/src/components/LegendSelect/LegendSelect.tsx +26 -0
  161. package/src/components/Link/Link.css +98 -0
  162. package/src/components/Link/Link.stories.tsx +70 -0
  163. package/src/components/Link/Link.tsx +52 -0
  164. package/src/components/LinkButton/LinkButton.css +67 -0
  165. package/src/components/LinkButton/LinkButton.stories.tsx +90 -42
  166. package/src/components/LinkButton/LinkButton.tsx +50 -63
  167. package/src/components/LinkList/LinkList.css +28 -0
  168. package/src/components/LinkList/LinkList.stories.tsx +46 -0
  169. package/src/components/LinkList/LinkList.tsx +23 -0
  170. package/src/components/List/Li.tsx +9 -0
  171. package/src/components/List/List.css +9 -0
  172. package/src/components/List/OrderedList.stories.tsx +36 -0
  173. package/src/components/List/OrderedList.tsx +9 -0
  174. package/src/components/List/UnorderedList.stories.tsx +36 -0
  175. package/src/components/List/UnorderedList.tsx +9 -0
  176. package/src/components/LoadingBox/LoadingBox.css +27 -0
  177. package/src/components/LoadingBox/LoadingBox.stories.tsx +66 -0
  178. package/src/components/LoadingBox/LoadingBox.tsx +40 -0
  179. package/src/components/Modal/Modal.css +114 -0
  180. package/src/components/Modal/Modal.stories.tsx +41 -160
  181. package/src/components/Modal/Modal.tsx +132 -75
  182. package/src/components/NoScriptBanner/NoScriptBanner.css +17 -0
  183. package/src/components/NoScriptBanner/NoScriptBanner.stories.tsx +46 -0
  184. package/src/components/NoScriptBanner/NoScriptBanner.tsx +26 -0
  185. package/src/components/Paragraph/Paragraph.css +22 -0
  186. package/src/components/Paragraph/Paragraph.stories.tsx +1 -42
  187. package/src/components/Paragraph/Paragraph.tsx +4 -3
  188. package/src/components/Paragraph/ParagraphSkeleton.stories.tsx +44 -0
  189. package/src/components/Paragraph/ParagraphSkeleton.tsx +33 -0
  190. package/src/components/PasswordInput/PasswordInput.css +3 -0
  191. package/src/components/PasswordInput/PasswordInput.stories.tsx +47 -0
  192. package/src/components/PasswordInput/PasswordInput.tsx +45 -0
  193. package/src/components/PhaseBanner/PhaseBanner.css +12 -0
  194. package/src/components/PhaseBanner/PhaseBanner.stories.tsx +61 -0
  195. package/src/components/PhaseBanner/PhaseBanner.tsx +17 -0
  196. package/src/components/Popover/Popover.css +43 -0
  197. package/src/components/Popover/Popover.stories.tsx +102 -0
  198. package/src/components/Popover/Popover.tsx +40 -0
  199. package/src/components/Radio/Radio.css +69 -0
  200. package/src/components/Radio/Radio.stories.tsx +169 -0
  201. package/src/components/Radio/Radio.tsx +56 -0
  202. package/src/components/Resizable/Resizable.css +86 -0
  203. package/src/components/Resizable/Resizable.stories.tsx +123 -0
  204. package/src/components/Resizable/Resizable.tsx +86 -0
  205. package/src/components/ScrollArea/ScrollArea.css +9 -0
  206. package/src/components/ScrollArea/ScrollArea.stories.tsx +42 -0
  207. package/src/components/ScrollArea/ScrollArea.tsx +11 -0
  208. package/src/components/SearchBox/SearchBox.stories.tsx +88 -0
  209. package/src/components/SearchBox/SearchBox.tsx +36 -0
  210. package/src/components/Select/AsyncSelect.stories.tsx +84 -0
  211. package/src/components/Select/AsyncSelect.tsx +41 -0
  212. package/src/components/Select/Select.css +194 -0
  213. package/src/components/Select/Select.stories.tsx +162 -0
  214. package/src/components/Select/Select.test.tsx +36 -0
  215. package/src/components/Select/Select.tsx +291 -0
  216. package/src/components/Select/SelectSkeleton.stories.tsx +51 -0
  217. package/src/components/Select/SelectSkeleton.tsx +23 -0
  218. package/src/components/Separator/Separator.css +41 -0
  219. package/src/components/Separator/Separator.stories.tsx +63 -0
  220. package/src/components/Separator/Separator.tsx +42 -0
  221. package/src/components/Sidebar/ResizableSidebar.tsx +118 -0
  222. package/src/components/Sidebar/Sidebar.css +203 -0
  223. package/src/components/Sidebar/Sidebar.stories.tsx +438 -0
  224. package/src/components/Sidebar/Sidebar.tsx +225 -0
  225. package/src/components/Skeleton/Skeleton.css +16 -0
  226. package/src/components/Skeleton/Skeleton.stories.tsx +39 -0
  227. package/src/components/Skeleton/Skeleton.tsx +12 -0
  228. package/src/components/SkipLink/SkipLink.css +16 -0
  229. package/src/components/SkipLink/SkipLink.stories.tsx +40 -0
  230. package/src/components/SkipLink/SkipLink.tsx +15 -0
  231. package/src/components/Spinner/Spinner.css +30 -0
  232. package/src/components/Spinner/Spinner.stories.tsx +36 -0
  233. package/src/components/Spinner/Spinner.tsx +45 -0
  234. package/src/components/StartButton/StartButton.css +13 -0
  235. package/src/components/StartButton/StartButton.stories.tsx +68 -0
  236. package/src/components/StartButton/StartButton.tsx +50 -0
  237. package/src/components/SubmitButton/SubmitButton.stories.tsx +31 -0
  238. package/src/components/SubmitButton/SubmitButton.tsx +14 -0
  239. package/src/components/SummaryList/SummaryList.css +71 -0
  240. package/src/components/SummaryList/SummaryList.stories.tsx +211 -0
  241. package/src/components/SummaryList/SummaryList.tsx +41 -0
  242. package/src/components/SummaryList/SummaryListSkeleton.stories.tsx +67 -0
  243. package/src/components/SummaryList/SummaryListSkeleton.tsx +40 -0
  244. package/src/components/Tabs/Tabs.css +84 -0
  245. package/src/components/Tabs/Tabs.stories.tsx +133 -0
  246. package/src/components/Tabs/Tabs.tsx +66 -0
  247. package/src/components/Tag/Tag.css +8 -0
  248. package/src/components/Tag/Tag.stories.tsx +96 -0
  249. package/src/components/Tag/Tag.tsx +34 -0
  250. package/src/components/Textarea/Textarea.css +38 -0
  251. package/src/components/Textarea/Textarea.stories.tsx +131 -0
  252. package/src/components/Textarea/Textarea.tsx +50 -0
  253. package/src/components/TextareaCount/TextareaCount.css +17 -0
  254. package/src/components/TextareaCount/TextareaCount.stories.tsx +131 -0
  255. package/src/components/TextareaCount/TextareaCount.tsx +108 -0
  256. package/src/components/Tooltip/Tooltip.css +43 -0
  257. package/src/components/Tooltip/Tooltip.stories.tsx +110 -0
  258. package/src/components/Tooltip/Tooltip.tsx +53 -0
  259. package/src/components/WarningText/WarningText.css +20 -0
  260. package/src/components/WarningText/WarningText.stories.tsx +29 -0
  261. package/src/components/WarningText/WarningText.tsx +17 -0
  262. package/src/components/index.ts +342 -61
  263. package/src/errors/errorDisplay.ts +70 -0
  264. package/src/errors/index.ts +1 -0
  265. package/src/http/constants.ts +1 -0
  266. package/src/http/fetch.ts +7 -3
  267. package/src/map/LayerSwitcherPanel.tsx +2 -173
  268. package/src/map/LegendShim.tsx +2 -0
  269. package/src/map/MapComponent.tsx +7 -17
  270. package/src/map/MapControlsOverlay.tsx +68 -175
  271. package/src/map/Popup.tsx +71 -24
  272. package/src/map/geocoder/Geocoder.test.tsx +46 -3
  273. package/src/map/geocoder/Geocoder.tsx +155 -278
  274. package/src/map/index.ts +1 -1
  275. package/src/types/utils.ts +0 -10
  276. package/src/utils/components.ts +96 -0
  277. package/src/utils/index.ts +1 -0
  278. package/src/utils/utils.ts +0 -12
  279. package/src/assets/images/defra-logo.svg +0 -51
  280. package/src/assets/images/ea-logo.svg +0 -58
  281. package/src/assets/images/ogl.svg +0 -1
  282. package/src/components/Button/Button.test.tsx +0 -53
  283. package/src/components/ButtonLink/ButtonLink.test.tsx +0 -154
  284. package/src/components/Card/Card.test.tsx +0 -51
  285. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +0 -75
  286. package/src/components/ErrorBoundary/ErrorFallback.test.tsx +0 -107
  287. package/src/components/ErrorText/ErrorText.test.tsx +0 -33
  288. package/src/components/Heading/Heading.test.tsx +0 -22
  289. package/src/components/Hint/Hint.stories.tsx +0 -58
  290. package/src/components/Hint/Hint.test.tsx +0 -33
  291. package/src/components/Hint/Hint.tsx +0 -12
  292. package/src/components/InfoBox/InfoBox.test.tsx +0 -330
  293. package/src/components/InfoBox/types.ts +0 -6
  294. package/src/components/LinkButton/LinkButton.test.tsx +0 -177
  295. package/src/components/Modal/Modal.test.tsx +0 -246
  296. package/src/components/NotificationBanner/NotificationBanner.stories.tsx +0 -45
  297. package/src/components/NotificationBanner/NotificationBanner.test.tsx +0 -58
  298. package/src/components/NotificationBanner/NotificationBanner.tsx +0 -45
  299. package/src/components/Paragraph/Paragraph.test.tsx +0 -10
  300. package/src/components/SlidingPanel/SlidingPanel.stories.tsx +0 -129
  301. package/src/components/SlidingPanel/SlidingPanel.test.tsx +0 -83
  302. package/src/components/SlidingPanel/SlidingPanel.tsx +0 -258
  303. package/src/components/accordion/Accordion.stories.tsx +0 -234
  304. package/src/components/accordion/Accordion.test.tsx +0 -192
  305. package/src/components/accordion/Accordion.tsx +0 -73
  306. package/src/components/backToTop/BackToTop.stories.tsx +0 -407
  307. package/src/components/backToTop/BackToTop.test.tsx +0 -57
  308. package/src/components/backToTop/BackToTop.tsx +0 -134
  309. package/src/components/chip/Chip.stories.tsx +0 -61
  310. package/src/components/chip/Chip.test.tsx +0 -31
  311. package/src/components/chip/Chip.tsx +0 -23
  312. package/src/components/container/Container.tsx +0 -42
  313. package/src/components/cookieBanner/CookieBanner.stories.tsx +0 -257
  314. package/src/components/cookieBanner/CookieBanner.test.tsx +0 -68
  315. package/src/components/cookieBanner/CookieBanner.tsx +0 -73
  316. package/src/components/divider/RuleDivider.stories.tsx +0 -254
  317. package/src/components/divider/RuleDivider.test.tsx +0 -164
  318. package/src/components/divider/RuleDivider.tsx +0 -23
  319. package/src/components/dropdown/DropdownMenu.test.tsx +0 -211
  320. package/src/components/dropdown/DropdownMenu.tsx +0 -108
  321. package/src/components/dropdown/useDropdownMenu.ts +0 -249
  322. package/src/components/form/Input.stories.tsx +0 -435
  323. package/src/components/form/Input.test.tsx +0 -206
  324. package/src/components/form/Input.tsx +0 -23
  325. package/src/components/form/TextArea.stories.tsx +0 -464
  326. package/src/components/form/TextArea.test.tsx +0 -232
  327. package/src/components/form/TextArea.tsx +0 -23
  328. package/src/components/layout/footer/Footer.tsx +0 -26
  329. package/src/components/layout/footer/Licence.tsx +0 -19
  330. package/src/components/layout/header/Header.test.tsx +0 -36
  331. package/src/components/layout/header/Header.tsx +0 -90
  332. package/src/components/layout/header/HeaderAuthClient.test.tsx +0 -45
  333. package/src/components/layout/header/HeaderAuthClient.tsx +0 -40
  334. package/src/components/layout/header/HeaderNavClient.test.tsx +0 -44
  335. package/src/components/layout/header/HeaderNavClient.tsx +0 -67
  336. package/src/components/link/ExternalLink.test.tsx +0 -102
  337. package/src/components/link/ExternalLink.tsx +0 -29
  338. package/src/components/link/Link.tsx +0 -26
  339. package/src/components/select/Select.stories.tsx +0 -336
  340. package/src/components/select/Select.test.tsx +0 -474
  341. package/src/components/select/Select.tsx +0 -125
  342. package/src/components/select/SelectSkeleton.stories.tsx +0 -194
  343. package/src/components/select/SelectSkeleton.test.tsx +0 -104
  344. package/src/components/select/SelectSkeleton.tsx +0 -23
  345. package/src/components/select/common.ts +0 -3
  346. package/src/components/select/index.ts +0 -18
  347. package/src/components/skipLink/SkipLink.stories.tsx +0 -346
  348. package/src/components/skipLink/SkipLink.test.tsx +0 -22
  349. package/src/components/skipLink/SkipLink.tsx +0 -49
  350. package/src/map/LegendPanel.tsx +0 -85
  351. /package/src/{components → assets}/images/DefraLogo.tsx +0 -0
  352. /package/src/{components → assets}/images/EaLogo.tsx +0 -0
  353. /package/src/{components → assets}/images/OglLogo.tsx +0 -0
  354. /package/src/components/{googleAnalytics → GoogleAnalytics}/GlobalVars.tsx +0 -0
  355. /package/src/components/{googleAnalytics → GoogleAnalytics}/GoogleAnalytics.tsx +0 -0
@@ -0,0 +1,15 @@
1
+ import { cn } from '../../utils/components';
2
+
3
+ export type LegendDotProps = {
4
+ color: string;
5
+ className?: string;
6
+ };
7
+
8
+ export const LegendDot = ({ color, className }: LegendDotProps) => (
9
+ <span
10
+ data-slot="legend-dot"
11
+ className={cn('cn-legend-dot', className)}
12
+ style={{ backgroundColor: color }}
13
+ aria-hidden
14
+ />
15
+ );
@@ -0,0 +1,101 @@
1
+ import { useState } from 'react';
2
+
3
+ import type { Meta, StoryObj } from '@storybook/react-vite';
4
+
5
+ import { LegendPanel } from './LegendPanel';
6
+ import type { LegendOption } from './LegendPanel';
7
+
8
+ const HABITAT_ITEMS: LegendOption[] = [
9
+ { value: 'bogs', label: 'Bogs', color: '#3b82f6' },
10
+ { value: 'dwarf-shrub', label: 'Dwarf shrub heath', color: '#14b8a6' },
11
+ { value: 'fens', label: 'Fens, marsh & swamp', color: '#ec4899' },
12
+ { value: 'littoral', label: 'Littoral sediments', color: '#f97316' },
13
+ { value: 'neutral', label: 'Neutral grassland', color: '#a855f7' },
14
+ ];
15
+
16
+ const meta: Meta<typeof LegendPanel> = {
17
+ title: 'Components/LegendPanel',
18
+ component: LegendPanel,
19
+ tags: ['autodocs'],
20
+ parameters: {
21
+ docs: {
22
+ description: {
23
+ component: `
24
+ Renders a list of \`LegendOption\` items (colour dot + label). This is the shared list rendering used inside \`Legend\`'s popover, and can also be used standalone.
25
+
26
+ Pass \`value\` and \`onSelectItem\` together to switch into single-select interactive mode (radio-group behaviour, one item selected at a time). Omit both for a static, display-only list.
27
+
28
+ \`LegendPanel\` itself has no border or background, that comes from whatever it's nested in (\`Legend\`'s \`PopoverContent\` already supplies it). For standalone use outside a popover, wrap it in a panel-styled container (the \`panel\` utility class, or your own bordered wrapper). \`Card\` is a different pattern now (a top-divider content tile), not a general-purpose bordered box.
29
+
30
+ **Props:**
31
+ - \`items\`: array of \`LegendOption\` objects (\`value\`, \`label\`, \`color\`)
32
+ - \`title\`: optional heading shown above the list
33
+ - \`value\` / \`onSelectItem\`: provide both to make the list selectable
34
+ `.trim(),
35
+ },
36
+ },
37
+ },
38
+ };
39
+
40
+ export default meta;
41
+
42
+ type Story = StoryObj<typeof LegendPanel>;
43
+
44
+ const InteractiveStory = () => {
45
+ const [active, setActive] = useState<string | null>('bogs');
46
+
47
+ return (
48
+ <div className="panel p-gds-3 w-52">
49
+ <LegendPanel
50
+ items={HABITAT_ITEMS}
51
+ title="Habitat types"
52
+ value={active}
53
+ onSelectItem={setActive}
54
+ />
55
+ </div>
56
+ );
57
+ };
58
+
59
+ const NoSelectionStory = () => {
60
+ const [active, setActive] = useState<string | null>(null);
61
+
62
+ return (
63
+ <div className="panel p-gds-3 w-52">
64
+ <LegendPanel
65
+ items={HABITAT_ITEMS}
66
+ title="Habitat types"
67
+ value={active}
68
+ onSelectItem={setActive}
69
+ />
70
+ </div>
71
+ );
72
+ };
73
+
74
+ export const Default: Story = {
75
+ render: () => (
76
+ <div className="panel p-gds-3 w-52">
77
+ <LegendPanel items={HABITAT_ITEMS} title="Habitat types" />
78
+ </div>
79
+ ),
80
+ };
81
+
82
+ export const Interactive: Story = {
83
+ parameters: {
84
+ docs: {
85
+ description: {
86
+ story:
87
+ 'Pass `value` and `onSelectItem` to make the list selectable, one item at a time. The same pattern as `LayerSwitcher`, without a popover.',
88
+ },
89
+ },
90
+ },
91
+ render: () => <InteractiveStory />,
92
+ };
93
+
94
+ export const NoSelection: Story = {
95
+ parameters: {
96
+ docs: {
97
+ description: { story: 'When `value` is `null` no option is shown as selected.' },
98
+ },
99
+ },
100
+ render: () => <NoSelectionStory />,
101
+ };
@@ -0,0 +1,68 @@
1
+ import type { ComponentProps } from 'react';
2
+
3
+ import { LegendDot } from './LegendDot';
4
+ import { cn } from '../../utils/components';
5
+
6
+ export type LegendOption = {
7
+ value: string;
8
+ label: string;
9
+ color: string;
10
+ };
11
+
12
+ export type LegendPanelProps = ComponentProps<'div'> & {
13
+ items: LegendOption[];
14
+ title?: string;
15
+ } & (
16
+ | { value?: never; onSelectItem?: never }
17
+ | { value: string | null; onSelectItem: (value: string) => void }
18
+ );
19
+
20
+ export const LegendPanel = ({
21
+ items,
22
+ title,
23
+ value,
24
+ onSelectItem,
25
+ className,
26
+ ...props
27
+ }: LegendPanelProps) => (
28
+ <div data-slot="legend-panel" className={cn('cn-legend-panel', className)} {...props}>
29
+ {title !== undefined ? (
30
+ <p data-slot="legend-title" className="cn-legend-title">
31
+ {title}
32
+ </p>
33
+ ) : null}
34
+
35
+ {onSelectItem !== undefined ? (
36
+ <div
37
+ data-slot="legend-items"
38
+ role="radiogroup"
39
+ aria-label={title ?? 'Legend'}
40
+ className="cn-legend-items"
41
+ >
42
+ {items.map((item) => (
43
+ <button
44
+ key={item.value}
45
+ type="button"
46
+ role="radio"
47
+ aria-checked={item.value === value}
48
+ onClick={() => onSelectItem(item.value)}
49
+ data-slot="legend-option"
50
+ className="cn-legend-option"
51
+ >
52
+ <LegendDot color={item.color} />
53
+ {item.label}
54
+ </button>
55
+ ))}
56
+ </div>
57
+ ) : (
58
+ <ul data-slot="legend-items" className="cn-legend-items">
59
+ {items.map((item) => (
60
+ <li key={item.value} data-slot="legend-item" className="cn-legend-item">
61
+ <LegendDot color={item.color} />
62
+ {item.label}
63
+ </li>
64
+ ))}
65
+ </ul>
66
+ )}
67
+ </div>
68
+ );
@@ -0,0 +1,87 @@
1
+ import { useState } from 'react';
2
+
3
+ import type { Meta, StoryObj } from '@storybook/react-vite';
4
+
5
+ import { LegendPanel } from './LegendPanel';
6
+ import type { LegendOption } from './LegendPanel';
7
+ import { LegendSkeleton } from './LegendSkeleton';
8
+
9
+ const HABITAT_ITEMS: LegendOption[] = [
10
+ { value: 'bogs', label: 'Bogs', color: '#3b82f6' },
11
+ { value: 'dwarf-shrub', label: 'Dwarf shrub heath', color: '#14b8a6' },
12
+ { value: 'fens', label: 'Fens, marsh & swamp', color: '#ec4899' },
13
+ { value: 'littoral', label: 'Littoral sediments', color: '#f97316' },
14
+ ];
15
+
16
+ const meta: Meta<typeof LegendSkeleton> = {
17
+ title: 'Components/Legend/Skeleton',
18
+ component: LegendSkeleton,
19
+ tags: ['autodocs'],
20
+ parameters: {
21
+ docs: {
22
+ description: {
23
+ component:
24
+ 'Placeholder for a LegendPanel while its items are loading (e.g. fetched from a WMS GetLegendGraphic call). Reuses cn-legend-panel/title/items/item directly, so it lines up exactly with the real panel once data arrives.',
25
+ },
26
+ },
27
+ },
28
+ };
29
+
30
+ export default meta;
31
+
32
+ type Story = StoryObj<typeof LegendSkeleton>;
33
+
34
+ export const Default: Story = {
35
+ render: () => (
36
+ <div className="w-52">
37
+ <LegendSkeleton />
38
+ </div>
39
+ ),
40
+ };
41
+
42
+ export const SideBySide: Story = {
43
+ parameters: {
44
+ docs: {
45
+ description: { story: 'The skeleton and the real panel line up exactly once loaded.' },
46
+ },
47
+ },
48
+ render: () => (
49
+ <div className="flex gap-gds-4">
50
+ <div className="w-52">
51
+ <LegendSkeleton items={HABITAT_ITEMS.length} />
52
+ </div>
53
+
54
+ <div className="w-52">
55
+ <LegendPanel items={HABITAT_ITEMS} title="Legend" />
56
+ </div>
57
+ </div>
58
+ ),
59
+ };
60
+
61
+ const InteractiveSideBySideExample = () => {
62
+ const [active, setActive] = useState<string | null>(HABITAT_ITEMS[0]?.value ?? null);
63
+
64
+ return (
65
+ <div className="flex gap-gds-4">
66
+ <div className="w-52">
67
+ <LegendSkeleton items={HABITAT_ITEMS.length} interactive />
68
+ </div>
69
+
70
+ <div className="w-52">
71
+ <LegendPanel items={HABITAT_ITEMS} title="Legend" value={active} onSelectItem={setActive} />
72
+ </div>
73
+ </div>
74
+ );
75
+ };
76
+
77
+ export const InteractiveSideBySide: Story = {
78
+ parameters: {
79
+ docs: {
80
+ description: {
81
+ story:
82
+ 'Interactive LegendPanel rows (a radiogroup of padded, full-width buttons) are noticeably taller/wider than the plain display rows above, set interactive on the skeleton to match.',
83
+ },
84
+ },
85
+ },
86
+ render: () => <InteractiveSideBySideExample />,
87
+ };
@@ -0,0 +1,73 @@
1
+ import type { ComponentProps } from 'react';
2
+
3
+ import { cn } from '../../utils/components';
4
+ import { Skeleton } from '../Skeleton/Skeleton';
5
+
6
+ // Stable, fixed identifiers rather than the array index, even though these
7
+ // are decorative and never reorder, so an item's identity is never tied to
8
+ // its position at render time.
9
+ const ITEM_KEYS = [
10
+ 'item-1',
11
+ 'item-2',
12
+ 'item-3',
13
+ 'item-4',
14
+ 'item-5',
15
+ 'item-6',
16
+ 'item-7',
17
+ 'item-8',
18
+ ] as const;
19
+
20
+ export type LegendSkeletonProps = ComponentProps<'div'> & {
21
+ /** Explicitly disallow children, a skeleton is a placeholder shape, not a content wrapper. */
22
+ children?: never;
23
+ /** Number of item rows to show. Defaults to 4. */
24
+ items?: number;
25
+ /** Shows a title bar, matching LegendPanel's own optional title. Defaults to true. */
26
+ showTitle?: boolean;
27
+ /** Matches LegendPanel's interactive (radiogroup) mode: rows are padded, full-width
28
+ * cn-legend-option buttons rather than plain cn-legend-item rows, which is
29
+ * noticeably taller/wider, so the skeleton needs to reserve that same space. */
30
+ interactive?: boolean;
31
+ };
32
+
33
+ export const LegendSkeleton = ({
34
+ className,
35
+ items = 4,
36
+ showTitle = true,
37
+ interactive = false,
38
+ ...props
39
+ }: LegendSkeletonProps) => {
40
+ const itemKeys = ITEM_KEYS.slice(0, items);
41
+
42
+ return (
43
+ <div aria-hidden className={cn('cn-legend-panel', className)} {...props}>
44
+ {showTitle ? (
45
+ <div className="cn-legend-title">
46
+ <Skeleton className="cn-legend-skeleton-title" />
47
+ </div>
48
+ ) : null}
49
+
50
+ {interactive ? (
51
+ <div className="cn-legend-items">
52
+ {itemKeys.map((key) => (
53
+ <div key={key} className="cn-legend-option">
54
+ <Skeleton className="cn-legend-skeleton-dot" />
55
+
56
+ <Skeleton className="cn-legend-skeleton-label" />
57
+ </div>
58
+ ))}
59
+ </div>
60
+ ) : (
61
+ <ul className="cn-legend-items">
62
+ {itemKeys.map((key) => (
63
+ <li key={key} className="cn-legend-item">
64
+ <Skeleton className="cn-legend-skeleton-dot" />
65
+
66
+ <Skeleton className="cn-legend-skeleton-label" />
67
+ </li>
68
+ ))}
69
+ </ul>
70
+ )}
71
+ </div>
72
+ );
73
+ };
@@ -0,0 +1,8 @@
1
+ @layer components {
2
+ /* MARK: Legend dot
3
+ White ring separates the dot from the accent-coloured selected-option
4
+ background, ensuring visibility regardless of the dot colour. */
5
+ .cn-select-option-selected .cn-legend-dot {
6
+ outline: var(--focus-ring-width) solid var(--color-panel);
7
+ }
8
+ }
@@ -0,0 +1,80 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+
3
+ import { LegendSelect, type LegendOption } from './LegendSelect';
4
+ import { ErrorText } from '../ErrorText/ErrorText';
5
+ import { FormGroup } from '../Form/FormGroup';
6
+ import { Label } from '../Label/Label';
7
+
8
+ const meta: Meta<typeof LegendSelect> = {
9
+ title: 'Components/LegendSelect',
10
+ component: LegendSelect,
11
+ tags: ['autodocs'],
12
+ parameters: {
13
+ docs: {
14
+ description: {
15
+ component:
16
+ 'A Select variant where each option carries a `color` field rendered as a filled circle before the label. Useful for map legend filters, status indicators, and any dataset where colour encodes meaning. Extends `Select` directly, so all Select props (clearable, disabled, invalid, async, etc.) work without extra wiring. Pass `formatOptionLabel` if you need to override the rendering.',
17
+ },
18
+ },
19
+ },
20
+ };
21
+
22
+ export default meta;
23
+
24
+ type Story = StoryObj<typeof LegendSelect>;
25
+
26
+ const LAND_COVER_OPTIONS: LegendOption[] = [
27
+ { value: 'woodland', label: 'Woodland', color: '#2d6a4f' },
28
+ { value: 'grassland', label: 'Grassland', color: '#95d5b2' },
29
+ { value: 'arable', label: 'Arable land', color: '#e9c46a' },
30
+ { value: 'wetland', label: 'Wetland', color: '#4895ef' },
31
+ { value: 'urban', label: 'Urban / developed', color: '#adb5bd' },
32
+ ];
33
+
34
+ export const Default: Story = {
35
+ args: {
36
+ options: LAND_COVER_OPTIONS,
37
+ placeholder: 'Select land cover type...',
38
+ },
39
+ };
40
+
41
+ export const WithDefault: Story = {
42
+ parameters: {
43
+ docs: {
44
+ description: {
45
+ story:
46
+ 'The colour dot appears in both the dropdown and the selected-value slot in the control.',
47
+ },
48
+ },
49
+ },
50
+ args: {
51
+ options: LAND_COVER_OPTIONS,
52
+ defaultValue: LAND_COVER_OPTIONS[0],
53
+ },
54
+ };
55
+
56
+ export const Clearable: Story = {
57
+ args: {
58
+ options: LAND_COVER_OPTIONS,
59
+ defaultValue: LAND_COVER_OPTIONS[2],
60
+ isClearable: true,
61
+ },
62
+ };
63
+
64
+ export const Invalid: Story = {
65
+ render: () => (
66
+ <FormGroup invalid>
67
+ <Label htmlFor="legend-invalid">Land cover type</Label>
68
+
69
+ <ErrorText id="legend-invalid-error">Select a land cover type</ErrorText>
70
+
71
+ <LegendSelect
72
+ inputId="legend-invalid"
73
+ aria-describedby="legend-invalid-error"
74
+ options={LAND_COVER_OPTIONS}
75
+ placeholder="Select land cover type…"
76
+ invalid
77
+ />
78
+ </FormGroup>
79
+ ),
80
+ };
@@ -0,0 +1,26 @@
1
+ import type { GroupBase } from 'react-select';
2
+
3
+ import { LegendDot } from '../Legend/LegendDot';
4
+ import type { LegendOption } from '../Legend/LegendPanel';
5
+ import { Select, type SelectProps } from '../Select/Select';
6
+
7
+ export type { LegendOption };
8
+
9
+ export type LegendSelectProps<IsMulti extends boolean = false> = Omit<
10
+ SelectProps<LegendOption, IsMulti, GroupBase<LegendOption>>,
11
+ 'formatOptionLabel'
12
+ >;
13
+
14
+ export const LegendSelect = <IsMulti extends boolean = false>(
15
+ props: LegendSelectProps<IsMulti>,
16
+ ) => (
17
+ <Select<LegendOption, IsMulti>
18
+ {...props}
19
+ formatOptionLabel={(option) => (
20
+ <span className="flex items-center gap-gds-1">
21
+ <LegendDot color={option.color} />
22
+ {option.label}
23
+ </span>
24
+ )}
25
+ />
26
+ );
@@ -0,0 +1,98 @@
1
+ /* MARK: Appearances
2
+ Defined as utilities so ButtonLink can @apply them without duplication. */
3
+
4
+ @utility cn-link-appearance-primary {
5
+ @apply text-link;
6
+
7
+ &:visited {
8
+ @apply text-link-visited;
9
+ }
10
+ &:hover:not(:disabled) {
11
+ @apply text-link-hover;
12
+ }
13
+ &:active:not(:disabled) {
14
+ @apply text-link-active;
15
+ }
16
+ &:focus:not(:disabled) {
17
+ @apply text-on-focus;
18
+ }
19
+ }
20
+
21
+ @utility cn-link-appearance-error {
22
+ color: var(--color-error);
23
+
24
+ &:visited {
25
+ color: var(--color-error);
26
+ }
27
+ &:hover:not(:disabled) {
28
+ color: color-mix(in srgb, var(--color-error) 80%, black);
29
+ }
30
+ &:active:not(:disabled) {
31
+ color: color-mix(in srgb, var(--color-error) 80%, black);
32
+ }
33
+ &:focus:not(:disabled) {
34
+ @apply text-on-focus;
35
+ }
36
+ }
37
+
38
+ @utility cn-link-appearance-inverse {
39
+ @apply text-white;
40
+
41
+ &:visited {
42
+ @apply text-white;
43
+ }
44
+ &:hover:not(:disabled) {
45
+ @apply text-white;
46
+ }
47
+ &:focus:not(:disabled) {
48
+ @apply text-on-focus;
49
+ }
50
+ }
51
+
52
+ @utility cn-link-appearance-contrast {
53
+ @apply text-body;
54
+
55
+ &:visited {
56
+ @apply text-body;
57
+ }
58
+ &:hover:not(:disabled),
59
+ &:active:not(:disabled) {
60
+ @apply text-body;
61
+ }
62
+ &:focus:not(:disabled) {
63
+ @apply text-on-focus;
64
+ }
65
+ }
66
+
67
+ @layer components {
68
+ /*
69
+ MARK: Link
70
+ GDS link pattern. Underline always visible, thicker on hover,
71
+ yellow highlight box on focus. Box shadow creates lines above
72
+ and below text (not a ring). Visited uses distinct purple.
73
+ */
74
+ .cn-link {
75
+ @apply w-fit cn-link-decoration;
76
+
77
+ &:hover {
78
+ @apply cn-link-hover-decoration;
79
+ }
80
+
81
+ /* GDS focus: yellow box with black underline shadow */
82
+ &:focus {
83
+ @apply text-on-focus bg-focus no-underline outline-focus outline-transparent;
84
+ /* Top shadow extends focus box above text. Bottom shadow replaces underline */
85
+ box-shadow:
86
+ 0 -2px var(--color-focus),
87
+ 0 4px var(--color-on-focus);
88
+ }
89
+ }
90
+
91
+ /* MARK: Expand variant
92
+ Overrides the base w-fit: content (e.g. a title and a trailing chevron)
93
+ spreads across the full width of whatever the link sits in, rather than
94
+ the icon sitting flush against the text. */
95
+ .cn-link-variant-expand {
96
+ @apply flex w-full items-center justify-between gap-gds-2;
97
+ }
98
+ }
@@ -0,0 +1,70 @@
1
+ import { LuChevronRight } from 'react-icons/lu';
2
+
3
+ import type { Meta, StoryObj } from '@storybook/react-vite';
4
+
5
+ import { Link } from './Link';
6
+
7
+ const meta: Meta<typeof Link> = {
8
+ title: 'Components/Link',
9
+ component: Link,
10
+ tags: ['autodocs'],
11
+ parameters: {
12
+ docs: {
13
+ description: {
14
+ component: 'Use Link for accessible anchor navigation with multiple visual variants.',
15
+ },
16
+ },
17
+ },
18
+ argTypes: {
19
+ appearance: {
20
+ control: { type: 'radio' },
21
+ options: ['primary', 'inverse', 'contrast'],
22
+ },
23
+ variant: {
24
+ control: { type: 'radio' },
25
+ options: ['default', 'icon', 'expand'],
26
+ },
27
+ href: { control: 'text' },
28
+ children: { control: 'text' },
29
+ },
30
+ args: {
31
+ appearance: 'primary',
32
+ variant: 'default',
33
+ href: '#',
34
+ children: 'Story link',
35
+ },
36
+ };
37
+
38
+ export default meta;
39
+
40
+ type Story = StoryObj<typeof Link>;
41
+
42
+ export const Primary: Story = {
43
+ args: {
44
+ appearance: 'primary',
45
+ },
46
+ };
47
+
48
+ export const Inverse: Story = {
49
+ args: {
50
+ appearance: 'inverse',
51
+ },
52
+ };
53
+
54
+ export const Contrast: Story = {
55
+ args: {
56
+ appearance: 'contrast',
57
+ },
58
+ };
59
+
60
+ export const Expanded: Story = {
61
+ args: {
62
+ variant: 'expand',
63
+ },
64
+ render: (args) => (
65
+ <Link {...args}>
66
+ Explore
67
+ <LuChevronRight aria-hidden className="size-4" strokeWidth={2.5} />
68
+ </Link>
69
+ ),
70
+ };
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+
3
+ import type { ComponentProps } from 'react';
4
+
5
+ import { Slot } from 'radix-ui';
6
+
7
+ import { cn } from '../../utils/components';
8
+
9
+ const LINK_APPEARANCES = {
10
+ primary: 'cn-link-appearance-primary',
11
+ /**
12
+ * Typically reserved for use within an `Alert` component with the error appearance.
13
+ */
14
+ error: 'cn-link-appearance-error',
15
+ inverse: 'cn-link-appearance-inverse',
16
+ contrast: 'cn-link-appearance-contrast',
17
+ } as const;
18
+
19
+ export const LINK_VARIANTS = {
20
+ default: 'cn-link-variant-default',
21
+ icon: 'cn-link-variant-icon',
22
+ /** Full width, content spread apart, e.g. a title with a trailing chevron pushed to the end. */
23
+ expand: 'cn-link-variant-expand',
24
+ };
25
+
26
+ export type LinkAppearance = keyof typeof LINK_APPEARANCES;
27
+ export type LinkVariant = keyof typeof LINK_VARIANTS;
28
+
29
+ export type LinkProps = ComponentProps<'a'> & {
30
+ asChild?: boolean;
31
+ appearance?: LinkAppearance;
32
+ variant?: LinkVariant;
33
+ };
34
+
35
+ export const Link = ({
36
+ className,
37
+ asChild = false,
38
+ appearance = 'primary',
39
+ variant = 'default',
40
+ ...props
41
+ }: LinkProps) => {
42
+ const Comp = asChild ? Slot.Root : 'a';
43
+
44
+ return (
45
+ <Comp
46
+ {...props}
47
+ data-slot="link"
48
+ data-variant={variant}
49
+ className={cn('cn-link', LINK_APPEARANCES[appearance], LINK_VARIANTS[variant], className)}
50
+ />
51
+ );
52
+ };